我想通过多个线程使用hibernate保存新实体。
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 stuff(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 stuff(创建过程):
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
hibernate抱怨我的实体自动增量!
我应该采取什么策略?
我必须实现线程池或其他东西来处理多线程实体保存吗?
这个线程问题不是一个休眠任务吗?
答案 0 :(得分:2)
我找不到明显的错误。
建议:
文档说“不要在群集环境中使用increment
”。这似乎不是你的情况,但要确保你只运行一个进程。同一进程中的几个线程应该没问题。
使用其他生成器。对于MySQL,identity
是一个很好的候选者,因为数据库会给你一个ID。请注意,您还需要为列提供正确的类型。
答案 1 :(得分:0)
使用身份(或序列取决于DB术语)或GUID或您独特的自然商业身份。