簡體   English   中英

JPA:如何將PK設置為MAX(PK)+ 1

[英]JPA: How to INSERT setting PK to MAX(PK) + 1

場景:我遇到了一些在事務中混合JPA和JDBC的代碼。 JDBC正在對一個基本上為空行的表進行INSERT,將主鍵設置為(SELECT MAX(PK) + 1) ,將middleName設置為臨時時間戳。 然后該方法從同一個表中選擇max(PK) +臨時時間戳以檢查是否存在沖突。 如果成功,則將middleName和更新middleName 該方法返回新創建的主鍵。

問題:是否有更好的方法將實體插入數據庫,將PK設置為max(pk) + 1並獲得對新創建的PK(最好使用JPA)的訪問權限?

環境:使用EclipseLink並需要支持Oracle和MS SqlServer數據庫的多個版本。

獎金背景:我問這個問題的原因是因為我在運行集成測試時將此方法作為鏈的一部分調用時遇到了java.sql.BatchUpdateException 鏈的上半部分使用JPA EntityManager來保存一些對象。

有問題的方法

@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;
}

首先:很難回答這個問題。 但我知道,有時你必須處理魔鬼:(

從技術上講,它不是JPA,但如果您使用Hibernate作為JPA-Provider,那么您可以繼續使用

@org.hibernate.annotations.GenericGenerator(
    name = “incrementGenerator”,
    strategy = “org.hibernate.id.IncrementGenerator”)
@GeneratedValue(generator="incrementGenerator")
private Long primaryKey;

Hibernate解決方案是“線程安全的”,但不是“群集安全”,即如果您在多個主機上運行應用程序,則可能會失敗。 您可能會捕獲相應的異常並重試。

如果您堅持使用您的解決方案:關閉 ResultSetStatementConnection 對不起,最初沒有抓住try-with-resources。

JDBC代碼是病態的,毫無意義,並且不適用於多用戶環境。

我強烈建議修復代碼以使用序列對象或序列表。

在JPA中,您可以使用排序。

請參閱http://en.wikibooks.org/wiki/Java_Persistence/Identity_and_Sequencing#Sequencing

如果您真的想要自己進行排序,可以自己分配Id,使用PrePersist分配您自己的ID,或者在EclipseLink中實現您自己的Sequence子類,它可以滿足您的需求。 您需要使用SessionCustomizer注冊此Sequence對象。

請參閱http://wiki.eclipse.org/EclipseLink/Examples/JPA/CustomSequencing

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM