场景:我遇到了一些在事务中混合 JPA 和 JDBC 的代码。JDBC 正在插入一个基本上是空白行的表,将主键设置(SELECT MAX(PK) + 1)
为middleName
临时时间戳。然后该方法从同一个表中选择max(PK)
+那个临时时间戳来检查是否存在冲突。如果成功,它会取消middleName
和更新。该方法返回新创建的主键。
问题:
有没有更好的方法将实体插入数据库,将 PK 设置为max(pk) + 1
并获得对新创建的 PK 的访问权限(最好使用 JPA)?
环境: 使用 EclipseLink,需要同时支持多个版本的 Oracle 和 MS SqlServer 数据库。
奖励背景:我问这个问题的原因是因为我java.sql.BatchUpdateException
在运行集成测试时将此方法作为链的一部分调用时遇到了。链的上半部分使用 JPAEntityManager
来持久化一些对象。
有问题的方法
@Override
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public int generateStudentIdKey() {
final long now = System.currentTimeMillis();
int id = 0;
try {
try (final Connection connection = dataSource.getConnection()) {
if (connection.getAutoCommit()) {
connection.setAutoCommit(false);
}
try (final Statement statement = connection.createStatement()) {
// insert a row into the generator table
statement.executeUpdate(
"insert into student_demo (student_id, middle_name) " +
"select (max(student_id) + 1) as student_id, '" + now +
"' as middle_name from student_demo");
try (final ResultSet rs = statement.executeQuery(
"select max(student_id) as student_id " +
"from student_demo where middle_name = '" + now + "'")) {
if (rs.next()) {
id = rs.getInt(1);
}
}
if (id == 0) {
connection.rollback();
throw new RuntimeException("Key was not generated");
}
statement.execute("update student_demo set middle_name = null " +
"where student_id = " + id);
} catch (SQLException statementException) {
connection.rollback();
throw statementException;
}
}
} catch (SQLException exception) {
throw new RuntimeException(
"Exception thrown while trying to generate new student_ID", exception);
}
return id;
}