java - 不同 OracleDB 连接之间的共享事务

标签 java oracle junit transactions sql2o

经过几天的调查,我决定提交这个问题,因为发生的事情显然没有意义。

案例

我的计算机配置了本地 Oracle Express 数据库。 我有一个 JAVA 项目,其中包含几个扩展父类的 JUnit 测试(我知道这不是“最佳实践”),它在 @Before 方法中打开一个 OJDBC 连接(使用 10 个连接的静态 Hikari 连接池)并滚动在@After 中支持它。

public class BaseLocalRollbackableConnectorTest {
private static Logger logger = LoggerFactory.getLogger(BaseLocalRollbackableConnectorTest.class);
protected Connection connection;

@Before
public void setup() throws SQLException{
    logger.debug("Getting connection and setting autocommit to FALSE");
    connection = StaticConnectionPool.getPooledConnection();
}

@After
public void teardown() throws SQLException{ 
    logger.debug("Rollback connection");
    connection.rollback();
    logger.debug("Close connection");
    connection.close();
}

StacicConnectionPool

public class StaticConnectionPool {

private static HikariDataSource ds;

private static final Logger log = LoggerFactory.getLogger(StaticConnectionPool.class);

public static Connection getPooledConnection() throws SQLException {

    if (ds == null) {
        log.debug("Initializing ConnectionPool");
        HikariConfig config = new HikariConfig();
        config.setMaximumPoolSize(10);
        config.setDataSourceClassName("oracle.jdbc.pool.OracleDataSource");
        config.addDataSourceProperty("url", "jdbc:oracle:thin:@localhost:1521:XE");
        config.addDataSourceProperty("user", "MyUser");
        config.addDataSourceProperty("password", "MyPsw");
        config.setAutoCommit(false);
        ds = new HikariDataSource(config);

    }
    return ds.getConnection();

}

}

这个项目有数百个测试(不是并行的),使用这个连接(在本地主机上)使用 Sql2o 执行查询(插入/更新和选择),但连接的事务和关闭仅在外部管理(通过上面的测试)。 数据库完全为空,无法进行 ACID 测试。

所以预期的结果是向数据库中插入一些东西,做出断言然后回滚。这样第二个测试就不会发现前一个测试添加的任何数据,以保持隔离级别。

问题 一起(按顺序)运行所有测试,90% 的时间它们都能正常工作。 10% 的一两个测试随机失败,因为数据库中有脏数据(例如重复唯一)由先前的测试。查看日志,先前测试的回滚已正确完成。事实上,如果我检查数据库,它是空的) 如果我在性能更高但使用相同 JDK、相同 Oracle DB XE 的服务器上执行此测试,则此故障率会增加到 50%。

这很奇怪,我不知道,因为测试之间的连接不同,并且每次都会调用回滚。 JDBC 隔离级别是 READ COMMITTED,所以即使我们使用相同的连接,即使使用相同的连接也不应该产生任何问题。 所以我的问题是: 为什么会发生?你有什么主意吗?如我所知,JDBC 回滚是同步的,还是在某些情况下即使未完全完成也可以继续执行?

这些是我的主要数据库参数: 处理 100 session 172 交易 189

最佳答案

我在 2-3 年前遇到过同样的问题(我花了很多时间来弄清楚这一点)。问题是@Before 和@After 并不是总是 真正连续的。 [您可以通过在调试中启动进程并在带注释的方法中放置一些断点来尝试此操作。

编辑:我不够清楚 Tonio指出。 @Before 和@After 的顺序保证了测试之前和之后的运行。就我而言,问题是有时 @Before 和 @After 会搞砸。

预期:

@Before -> test1() -> @After -> @Before -> @test2() -> @After

但有时我会遇到以下顺序:

@Before -> test1() -> @Before -> @After -> @test2() -> @After

我不确定这是否是错误。当时我深入研究它,它看起来像是某种(处理器?)与调度相关的魔法。 该问题的解决方案是在我们的案例中在单个线程上运行测试并手动调用 init 和 cleanup 进程......像这样:

public class BaseLocalRollbackableConnectorTest {
    private static Logger logger = LoggerFactory.getLogger(BaseLocalRollbackableConnectorTest.class);
    protected Connection connection;

    public void setup() throws SQLException{
        logger.debug("Getting connection and setting autocommit to FALSE");
        connection = StaticConnectionPool.getPooledConnection();
    }

    public void teardown() throws SQLException{ 
        logger.debug("Rollback connection");
        connection.rollback();
        logger.debug("Close connection");
        connection.close();
    }

    @Test
    public void test() throws Exception{
        try{
            setup();
            //test
        }catch(Exception e){ //making sure that the teardown will run even if the test is failing 
            teardown();
            throw e;
        }
        teardown();
    }
}

我尚未对其进行测试,但更优雅的解决方案可能是在同一对象上同步 @Before 和 @After 方法。如果您有机会尝试一下,请更新我。 :)

我希望它也能解决你的问题。

关于java - 不同 OracleDB 连接之间的共享事务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38197158/

相关文章:

sql - Oracle sql日期查询格式个位数

oracle - 如何在Oracle中将临时表转换为永久表,反之亦然

java - BindingResult 和 bean 名称 'configId' 的普通目标对象都不能用作请求属性 Jasper 异常

Java HttpClient : I keep getting login page back when I request a different webpage even after I had already logged in successfully

oracle - 配置 SQL*Plus 以仅返回数据

java - 在 Java(Spring、MVC)中针对 DAO 和服务进行 Junit 测试

java - 如何在两个不同的数据库上运行 JUnit 测试

java - 使用 RSA 算法对 Java 中的文本进行加密

java - 如何从 Java 中的 Random 中获取种子?

java - RxJava 中 debounce() 运算符的意外行为