上次在学习项目的过程中发现了一个这样的配置,方法事务上@Transactional(value = "transactionManager",readOnly = true)
增加了一个readOnly = true
的配置,很好奇这有什么用?原理是什么?下面我将一一说说它是什么以及在mysql、oracle中的区别。
事务分为只读事务和读写事务,我们第一反应会想到的含义是只读事务不允许你在一个事务中执行诸如update
、delete
、insert
的操作,你只能执行select
操作,但是,其实不是,只读事务并不是必须的,你同样可以在只读事务中执行修改操作,只不过显示声明事务为只读模式,会让相应的数据库对你的事务进行一些优化操作而已。
要演示只读事务对 mysql、oracle 的支持,首先要做的就是把例子给搭建起来,下面我将描述相关测试用例:
一、声明式配置 Spring 只读事务
Spring 声明式事务分为两种,一种是基于<tx>、<aop:config>
标签的事务声明,另外一种是基于@Transacional
的注解声明。我们采用第二种方式声明。
很显然,既然你要连接到 mysql、oracle 数据库,那么你就需要相应的数据库驱动程序;由于采用 Spring 进行事务管理,那么相应的Spring 包必不可少;当然你还需要一个数据源,告诉相应的驱动程序你的数据从哪里来;最后,我就不贴出代码了,代码太多,直接在github上看即可。
二、测试 Spring 对 mysql 的支持
mysql 提供对只读事务的支持,事务的默认隔离级别为“可重复读”。
编号 | 是否加事务 | 是否执行更新操作 | 事务是否只读 | 执行结果 |
---|---|---|---|---|
1 | 否 | 否 | 多次执行查询,结果随数据库改变而改变 | |
2 | 否 | 是 | 多次执行查询,结果随数据库改变而改变 | |
3 | 是 | 否 | 否 | 多次执行查询,结果不随数据库改变而改变,读视图一致 |
4 | 是 | 是 | 否 | 多次执行查询,结果不随数据库改变而改变,读视图一致 |
5 | 是 | 否 | 是 | 多次执行查询,结果不随数据库改变而改变,读视图一致 |
6 | 是 | 是 | 是 | 执行更会报错,提示 readOnly |
三、测试 Spring 对 oracle 的支持
oracle 提供对只读事务的支持,事务的默认隔离级别为“read committed”。
编号 | 是否加事务 | 是否执行更新操作 | 事务是否只读 | 执行结果 |
---|---|---|---|---|
1 | 否 | 否 | 多次执行查询,结果随数据库改变而改变 | |
2 | 否 | 是 | 多次执行查询,结果随数据库改变而改变 | |
3 | 是 | 否 | 否 | 多次执行查询,结果随数据库改变而改变 |
4 | 是 | 是 | 否 | 多次执行查询,结果随数据库改变而改变 |
5 | 是 | 否 | 是 | 多次执行查询,结果随数据库改变而改变 |
6 | 是 | 是 | 是 | 结果随数据库改变而改变 |
有此可见,Spring 设置的readOnly事务属性对oracle来说是无效的。
底层实现原理是基于JDBC的相关属性设置,如:
(1)在JDBC中,指定只读事务的办法为: connection.setReadOnly(true)
;
(2)在Hibernate中,指定只读事务的办法为: session.setFlushMode(FlushMode.NEVER)
;
四、Oracle 中只读事务
https://blog.csdn.net/msy_xingfu1314/article/details/50562991 当我们查看 oracle 驱动官方文档时会发现有,其实 Oracle 数据库本身也是支持只读事务的,也就是只读模式,但是文档很明确的说明了只读模式只能通过oracle数据库本身进行设置:
Read-only connections are supported by the Oracle server, but not by the Oracle JDBC drivers.
For transactions, the Oracle server supports only the TRANSACTION_READ_COMMITTED and TRANSACTION_SERIALIZABLE transaction isolation levels. The default is TRANSACTION_READ_COMMITTED. Use the following methods of the oracle.jdbc.OracleConnection interface to get and set the level:
-
getTransactionIsolation: Gets this connection's current transaction isolation level.
-
setTransactionIsolation: Changes the transaction isolation level, using one of the TRANSACTION_* values.
对于使用jdbc驱动来说,你只能设置TRANSACTION_READ_COMMITTED
和 TRANSACTION_SERIALIZABLE
两种隔离级别,如果你想要只读事务,只能通过执行SET TRANSACTION READ ONLY
完成。小编找了两篇更加全面的文章给大家参考
验证相关的数据库驱动可以在这里下载