参考资料:
http://openwares.net/java/spring_mybatis_transaction.html
spring,mybatis事务管理配置与@Transactional注解使用http://www.cnblogs.com/mingxuan/archive/2011/10/11/2207560.html
锁行还是锁表的实践验证http://blog.csdn.net/hushanfeng110/article/details/50174787
使用mybatis 实现乐观锁和悲观锁http://blog.csdn.net/mysteryhaohao/article/details/51669741
详细介绍了mysql的各种引擎下,锁和事务的差异http://www.voidcn.com/article/p-hnrytsbt-ms.html
spring 中常用的两种事务配置方式以及事务的传播性、隔离级别
上周遇到一个需求,1订单提交的时候,保证客户端数据和服务端数据的一致性,另外,2要保证提交操作的处理过程中,服务端的数据不会变化
最初的解决方案1,使用暴力的锁表操作:
可行性不高,整个订单提交的过程中,需要调用sf的下单api,整个处理过程大概有2秒左右,对于服务端,把一个表锁2秒,不可接受,大并发下会造成严重的阻塞。
解决方案2,实现乐观锁,其实乐观锁就是一种人为实现的锁,并没有锁表,主要思路是把对应订单信息加一个数据标识,将客户端提交的数据标识和服务端的标识进行比对,如果不合理不一致,则拒绝客户端的请求,要求客户端刷新数据后重新提交。
这种方案可以解决客户端与服务端数据不一致的问题,并且没有对数据库进行加锁,性能上几乎没有影响,比较适用。
但是仍然没有解决需求2,可能出现,数据标识核对一致,程序开始处理提交请求,但是还没有保证订单处理的过程中,服务端的数据不会变化。
解决方案3,使用行级锁,把订单所对应的几行锁定,不让客户端进行修改。
行级锁里又分为共享锁和排他锁,这里使用排他锁。(具体可查看参考资料)
解决方案4,使用spring的事物管理,将对应业务切点的事物隔离级别提高到最高TransactionDefinition.ISOLATION_SERIALIZABLE,当然性能也是最差的;
对应的事物传播特性也要设置成TransactionDefinition.PROPAGATION_REQUIRES_NEW。
此方案能够在事物级别对操作进行隔离,防止事物之间的融合。
其中TransactionDefinition接口定义以下特性:
事务隔离级别
隔离级别是指若干个并发的事务之间的隔离程度。TransactionDefinition 接口中定义了五个表示隔离级别的常量:
- TransactionDefinition.ISOLATION_DEFAULT:这是默认值,表示使用底层数据库的默认隔离级别。对大部分数据库而言,通常这值就是TransactionDefinition.ISOLATION_READ_COMMITTED。
- TransactionDefinition.ISOLATION_READ_UNCOMMITTED:该隔离级别表示一个事务可以读取另一个事务修改但还没有提交的数据。该级别不能防止脏读,不可重复读和幻读,因此很少使用该隔离级别。比如PostgreSQL实际上并没有此级别。
- TransactionDefinition.ISOLATION_READ_COMMITTED:该隔离级别表示一个事务只能读取另一个事务已经提交的数据。该级别可以防止脏读,这也是大多数情况下的推荐值。
- TransactionDefinition.ISOLATION_REPEATABLE_READ:该隔离级别表示一个事务在整个过程中可以多次重复执行某个查询,并且每次返回的记录都相同。该级别可以防止脏读和不可重复读。
- TransactionDefinition.ISOLATION_SERIALIZABLE:所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。
事务传播行为
所谓事务的传播行为是指,如果在开始当前事务之前,一个事务上下文已经存在,此时有若干选项可以指定一个事务性方法的执行行为。在TransactionDefinition定义中包括了如下几个表示传播行为的常量:
- TransactionDefinition.PROPAGATION_REQUIRED:如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。这是默认值。
- TransactionDefinition.PROPAGATION_REQUIRES_NEW:创建一个新的事务,如果当前存在事务,则把当前事务挂起。
- TransactionDefinition.PROPAGATION_SUPPORTS:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
- TransactionDefinition.PROPAGATION_NOT_SUPPORTED:以非事务方式运行,如果当前存在事务,则把当前事务挂起。
- TransactionDefinition.PROPAGATION_NEVER:以非事务方式运行,如果当前存在事务,则抛出异常。
- TransactionDefinition.PROPAGATION_MANDATORY:如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。
- TransactionDefinition.PROPAGATION_NESTED:如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于TransactionDefinition.PROPAGATION_REQUIRED。
事务超时
所谓事务超时,就是指一个事务所允许执行的最长时间,如果超过该时间限制但事务还没有完成,则自动回滚事务。在 TransactionDefinition 中以 int 的值来表示超时时间,其单位是秒。
默认设置为底层事务系统的超时值,如果底层数据库事务系统没有设置超时值,那么就是none,没有超时限制。
事务只读属性
只读事务用于客户代码只读但不修改数据的情形,只读事务用于特定情景下的优化,比如使用Hibernate的时候。