使用Hibernate通过多个线程保存多个实体

3

我希望能够使用Hibernate实现多线程保存新实体。

注意:客户端无法使用批处理。

因此,我设计了如下结构:

+-----------------+
|+------------------+
||+------------------+     +-----------------------------------------------+
|||                  |     | 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

Hibernate抱怨我的实体自增!

我应该采取什么策略?

我必须实现线程池或其他方法来处理多个线程实体保存吗?

这个线程问题不应该是一个Hibernate任务吗?

2个回答

2

我找不到明显的错误。

建议:

  1. 文档中说“在集群环境中不要使用increment”。这似乎不是您的情况,但请确保只运行一个进程。同一进程中的多个线程应该没有问题。

  2. 使用不同的生成器。对于MySQL,identity是一个很好的选择,因为数据库会给你一个ID。注意,您还需要给列指定正确的类型。


0

使用身份标识(或序列,根据数据库术语)或GUID或您独特的自然业务标识。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接