【问题标题】:Saving multiple entities by multiple threads with hibernate使用休眠的多个线程保存多个实体
【发布时间】:2012-08-22 02:13:38
【问题描述】:

我想通过休眠的多个线程保存新实体。

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

hibernate 抱怨我的实体的自动增量!

我应该采取什么策略?

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

这个线程问题不是休眠任务吗?

【问题讨论】:

    标签: java database multithreading hibernate


    【解决方案1】:

    我找不到明显的错误。

    建议:

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

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

    【讨论】:

      【解决方案2】:

      使用身份(或顺序取决于数据库术语)或 GUID 或您独特的自然业务身份。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-09-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-03-04
        • 1970-01-01
        相关资源
        最近更新 更多