【发布时间】:2014-07-31 13:57:57
【问题描述】:
我们正在尝试从 Spring 2.5.2 升级到 4.0.5.RELEASE,但发现 Spring 的事务管理不再起作用。
在我们的生产应用程序中,所有数据库操作都通过一个标有 @Transactional 注释的 Spring bean(使用默认设置)。几年来,这一直按预期工作,如果在事务边界内抛出 RuntimeException,则会发生回滚。但是,当我们升级到 Spring 4.0.5.RELEASE 时,它的作用就像 autocommit 设置为 true。
我们通过查看堆栈跟踪验证了问题代码仍在事务代理中运行。但是当我们在进入事务之后对表执行简单的一行更新时,更新是committed。这令人费解,因为我们所做的只是更改 Spring 版本。
在后来的 Spring 版本中,自动提交行为是否发生了变化?在 4.05 下我们需要做一些额外的配置吗?
这是我们事务管理器的配置(在 2.52 和 4.05 版本中相同):
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="efmsDataSource" />
</bean>
<bean id="efmsDataSource" class="com.uprr.eni.commons.dao.OracleDataSource">
<property name="driverClassName" value="oracle.jdbc.OracleDriver" />
<property name="url" value="jdbc:oracle:thin:@${db_instance}.oracle.uprr.com:1521:${db_instance}" />
<property name="username" value="${db_user}" />
<property name="password" value="${db_password}" />
<property name="maxActive" value="8" />
</bean>
这是在我们的代码中具有@Transactional 方法的bean:
<bean id="efmsExecutor" class="com.uprr.eni.commons.dao.exec.DataSourceExecutorBean">
<property name="dataSource" ref="efmsDataSource" />
</bean>
以下是我们如何创建应用程序上下文并获取事务 bean,然后将其保存为静态变量:
context = new ClassPathXmlApplicationContext(CONFIG_FILES);
efmsExecutorBean = (DataSourceExecutorBean)context.getBean(EFMS_EXECUTOR_BEAN);
我们将该 bean 保存在一个静态变量中,并在我们执行事务时引用它。我们应该做些不同的事情吗?
当我们要开始一个事务时,我们调用:
efmsExecutorBean.executeTransaction(executor);
这是我们在 DataSourceExecutorBean 中调用以启动事务的方法。它基本上只是将其内部数据源传递给执行器(实际执行数据库工作的代码)。
@Transactional public void executeTransaction(final DataSourceExecutor executor) {
executor.execute(source); // Perform the unit of work
final StringList errors = executor.getResult().getErrors(); // Did any errors occur?
if (!errors.isEmpty()) { // If so
for (final String error : errors) {
ApiLog.error(error); // Record them
}
throw new ExecutorError(ERROR, executor.getName()); // Abort
}
}
当我重新检查两个版本的日志时,我注意到 4.0.5(损坏的)版本有一些 2.5.2 版本没有的条目。这些条目在事务开始时出现:
2014-07-31 09:34:43,576 [btpool0-0] 调试 - 创建单例 bean 'efmsDataSource' 的共享实例 2014-07-31 09:34:43,576 [btpool0-0] 调试 - 创建 bean 'efmsDataSource' 的实例 2014-07-31 09:34:43,576 [btpool0-0] 调试 - 急切缓存 bean 'efmsDataSource' 以允许解决潜在的循环引用
也许这可以解释发生了什么(但不能解释为什么)。看起来单例数据源 bean 并不是真正的单例。谷歌显示了一些有类似问题的人,但没有说明如何解决它。这对任何人都有影响吗?
【问题讨论】:
-
看来事务有相同的行为,阅读documentation。可以把事务管理器的配置放上去吗?
-
没有额外的配置或已知的事务支持中断。您是否只更改了 Spring 版本或也进行了其他更改?可以出示一下代码吗?
-
新信息:通过 Spring 代码跟踪后,我们发现两个版本之间的行为存在差异。在损坏的(4.0.5)版本中,Spring 正在从应用程序上下文中创建一个新的事务管理器和新的数据源。因此,当它设置 autocommit 为 false 时,它设置的连接不同于我们的代码使用的连接。
标签: spring transactions spring-transactions autocommit