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

休眠抱怨我的实体的自动增量!

我应该采取什么策略?

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

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

4

2 回答 2

2

我找不到明显的错误。

建议:

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

  2. 使用不同的发电机。对于 MySQL,identity是一个很好的候选,因为数据库会给你一个 ID。请注意,您还需要为列提供正确的类型。

于 2012-08-27T15:17:31.197 回答
0

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

于 2012-08-27T15:20:32.390 回答