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

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

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

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 到底是怎么回事?,布布扣,bubuko.com

时间: 2024-10-08 17:22:51

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

Spring事务不起作用 问题汇总

Spring事务不起作用 问题汇总 博客分类: spring杂谈 java开发常见问题分析 总有很多朋友询问spring事务不起作用怎么回事,这里我汇总下,欢迎补充: 1.首先使用如下代码 确认你的bean 是代理对象吗? AopUtils.isAopProxy() AopUtils.isCglibProxy() //cglib AopUtils.isJdkDynamicProxy() //jdk动态代理 如果不是 那么就是切入点配置出错了 或者如果你使用了springmvc,可能是contex

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

前言 事务,是描述一组操作的抽象,比如对数据库的一组操作,要么全部成功,要么全部失败.事务具有4个特性:Atomicity(原子性),Consistency(一致性),Isolation(隔离性),Durability(持久性).在实际开发中,我们对事务应用最多就是在数据库操作这一环,特别是Spring对数据库事务进行了封装管理.Spring对事务的支持,确实很强大,但是从本质上来讲:事务是否生效取决数据库底层是否支持(比如MySQL的MyISAM引擎就不支持事务,Spring能奈何!),同时一

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

Spring事务为业务逻辑进行事务管理,保证业务逻辑上数据的原子性. 事务得根据项目性质来细分:事务可以设置到三个层面(dao层.service层和web层). 第一:web层事务,这一般是针对那些安全性要求较高的系统来说的.例如电子商务网站.粒度小,一般系统用不着这么细. 第二:service层事务,这是一常见的事务划分, 将事务设置在业务逻辑上,只要业务逻辑出错或异常就事务回滚.粒度较小,一般推荐这种方式. 第三:数据持久层数据务,也就是常说的数据库事务.这种事务在安全性方面要求低.就是给一

spring事务管理及相关知识

最近在项目中遇到了spring事务的注解及相关知识,突然间感觉自己对于这部分知识只停留在表面的理解层次上,于是乎花些时间上网搜索了一些文章,以及对于源码的解读,整理如下: 一.既然谈到事务,那就先搞清到底什么是事务,或者说,Spring事务管理中的事务到底是指什么? 1.事务(Transaction),通常是指数据库的事务,在计算机术语中是指访问并可能更新数据库中各种数据项的一个程序执行单元(unit),例如insert .update.delete等,事务是恢复和并发控制的基本单位. 2.事务

框架 day37 Spring事务管理,整合web,SSH整合,SSH整合注解

1     事务管理 1.1   回顾事务     事务:一组业务操作,要么全部成功,要么全部不成功.     事务特性:ACID 原子性:整体 一致性:数据(完整) 隔离性:并发(多个事务) 持久性:结果     隔离问题:脏读.不可重复读.幻读(虚读)     隔离级别:4个 readuncommitted 读未提交,存在3个问题. readcommitted 读已提交,解决:脏读:存在2个. repeatableread 可重复读,解决:脏读.不可重复读:存在1个 serializ

Spring事务管理(详解+实例)

写这篇博客之前我首先读了<Spring in action>,之后在网上看了一些关于Spring事务管理的文章,感觉都没有讲全,这里就将书上的和网上关于事务的知识总结一下,参考的文章如下: Spring事务机制详解 Spring事务配置的五种方式 Spring中的事务管理实例详解 1 初步理解 理解事务之前,先讲一个你日常生活中最常干的事:取钱. 比如你去ATM机取1000块钱,大体有两个步骤:首先输入密码金额,银行卡扣掉1000元钱:然后ATM出1000元钱.这两个步骤必须是要么都执行要么都

Spring事务管理

写这篇博客之前我首先读了<spring in action>,之后在网上看了一些关于Spring事务管理的文章,感觉都没有讲全,这里就将书上的和网上关于事务的知识总结一下,参考的文章如下: Spring事务机制详解 Spring事务配置的五种方式 Spring中的事务管理实例详解 1 初步理解 理解事务之前,先讲一个你日常生活中最常干的事:取钱. 比如你去ATM机取1000块钱,大体有两个步骤:首先输入密码金额,银行卡扣掉1000元钱:然后ATM出1000元钱.这两个步骤必须是要么都执行要么都

Spring 事务管理

<?xml version="1.0" encoding="UTF-8"?> <beans  xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema

功能第四篇——事务之Spring事务()

综述 事务的实现方式有三种,JTA,Spring事务,Web Container方式.本篇讲述Spring事务. Spring事务分为两个部分核心对象,Spring事务的实现方式. Spring事务实现的方式有三种.声明式,注解式,代码的方式.声明方式在实际项目中运用比较广泛,注解方式需要在每个方法上添加@Transactional注解,代码冗余度比较高.代码方式只是为了更好的理解Spring事务的机制,在实际项目中并不适用. 核心对象 PlatformTransactionManager 事务