2012-08-27 58 views
3

我想通過休眠多線程保存新實體。休眠多線程保存多個實體

OBS:我無法在客戶端上使用批處理。

所以我做了這樣的結構:

+-----------------+ 
|+------------------+ 
||+------------------+  +-----------------------------------------------+ 
|||     |  | Each thread do these steps:     | 
||| Multiple Threads |  | - get EntityManagerFactory     | 
|||     |---> | - create Entity Manager      | 
||| Creating new  |  | - begin new transaction      | 
+|| Entities on |  | - create new entity (with autoincrement id) | 
+|  Hibernate |  | - persist         | 
    +------------------+  | - commit the transaction      | 
          | - close the entity manager     | 
          +-----------------------------------------------+ 

實體:

@Entity 
@Table(name="EN_TEST") 
public class EnTest { 
    private long id; 

    private String name; 

    public EnTest() { 
    } 

    @Id 
    @GeneratedValue(generator="increment") 
    @GenericGenerator(name="increment", strategy = "increment") 
    @Column(name = "ID") 
    public long getId() { 
     return id; 
    } 

    @SuppressWarnings("unused") 
    private void setId(long id) { 
     this.id = id; 
    } 

    public void setName(String name) { 
     this.name = name; 
    } 

    @Column(length = 20) 
    public String getName() { 
     return name; 
    } 
} 

的Java的東西(DBHandler):

// just to get the session factory 
public class DBHandler { 
    private static DBHandler dbHandler; 

    private static EntityManager entityManager; 

    public static DBHandler get() { 
     if (dbHandler == null) { 
      dbHandler = new DBHandler(); 
     } 

     return dbHandler; 
    } 

    private DBHandler() { 
     try { 
      this.sessionFactory = Persistence.createEntityManagerFactory("a_persistence_unit"); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
    } 

    private EntityManagerFactory sessionFactory; 

    public EntityManagerFactory getSessionFactory() { 
     return sessionFactory; 
    } 
} 

的Java的東西(創建過程):

public class CreateTest { 

    // this is accessed by multiple threads to create new entities 
    public static void crateNewEntityTest(String name) { 
     EntityManagerFactory factory = DBHandler.get().getSessionFactory(); 

     EntityManager entityManager = factory.createEntityManager(); 

     entityManager.getTransaction().begin(); 

     EnTest newEnTest = new EnTest(); 
     newEnTest.setName(name); 

     entityManager.persist(newEnTest); 

     entityManager.getTransaction().commit(); 
     entityManager.close(); 
    } 

     // The creation of threads and saving, this is just an example: 
    public static void main(String[] args) { 
     for (int i = 0; i < 5; i++) { 
      new Thread() { 
       public void run() { 
        CreateTest.createNewEntityTest("Name_" + i); 
       }; 
      }.start(); 
     } 
    } 
} 

錯誤:

Caused by: javax.persistence.PersistenceException: org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update 
    at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1389) 
    at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1317) 
    at org.hibernate.ejb.TransactionImpl.commit(TransactionImpl.java:81) 
    ... 2 more 
Caused by: org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update 
    at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:96) 
    at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66) 
    at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:275) 
    at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:268) 
    at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:184) 
    at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321) 
    at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:51) 
    at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1216) 
    at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:383) 
    at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:133) 
    at org.hibernate.ejb.TransactionImpl.commit(TransactionImpl.java:76) 
    ... 2 more 
Caused by: java.sql.BatchUpdateException: Duplicate entry '3' for key 'PRIMARY' 
    at com.mysql.jdbc.PreparedStatement.executeBatchSerially(PreparedStatement.java:1666) 
    at com.mysql.jdbc.PreparedStatement.executeBatch(PreparedStatement.java:1082) 
    at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:70) 
    at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:268) 
    ... 10 more 

的休眠抱怨我的實體的自動增量!

我應該採取什麼策略?

我必須實現一個線程池或其他東西來處理多線程實體保存嗎?

此線程問題不是休眠任務?

回答

1

我找不到明顯的錯誤。

建議:

  1. 文檔說 「不要在集羣環境中使用increment」。這似乎不是你的情況,但要確保你只運行一個進程。同一過程中的多個線程應該可以。

  2. 使用不同的發生器。對於MySQL,identity是個不錯的選擇,因爲數據庫會給你一個ID。請注意,您也需要爲列提供正確的類型。

0

使用標識(或序列取決於DB termology)或GUID或您獨特的自然業務標識。