由于需要大批量的迁移数据(上千万),弄了个迁移工具。
千万的数据,不适宜一次性的提交或回滚事务,中间需要分批提交,在设置事务的过程中,居然发现spring的声明式事务中设置的方法read-only级别无效。
见下面代码:
<tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="add*" propagation="REQUIRED"/> <tx:method name="save*" propagation="REQUIRED"/> <tx:method name="insert*" propagation="REQUIRED"/> <tx:method name="del*" propagation="REQUIRED"/> <tx:method name="update*" propagation="REQUIRED"/> <tx:method name="*" read-only="true"/> </tx:attributes> </tx:advice>
上面的设置,任何的方法都可以更新或者删除数据,read-only形同虚设。
但是当抛出异常时查看数据,发现又都是回滚的,说明事务还是起作用的,
同样的代码,弄在我自己的小项目中,read-only又起作用了,这就奇怪了。
查询资料后发现,原来是数据库的原因,我自己的小项目使用的是mysql,而当前项目中是oracle,oracle的官方文档上有这么一句:
Read-only connections are supported by the Oracle server, but not by the Oracle JDBC drivers.
原来是Oracle Read Only 隔离级别只是支持Oracle Server,并不支持jdbc驱动,所以spring中虽然设置了read-only,仍旧不起作用!
顺便贴上spring的事务级别:
PROPAGATION_REQUIRED -- 支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。 PROPAGATION_SUPPORTS -- 支持当前事务,如果当前没有事务,就以非事务方式执行。 PROPAGATION_MANDATORY -- 支持当前事务,如果当前没有事务,就抛出异常。 PROPAGATION_REQUIRES_NEW -- 新建事务,如果当前存在事务,把当前事务挂起。 PROPAGATION_NOT_SUPPORTED -- 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。 PROPAGATION_NEVER -- 以非事务方式执行,如果当前存在事务,则抛出异常。 PROPAGATION_NESTED -- 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则进行与PROPAGATION_REQUIRED类似的操作。 前六个策略类似于EJB CMT,第七个(PROPAGATION_NESTED)是Spring所提供的一个特殊变量。 它要求事务管理器或者使用JDBC 3.0 Savepoint API提供嵌套事务行为(如Spring的DataSourceTransactionManager)