Spring事务之只读

定义

从设置的时间点(时间点beta)开始到事务结束的过程中,该事务将看不见其他事务所提交的数据,即查询中不会出现别人在beta之后提交的数据。
如果一个事务只对数据库执行读操作,那么该数据库就可能利用那个事务的只读特性,采取某些优化措施。通过把一个事务声明为只读,可以给后端数据库一个机会来应用那些它认为合适的优化措施。由于只读的优化措施是在一个事务启动时由后端数据库实施的, 因此,只有对于那些具有可能启动一个新事务的传播行为(PROPAGATION_REQUIRES_NEW、PROPAGATION_REQUIRED、 ROPAGATION_NESTED)的方法来说,将事务声明为只读才有意义

网上的各种资料里众说纷纭:
“只读事务”并不是一个强制选项,它只是一个“暗示”,提示数据库驱动程序和数据库系统,这个事务并不包含更改数据的操作,那么JDBC驱动程序和数据库就有可能根据这种情况对该事务进行一些特定的优化,比方说不安排相应的数据库锁,以减轻事务对数据库的压力,毕竟事务也是要消耗数据库的资源的。(但是我尝试了,mysql数据库设置只读,做添加数据确实会报异常)

应用场合

对于一个函数,如果执行的只是单条查询语句,则没有必要启用事务支持,数据库默认支持SQL执行期间的读一致性;如果执行多条查询语句,例如统计查询,报表查询等,则多条查询SQL必须保证整体的读一致性;否则,若在前后两条查询SQL执行的间隙,数据被其他用户改变,则该次整体的统计查询将会出现读数据不一致的情况,此时,应该启用事务支持。注意,是一次执行多次查询来统计某些信息,这时为了保证数据整体的一致性,要用只读事务。

如何设置

对于只读查询,可以指定事务类型为readonly,即只读事务
由于只读事务不存在数据的修改,因此数据库将会为只读事务提供一些优化手段,例如Oracle对于只读事务,不启动回滚段,不记录回滚log。指定只读事务的办法如下:

  • 在JDBC中,令connection.setReadOnly(true);
  • 在Hibernate中,令 session.setFlushMode(FlushMode.NEVER);
    此时,Hibernate也会为只读事务提供Session方面的一些优化手段。
  • 在Spring的Hibernate封装中,在bean配置文件中,prop属性增加“readOnly”;
  • 使用注解 @Transactional(readOnly=true)
    在将事务设置成只读后,相当于将数据库设置成只读数据库,此时若要进行写的操作,会出现错误。

其他知识

1.readonly并不是所有数据库都支持的,不同的数据库下会有不同的结果。
2.设置了readonly后,connection都会被赋予readonly,效果取决于数据库的实现。
3.在ORM中,设置了readonly会赋予一些额外的优化,例如在Hibernate中,会被禁止flush等
4.在oracle下测试,发现不支持readOnly,也就是不论Connection里的readOnly属性是true还是false均不影响SQL的增删改查;
5.在mysql下测试,发现支持readOnly,设置为true时,只能查询,若增删改会异常:
6.readOnly对oracle不生效是因为:

1 con.setReadOnly(true);
2 con.setAutoCommit(false);

autoCommit与readOlny赋值的顺序对其有影响,readonly在后则生效,readolny在前是无效的可进行insert/update/delete操作。

你可能感兴趣的:(事务,java,mysql,数据库,spring)