数据库并发及解决方案(二)

悲观锁及乐观锁的具体使用

(1)关于悲观锁的使用

        悲观锁只能写原生的SQL语句对数据库进行操作,EF是不支持悲观锁的,除非通过EF写原生的SQL语句执行数据库操作,并且一定要在同一个事务中。具体使用方式,在查询语句的表名后加with(xlock,ROWLOCK)。xlock表示“排他锁”,一旦加上排他锁,那么其他人在获取这个锁的话就要等待开锁,即事务结束。ROWLOCK为行锁,锁定的是查询出来的行。下面举一个在EF中使用悲观锁的例子:略

(2)关于乐观锁的使用

        在数据库中有一个特殊的字段类型rowversion,对列名无要求,这个字段的值也不需要开发人员去维护,每次修改这行数据的时候,对应的rowversion都会自动的变化(一般是增加)。有的数据库中也支持timestamp类型,我使用的是SQLServer数据库,在该数据库中支持timestamp类型,但是如果微软更推荐SQLServer中使用rowversion类型。乐观锁的使用其实很简单,首先给表增加一个rowversion或者timestamp类型的知道,字段名随意取名,在实体类中对应的字段类型要写出byte[],在FluentAPI中配置:Property(e=>e.RowVersion).IsRowVersion()。如果是通过注释配置,那么就在实体的该字段上方加[Timestamp]属性,意味指定该类型为行版本。应用场景如:抢单之前,查了一下获取到记录的rowversion值,比如查出来的是111,在执行更新的时候,若发现该记录在表中的rowversion的值已经不是111,那么就更新失败,即抢单失败,说明已经被别人抢到了。需要提醒的是,在EF中,在savechanges的时候也会校验rowversion的值,即在更新之前会查询当前数据库中的该条数据的rowversion的值和所要更新的值是否一致,若不一致,则更新失败。

总结

        EF会在SaveChanges()之后去检查RowVersion是否有变化,如果发现和之前查的时候不一致就会抛出DbUpdateConcurrencyException异常。悲观锁容易引起死锁,而且性能低,大部分系统的特点是“读多”、“写少”,因此除非特殊情况,否则推荐使用乐观锁。当然如果是使用也推荐更傻瓜化的捕捉bUpdateConcurrencyException异常。

 

 

 

你可能感兴趣的:(其他)