本文摘自classinstance.cn。
我们先来看下通常的spring配置:
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="save*" propagation="REQUIRED" />
<tx:method name="update*" propagation="REQUIRED" />
<tx:method name="remove*" propagation="REQUIRED" />
<tx:method name="newTx*" propagation="REQUIRES_NEW" />
<tx:method name="get*" read-only="true"/>
<tx:method name="find*" read-only="true" />
<tx:method name="*" read-only="true"/>
</tx:attributes>
</tx:advice>
上面的配置中增删改中用propagation="REQUIRED"和"REQUIRES_NEW",都是需要开启写事务的,应该每个人都知道,但查询是否需要开启事务呢?
反正我在这之前,真的以为不用,也没必须开启。
但今天研究了下mycat的读写分离,发现写事务里的读都走写库,这种做法是为了保证查询数据的一致性,也就是保证数据库的可重复读事务隔离性。
我们再看看上面的读配置:
<tx:method name="get*" read-only="true"/>
其中tx里的默认传播性是propagation="REQUIRED" read-only默认为"false",默认可写的意思,也就是说上面的配置是有事务的,只是告诉数据库此事务没有需要更新的语句,事务只读,用spring这么久了,我才发现虽然配置了read-only="true",但上面的事务配置查询也是有事务的!
所以说查询也是需要开启事务的,以MySQL为例,这是为了这一组事务里的所有查询在Repeatable Read隔离级别下能做到一致性,也就是常说的可重复读。
举个例子,如果上面的读配置成无事务,如下:
<tx:method name="get*" propagation="NEVER"/>
那么就可能在一组查询中出现数据不致的问题,如:
public void getUserList(){
select count(*) from user_info
select * from user_info limit 0,10
}
如上我们service里有这么一个方法(事务切面定义的是service里的方法),用来分页查询的,当第一条查询出来count为6条数据时,正好有人删除了其中一条数据,因为getUserList()方法定义为无事务,下面这条语句查询用户数据查询出来就只有5条,造成了前后数据不一致,这违背了Repeatable Read隔离级别。
我们也不希望用户看到这种情况。
所以说为了保证可重复读,查询也是需要事务的,只不过为了优化数据查询,将read-only设为"true"。
另外,如果你的方法里或者说此次查询操作只有一个查询语句,那就没必要开启只读事务了,因为只有一个语句,没有一致性的问题,数据库默认可重复读的事务级别,也就是说spring里的事务配置,可以给这种方法配置成无事务,这样做会让你的查询性能提升很多,当然如果你的程序的查询密集型,并且不在意查询一致性的问题的话,一样可以设置成查询无事务,因为这么做相对于有只读事务的查询来说,性能可以提升3-4倍。
相关阅读 >>
spring如何获取配置在application.properties文件中属性的值?
spring、springmvc、springboot和springcloud的区别
更多相关阅读请进入《spring》频道 >>
深入理解Java虚拟机 JVM高级特性与实践 周志明 第3版
这是一部从工作原理和工程实践两个维度深入剖析JVM的著作,是计算机领域公认的经典。