最近在HP实习里完成的一个项目让我真正地了解了ADO.NET的用法。其中我体会到了ADO。NET的数据库离线更新模式给我们带来的便捷,但同时又体验到了“天下没有免费的午餐”的真谛——一个“数据并发异常”就困扰了一个下午。这一个下午,也应该足以完成省下的update,insert,delete语句了,不过能够借此机会深入了解数据库及ADO.NET一些平时看书是不可能了解的特性,已经是well pay off了。
首先这个项目比较简单,只涉及一个数据表的更新,所以我一开始就选择了commandbuilder生成update,insert,delete语句,然后由dataset的update帮我把所有更改提交到数据库中,包括update,insert,delete的数据行。
这种离线更新的模式已受到了广大程序员的称赞。先update内存中的数据,再把update后的东西一次性交到数据库那边永久更新,而且有commandbuilder的自动语句生成,这省下了我大量的代码。
就在我将要以迅雷不及掩耳之势完成项目时,一个exception弹出了:DBConcurrencyException . 网上google了一下,并且查了一下msdn,发现原来是数据不同步。简单说起来就是我从DB下载到内存的数据在DB那里已经被更改了,使得和我数据库的那个版本不一致。当时我就觉得不对头,现在只有我自己在操作数据库阿,怎么会在DB端发生了我自己不知道的更改呢?可当时我没想这么多,按照msdn上的方法,三下五除二加上了异常处理,在试了几下没问题之后就宣布完工了。
但在真正投入使用时那个异常再次出现。看来真正深入了解问题的根源了。思考的过程省过不说了。发现问题的地方就是在我处理该异常时,想要通过DBConcurrencyException .Row打印引发问题的datarow,但发现本row找不到ID,也就是这个row的一个key。这下我终于了解问题的根源了。
通常我们设计数据库时,都喜欢用ID作为key,并且把这个Key设为自动增1。然后我们在新增row时就不必人手输入,由数据库帮助我们设好这个值。而用ADO。NET的离线Dataset模式时,我们再新增row时当然也就不会自己设这个值进去。因此在我们内存中的Dataset里这个值一直是空缺的,用Update提交数据库更新时,数据库自动帮我们把这个值设上去了,但内存中的Dataset却没有。所以当下一次更新时,由于Dataset的Key缺失,与DB中不一致,因为ADO。NET是通过Key来找DataRow的,所以DB找不到该row在Dataset中对应的行,所以就报了一个DBConcurrencyException。解决的方法很简单,就是在每次Update之后重新用Adapter Fill一下Dataset就可以了。
这里想起来,一开始受了DBConcurrencyException的本来意思的误导,以为问题真的在于数据库的多用户之前的数据同步,总以为是其它什么地方更改了数据库使到DB和自己内存中的版本不同步,谁知道其实是事情的另一个方面——是自己内存中的版本不对使得和DB不同步的。
这隐隐中让我想到更深一层的哲学概念:矛盾都是有两个方面的,当什么地方出现问题后,多想想自己的主观因素,不要老是埋怨和怀疑其它的客观,多从自己身上找原因。When something is wrong, there must be some problems caused by yourself.
只有注册用户登录后才能发表评论。

posts - 0, comments - 0, trackbacks - 0, articles - 1

Copyright © Superbull