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

---------------------------------------------

早期的提问会有这样的结论:

readOnly对oracle不生效是因为:

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

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

同样,DataSourceTransactionManager 里也是因为这个原因:

 1             Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
2 txObject.setPreviousIsolationLevel(previousIsolationLevel);
3
4 // Switch to manual commit if necessary. This is very expensive in some JDBC drivers,
5 // so we don't want to do it unnecessarily (for example if we've explicitly
6 // configured the connection pool to set it already).
7 if (con.getAutoCommit()) {
8 txObject.setMustRestoreAutoCommit(true);
9 if (logger.isDebugEnabled()) {
10 logger.debug("Switching JDBC Connection [" + con + "] to manual commit");
11 }
12 con.setAutoCommit(false);
13 }

因为DataSourceUtils.prepareConnectionForTransaction(con, definition)里会先设置readOnly属性,导致readOnly对oracle不生效;

-------------------------------------------------

他们的实践结果使我不得不相信他们说的真是这样,但以我现在的环境测试,不管什么顺序均无影响,readOnly就是对oracle不生效;看那些帖子时间已是几年前,版本差别太大,已无从考证……

====================疑问的分隔线==============================================

我也看到有人找到oracle的官方文档链接里句子来说原因:

http://docs.oracle.com/cd/B14117_01/java.101/b10979/tips.htm#i1007231

http://docs.oracle.com/cd/B19306_01/java.102/b14355/apxtips.htm#i1007231

http://docs.oracle.com/cd/B28359_01/java.111/b31224/apxtips.htm#i1007231

http://docs.oracle.com/cd/E11882_01/java.112/e16548/apxtips.htm#i1007231

10.1、10.2和11.1的文档里写着:

1 Read-only connections are supported by the Oracle server, but not by the Oracle JDBC drivers.

11.2的文档里写着:

1 Read-only connections are supported by Oracle JDBC drivers, but not by the Oracle server.

再结合oracle可以设置 “set transaction read only”,搞不清楚哪个对哪个错,反正就是不支持。。。

Spring 事务 readOnly 到底是怎么回事?的更多相关文章

  1. Spring(二十二):Spring 事务

    事务简介: 事务管理是企业级应用程序开发中必不可少的技术,用来确保数据的完整性和一致性. 事务就是一系列的动作,它们被当做一个单独的工作单元.这些动作要么全部完成,要么全部不起作用. 事务的是四个关键 ...

  2. 透彻理解Spring事务设计思想之手写实现

    前言 事务,是描述一组操作的抽象,比如对数据库的一组操作,要么全部成功,要么全部失败.事务具有4个特性:Atomicity(原子性),Consistency(一致性),Isolation(隔离性),D ...

  3. 透彻理解Spring事务设计思想之手写实现(山东数漫江湖)

    前言 事务,是描述一组操作的抽象,比如对数据库的一组操作,要么全部成功,要么全部失败.事务具有4个特性:Atomicity(原子性),Consistency(一致性),Isolation(隔离性),D ...

  4. Spring事务管理 —— readOnly只读事务

    事务是什么?事务是一个原子操作,由一系列动作组成.事务的原子性确保动作要么全部完成,要么完全不起作用. 下面来看一个项目中遇到的问题: 有这么一个需求,我们要查询一些数据,但是在查询这个数据之前我们要 ...

  5. Spring事务专题(五)聊聊Spring事务到底是如何实现的

    前言 本专题大纲: 本文为本专题倒数第二篇文章. 在上篇文章中我们一起学习了Spring中的事务抽象机制以及动手模拟了一下Spring中的事务管理机制,那么本文我们就通过源码来分析一下Spring中的 ...

  6. Spring 设置readonly 事务只读模式

    详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt394 在学习spring事务的时候,发现设置readOnly后不启作用. 查 ...

  7. spring事务到底用于service层还是dao层

    Spring事务为业务逻辑进行事务管理,保证业务逻辑上数据的原子性. 事务得根据项目性质来细分:事务可以设置到三个层面(dao层.service层和web层). 第一:web层事务,这一般是针对那些安 ...

  8. Spring Boot Starters到底怎么回事?

    前言 上周看了一篇.你一直在用的Spring Boot Starters究竟是怎么回事(https://www.cnblogs.com/fengzheng/p/10947585.html)   感觉终 ...

  9. spring事务管理器设计思想(二)

    上文见<spring事务管理器设计思想(一)> 对于第二个问题,涉及到事务的传播级别,定义如下: PROPAGATION_REQUIRED-- 如果当前没有事务,就新建一个事务.这是最常见 ...

随机推荐

  1. 自己总结的C#编码规范--1.命名约定篇

    命名约定 我们在命名标识符时(包括参数,常量,变量),应使用单词的首字母大小写来区分一个标识符中的多个单词,如UserName. PascalCasing PascalCasing包含一到多个单词,每 ...

  2. 按字典序依次打印只由1~n组成的n位数

    //我的dfs入门.将1~n一次填入数组然后打印. #include<stdio.h> #include<string.h> ]; ]; void dfs(int,int); ...

  3. AE视频制作 参考 资源 科幻科技风格 开场 公司企业宣传

    == 人类已经堕落,机器军团大举入侵,开始抹除人类,净化地球!-原创-高清正版视频在线观看–爱奇艺 这个视频片头不错.展示效果和音乐. == 外星人入侵地球,只为收集人类大脑!速看科幻电影<天际 ...

  4. RFID的winform程序心得1

    /// 根据日期获取当周星期一 /// </summary> /// <param name="dt"></param> /// <ret ...

  5. malloc函数详解 C语言逻辑运算符

    今天写线性表的实现,又遇到了很多的难题,C语言的指针真的没学扎实.很多基础都忘了. 一是 :malloc 函数的使用. 二是:C语言逻辑运算符. 一.原型:extern void *malloc(un ...

  6. tomcat修改端口号

    以前只知道当tomcat端口号冲突了如何修改tomcat默认的8080端口号 今天遇到个情况,装了个BO,自带个tomcat,这时就需要修改三个地方 修改Tomcat的端口号: 在默认情况下,tomc ...

  7. ajax中的async属性值之同步和异步及同步和异步区别

    jquery中ajax方法有个属性async用于控制同步和异步,默认是true,即ajax请求默认是异步请求,有时项目中会用到AJAX同步.这个同步的意思是当JS代码加载到当前AJAX的时候会把页面里 ...

  8. java.lang.NoSuchMethodException: .<init>()

    严重: Servlet.service() for servlet [springmvc] in context with path [/SpringMvc-1] threw exception [R ...

  9. HTML 标题标签

    HTML:超文本标记语言基本结构 <!DOCTYPE html> <!--文档的声明 一个HTML文件就是一个文档 --> <html lang="en&quo ...

  10. jdk各种包安装方式

    大家都知道,现在JAVA的发展可谓是如日中天,它覆盖面非常广泛,小到个人PC,大到商业应用都能见到它的身影.以前它是由SUN公司来维护的,现在已经归属到甲骨文旗下了. 今天我们来学习一下Java JD ...