我们先来看下通常的spring配置:
上面的配置中增删改中用propagation="REQUIRED"和"REQUIRES_NEW",都是需要开启写事务的,应该每个人都知道,但查询是否需要开启事务呢?反正我在这之前,真的以为不用,也没必须开启。但今天研究了下mycat的读写分离,发现写事务里的读都走写库,这种做法是为了保证查询数据的一致性,也就是保证数据库的可重复读事务隔离性。
我们再看看上面的读配置:
其中tx里的默认传播性是propagation="REQUIRED" read-only默认为"false",默认可写的意思,也就是说上面的配置是有事务的,只是告诉数据库此事务没有需要更新的语句,事务只读,用spring这么久了,我才发现虽然配置了read-only="true",但上面的事务配置查询也是有事务的!
所以说查询也是需要开启事务的,以MySQL为例,这是为了这一组事务里的所有查询在Repeatable Read隔离级别下能做到一致性,也就是常说的可重复读。
举个例子,如果上面的读配置成无事务,如下:
那么就可能在一组查询中出现数据不致的问题,如:
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倍。