Spring 在不应该提交的时候提交? (与 Oracle 自动提交有关)
Posted
技术标签:
【中文标题】Spring 在不应该提交的时候提交? (与 Oracle 自动提交有关)【英文标题】:Spring commits when it should not ? (related to Oracle autocommit) 【发布时间】:2010-06-24 14:14:01 【问题描述】:我有一个类似下面的界面
public interface FooDAO
public void callA(String x);
下面的实现故意使 readonly 为 true 且不受支持
public class FooDAOImpl implements FooDAO
//for testing
@Transactional(readOnly = true, propagation = Propagation.NOT_SUPPORTED)
public void callA(String x)
//sql update method
在我的 spring 上下文中,我声明了 Datasource 事务管理器和 tx:annotation-driven。我写了一个 Junit4 测试,看起来像
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(...)
@TransactionConfiguration(transactionManager="txManager", defaultRollback=true)
public class MyTest
@Resource
FooDAO fooDAO;
@Test
public void testRegisterWorker()
fooDAO.callA("")
我本来希望这条记录根本不会插入到数据库中。但是我看到该行实际上已插入数据库。我确实使用 Oracle 数据库,所以我认为自动提交默认设置为 true(我认为)。但是spring事务标签不应该覆盖它们吗?
谁能告诉我这里出了什么问题?
【问题讨论】:
【参考方案1】:自动提交可能默认开启。使用 DataSourceTransactionManager,只有在 事务实际启动时才会更改自动提交。 NOT_SUPPORTED 或 SUPPORTS 都不会启动事务,因此无论连接处于何种默认状态都将保持不变。
考虑在您的 Spring xml 文件中默认设置关闭自动提交。如果启用,Spring 将不得不在每次 tx 之前更改它并在之后恢复它,这在 Oracle 中可能会很昂贵(不确定)。这也可以防止您在事务之外意外提交。
有关详细信息,请参阅org.springframework.jdbc.datasource.DataSourceTransactionManager.doBegin()
,它管理 Connection 的自动提交和隔离级别。 doBegin() 仅在传播为 REQUIRED、REQUIRES_NEW 或 PROPAGATION_NESTED 时由 AbstractPlatformTransactionManager.getTransaction()
和 handleExistingTransaction()
调用。
您可能想看看org.springframework.test.context.junit4.AbstractTransactionalJUnit4SpringContextTests
。这是一个可用于测试类的 Spring 感知基类。它将在每个测试用例结束时回滚所有事务。这样就不需要为了测试而更改注释。您可以将 @Transactional 设置为它们应该在 prod 中的方式,并依靠回滚来确保在测试期间数据库中没有任何实际更改。
【讨论】:
【参考方案2】:自动提交是 JDBC 的“特性”,而不是 Oracle(在 Oracle 中,所有 DML 语句都是事务的一部分,因此只有在应用程序发出提交时才会提交)。
大多数驱动程序在创建与数据库的连接时将自动提交设为默认值。您可以通过调用setAutoCommit 方法来更改您的连接行为。
【讨论】:
【参考方案3】:为了使用@TransactionConfiguration
,您应该注释您的测试类或测试方法@Transactional
。此外,由于propagation = Propagation.NOT_SUPPORTED
,您的 DAO 方法可能在没有事务的情况下运行。
【讨论】:
以上是关于Spring 在不应该提交的时候提交? (与 Oracle 自动提交有关)的主要内容,如果未能解决你的问题,请参考以下文章
使用git提交代码--在不切换分支的情况下向不同的分支提交代码
如何在不提交表单的情况下使用struts2提交标签作为按钮?