经过几天对这个问题的调查,我决定提交这个问题,因为发生的事情显然没有意义。
案子
我的计算机配置了本地 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();
}
静态连接池
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 个会话 172 个事务 189