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.
2if (definition != null && definition.isReadOnly()) {
3try {
4if (logger.isDebugEnabled()) {
5 logger.debug("Setting JDBC Connection [" + con + "] read-only");
6 }
7con.setReadOnly(true);
8 }
9catch (SQLException ex) {
10 Throwable exToCheck = ex;
11while (exToCheck != null) {
12if (Class().getSimpleName().contains("Timeout")) {
13// Assume it's a connection timeout that would otherwise get lost: e.g. from JDBC 4.0
14throw ex;
15 }
16 exToCheck = Cause();
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 }
21catch (RuntimeException ex) {
22 Throwable exToCheck = ex;
23while (exToCheck != null) {
24if (Class().getSimpleName().contains("Timeout")) {
25// Assume it's a connection timeout that would otherwise get lost: e.g. from Hibernate
26throw ex;
27 }
28 exToCheck = Cause();
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 sql.ateSQLException(SQLError.java:910)
3 sql.ute(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).
7if (AutoCommit()) {
8 txObject.setMustRestoreAutoCommit(true);
9if (logger.isDebugEnabled()) {
10 logger.debug("Switching JDBC Connection [" + con + "] to manual commit");itswarminspring怎么读
11 }
12 con.setAutoCommit(false);
13 }
因为DataSourceUtils.prepareConnectionForTransaction(con, definition)⾥会先设置readOnly属性,导致readOnly对oracle不⽣效;
-------------------------------------------------
他们的实践结果使我不得不相信他们说的真是这样,但以我现在的环境测试,不管什么顺序均⽆影响,readOnly就是对oracle不⽣效;看那些帖⼦时间已是⼏年前,版本差别太⼤,已⽆从考证……
====================疑问的分隔线==============================================
我也看到有⼈到oracle的官⽅⽂档链接⾥句⼦来说原因:
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”,搞不清楚哪个对哪个错,反正就是不⽀持。。。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论