Spring 事务 readOnly 属性

Spring的事务经常会有这样的配置:

1 <tx:method name="search*" read-only="true" /> 

或者这样的注记:

1 @Transactional(readOnly = true)

正好我正在做的项目中这样配置了,而且偶然发现配置了不生效,本着“不弄明白对不起祖国对不起人民”的精神,参考了不少帖子和文档,总结了网上形形色色的答案,稍有收获,规整如下,不正确请指出。

1 readonly并不是所有数据库都支持的,不同的数据库下会有不同的结果。
2 设置了readonly后,connection都会被赋予readonly,效果取决于数据库的实现。
3 在ORM中,设置了readonly会赋予一些额外的优化,例如在Hibernate中,会被禁止flush等。

经实践,上面的观点基本正确。

环境:Spring-3.1.1、jdk6、oracle-11gR2、mysql-5.6.16、ojdbc6、mysql-connector-java-5.1.31、ibatis-2.3.4.726等,使用的Spring的DataSourceTransactionManager 事务管理器。

查看DataSourceTransactionManager 相关代码可知readOnly值最终是传给Connection的:

 1         // Set read-only flag.
 2         if (definition != null && definition.isReadOnly()) {
 3             try {
 4                 if (logger.isDebugEnabled()) {
 5                     logger.debug("Setting JDBC Connection [" + con + "] read-only");
 6                 }
 7                 con.setReadOnly(true);
 8             }
 9             catch (SQLException ex) {
10                 Throwable exToCheck = ex;
11                 while (exToCheck != null) {
12                     if (exToCheck.getClass().getSimpleName().contains("Timeout")) {
13                         // Assume it's a connection timeout that would otherwise get lost: e.g. from JDBC 4.0
14                         throw ex;
15                     }
16                     exToCheck = exToCheck.getCause();
17                 }
18                 // "read-only not supported" SQLException -> ignore, it's just a hint anyway
19                 logger.debug("Could not set JDBC Connection read-only", ex);
20             }
21             catch (RuntimeException ex) {
22                 Throwable exToCheck = ex;
23                 while (exToCheck != null) {
24                     if (exToCheck.getClass().getSimpleName().contains("Timeout")) {
25                         // Assume it's a connection timeout that would otherwise get lost: e.g. from Hibernate
26                         throw ex;
27                     }
28                     exToCheck = exToCheck.getCause();
29                 }
30                 // "read-only not supported" UnsupportedOperationException -> ignore, it's just a hint anyway
31                 logger.debug("Could not set JDBC Connection read-only", ex);
32             }
33         }

1、在oracle下测试,发现不支持readOnly,也就是不论Connection里的readOnly属性是true还是false均不影响SQL的增删改查;

2、在mysql下测试,发现支持readOnly,设置为true时,只能查询,若增删改会异常:

1 Caused by: java.sql.SQLException: Connection is read-only. Queries leading to data modification are not allowed
2     at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:910)
3     at com.mysql.jdbc.PreparedStatement.execute(PreparedStatement.java:792)

3、为了排除各种框架封装的影响,写JDBC原生代码也是相同的结论。

“只读事务”并不是一个强制选项,它只是一个“暗示”,提示数据库驱动程序和数据库系统,这个事务并不包含更改数据的操作,那么JDBC驱动程序和数据库就有可能根据这种情况对该事务进行一些特定的优化,比方说不安排相应的数据库锁,以减轻事务对数据库的压力,毕竟事务也是要消耗数据库的资源的。
但是你非要在“只读事务”里面修改数据,也并非不可以,只不过对于数据一致性的保护不像“读写事务”那样保险而已。
因此,“只读事务”仅仅是一个性能优化的推荐配置而已,并非强制你要这样做不可。

  • 10
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值