2012-10-22 26 views
0

我剛創建了一個自定義hibernate ID生成器,因爲我不是休眠專家,所以我想對我的代碼獲得一些反饋。生成的ID是select max(id) from table,+1。下面的Hibernate自定義ID生成器代碼是否正確?

public class MaxIdGenerator implements IdentifierGenerator, Configurable { 

    private Type identifierType; 
    private String tableName; 
    private String columnName; 

    @Override 
    public void configure(Type type, Properties params, Dialect dialect) { 
     identifierType = type; 
     tableName = (String) params.getProperty("target_table"); 
     columnName = (String) params.getProperty("target_column"); 
    } 

    @Override 
    public synchronized Serializable generate(SessionImplementor session, 
      Object object) { 
     return generateHolder(session).makeValue(); 
    } 

    protected IntegralDataTypeHolder generateHolder(SessionImplementor session) { 
     Connection connection = session.connection(); 
     try { 
      IntegralDataTypeHolder value = IdentifierGeneratorHelper 
       .getIntegralDataTypeHolder(identifierType 
         .getReturnedClass()); 
      String sql = "select max(" + columnName + ") from " + tableName; 
      PreparedStatement qps = connection.prepareStatement(sql); 
      try { 
       ResultSet rs = qps.executeQuery(); 
       if (rs.next()) 
        value.initialize(rs, 1); 
       else 
        value.initialize(1); 
       rs.close(); 
      } finally { 
       qps.close(); 
      } 
      return value.copy().increment(); 
     } catch (SQLException e) { 
      throw new IdentifierGenerationException(
        "Can't select max id value", e); 
     } 
    } 
    } 

我想知道:

  1. 我怎樣才能讓這個多事務安全? (即如果兩個併發事務插入數據,我怎麼能安全地假定我不會最終擁有兩次相同的ID?) - 我想這裏唯一的解決方案是防止兩個併發的hibernate事務同時運行如果他們使用相同的發生器,這可能嗎?
  2. 如果代碼可以改進:我覺得不對勁不必使用硬編碼​​,"target_column",等...

爲了保證1點),我可以根據需要回退到上插入同步我的java客戶端代碼。

請不要評論我爲什麼使用這種類型的生成器的原因:遺留代碼仍將數據插入到同一數據庫並使用此機制...並且無法修改。是的,我知道,它很糟糕。

回答

2

我認爲實現事務安全行爲的最簡單方法是將代碼用於檢索最大ID並在事務性塊中執行插入語句。 喜歡的東西:

Transaction transaction = session.beginTransaction(); 
//some code... 
transaction.commit(); 
session.close() 

我也建議使用HQL(Hibernate查詢語言)來創建查詢,而不是本地的SQL如果可能的話。此外,根據您的描述,我瞭解到您希望從查詢中獲得唯一的結果,即最大ID。所以,你可以在你的查詢中使用uniqueResult()方法而不是executeQuery。

0

您可以使用AtomicInteger生成ID。這可以被許多線程同時使用。

如果您可以自由使用任何其他ID的提供者,那麼我會建議使用UUID類來生成隨機ID。

UUID.randomUUID(); 

您可以參考link其中包含一些其他方式來生成ID。

相關問題