.net 实用环境事务Transaction.Current随笔

环境事务使用静态属性Transaction.Current与线程关联,仅作用于线程上,它是可设置的。CommittableTransaction是唯一一个支持Commit的事务,new一个实例赋值给Transaction.Current后,当前线程上的任务就开启了事务(需要支持环境事务,SqlConnection支持环境事务),所有调用栈里方法都自动开启了事务。如果开启一个新任务,因为新任务几乎不会在当前线程执行,所以需要再给新任务一个事务,使用Transaction.Current.DependentClone(DependentCloneOption)方法创建一个依赖事务传递到新任务中,新任务就可使用这个依赖事务(子事务)与原事务关联上。

TransactionScope也是使用Transaction.Current的,而且还可以升级为分布式事务。特别要注意的是,transactionScope.Complete()只是标识事务已完成,并不会提交事务(这就是为什么叫Complete不叫Commit的原因),事务的提交是在transactionScope.Dispose()中。调用transactionScope.Dispose()时,如果事务被标识为已完成就会提交事务,否则回滚事务。一般使用是都是使用using语法,由编译器处理对Dispose的调用,但如果没有使用using语法,记得千万要在Complete之后调用Dispose,否则事务会一直挂起,直到垃圾回收器回收transactionScope对象调用终结器后才会提交事务。这过程中可能导致一系列问题,比如数据库的锁是占用着的;意外导致进程崩溃后数据丢失等。

使用[DatabaseGenerated(DatabaseGeneratedOption.None)]给int型非自增主键属性标识后,insert时会插入id,否则insert时不会插入id字段。

使用[ConcurrencyCheck()]给属性标识后,SaveChanges时会生成where子句,用以检测过程中实体当前属性的值有没有改变,如果发生改变,update时受影响的行数就会为0,从而抛出异常,保证了并发安全。

[ConcurrencyCheck()]只比较当前标识的字段,如果想要并发安全的还有其它的字段,最好是额外增加一外字段(字段在SqlServer中的数据类型为rowversion),对应的属性标识上[Timestamp],这样一来,通过比较[Timestamp]标识的属性就知道实体是不是发生变化了。

 

 

发表评论

电子邮件地址不会被公开。