为什么实体管理器在同一实体的单独线程中只能在entitymanager.close()上更新

时间:2014-11-29 17:11:48

标签: java multithreading jpa entitymanager

我有一个应用程序管理JPA设置(我第一次使用JPA)。

我有一个读者线程和一个写作者线程。

读者可以根据查询或交易创建和关闭实体经理。

编写器线程创建一个实体管理器并读取阻塞队列,以便它知道所有托管实体,因为我有很多一对多/父子关系,如果我有级联类型导致重复异常( com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException),或者没有级联会导致瞬态实体异常(即entitymanager不知道父实体),如果我按实体写入打开和关闭实体管理器。

我遇到的问题是,如果我通过db writer线程持久化,然后通过sql查询进行查询,db reader线程返回null,即使实体持久存储在数据库(mysql)中,并且两个实体管理器都是从同一实体经理工厂。如果我在每次插入后关闭db writer线程中的实体管理器,那么读取器线程确实会知道插入的实体,但是编写器不知道先前插入的父实体并抛出MySQLIntegrityConstraintViolationException。我相信关闭实体管理器似乎会分离所有实体并清除实体管理器的持久化上下文,但如果我通过@PostPersist注释在方法中执行此操作,那么它似乎无助于在读者线程中创建任何实体管理器了解编写器线程中单个实体管理器插入的实体。

如果有任何方法可以让读者线程中创建的实体管理器知道编写器线程完成的插入/更新? (试图驱逐所有,没有太多运气)。迁移到EJB和容器管理的JPA设置是一个很大的变化,我相信我还必须在服务器上运行apache来管理EJB。

我尝试了一些没有太多运气的东西

  • 在持久性上分离实体
  • 持久驱逐实体
  • 级联父实体的持久性
  • 刷新持久化实体
  • 覆盖实体的等号和哈希码
  • 在阅读时绕过缓存

实体经理工厂

    Map<String, String> properties = new HashMap<>();

    properties.put("hibernate.hbm2ddl.auto", createMode);
    properties.put("hibernate.connection.driver_class", ConfigUtil.combined().getString("db.driver"));
    properties.put("hibernate.dialect", ConfigUtil.combined().getString("db.dialect"));
    properties.put("hibernate.connection.url", ConfigUtil.combined().getString("db.url"));
    properties.put("hibernate.connection.username", ConfigUtil.combined().getString("db.username"));
    properties.put("hibernate.connection.password", ConfigUtil.combined().getString("db.password"));
    properties.put("hibernate.ejb.naming_strategy", "org.hibernate.cfg.ImprovedNamingStrategy");

    try {
        PersistUtilHelper emh = new PersistUtilHelper(properties);

示例实体

public abstract class EntityBase implements Serializable {

@Id
@Column(columnDefinition = "BINARY(16)", length = 16, updatable = false, nullable = false)
public UUID getId() {
    ensureId();
    return id;
}

@Version
private Long version;

public Long getVersion() {
    return version;
}

public void setVersion(Long version) {
    this.version = version;
}

@Override
public boolean equals(Object o) {
    // generated by IDEA
    if (this == o)
        return true;
    if (!(o instanceof EntityBase))
        return false;
    EntityBase that = (EntityBase) o;
    return id.equals(that.id);
}

@Override
public int hashCode() {
    ensureId();
    return id.hashCode();
}

// JPA
protected EntityBase() {
}

protected void setId(UUID id) {
    this.id = id;
}

private void ensureId() {
    if (id == null)
        id = UUID.randomUUID();
}

private UUID id;
}




@Entity
@Table(name = "listing", uniqueConstraints = { @UniqueConstraint(columnNames = { "base", "quote",     "prompt" }),
    @UniqueConstraint(columnNames = { "base", "quote" }) })
public class Listing extends EntityBase {

@ManyToOne(optional = false)
//@Column(unique = true)
public Asset getBase() {
    return base;
}

@PostPersist
private void postPersist() {
    //  PersistUtil.clear();
    //  PersistUtil.refresh(this);
    //PersistUtil.merge(this);
    // PersistUtil.close();
    //PersistUtil.evict(this);

}

@ManyToOne(optional = false)
//@Column(unique = true)
public Asset getQuote() {
    return quote;
}

@Nullable
//@Column(unique = true)
public String getPrompt() {
    return prompt;
}

@Override
public boolean equals(Object obj) {
    if (obj instanceof Listing) {
        Listing listing = (Listing) obj;

        if (!listing.getBase().equals(getBase())) {
            return false;
        }

        if (!listing.getQuote().equals(getQuote())) {
            return false;
        }

        return true;
    }

    return false;
}

@Override
public int hashCode() {
    return getQuote().hashCode() + getBase().hashCode();
}

作家线程

public class DatabaseWriter implements Runnable {
private static final int defaultBatchSize = 20;
private static boolean running = false;
private static boolean shutdown = false;
private static ExecutorService service;
private static FutureTask persitanceTask = null;

 private static BlockingQueue<EntityBase[]> blockingQueue;

 public DatabaseWriter(BlockingQueue<EntityBase[]> blockingqueue) {
    this.blockingQueue = blockingqueue;
}

@Override
public void run() {
    EntityBase[] entities = null;
    boolean persited = true;
    while (!shutdown) {

        try {
            entities = blockingQueue.take();
            for (EntityBase entity : entities)
                PersistUtil.persist(entity);
        }

        catch (Exception e) {

        } finally {
        }

    }
    PersistUtilHelper.closeEntityManager();

}
}

样本阅读

  Listing listing = PersistUtil.queryZeroOne(Listing.class, "select a from Listing a where base=?1     and quote=?2", base, quote);

读者线程

     public static <T> T queryZeroOne(Class<T> resultType, String queryStr, Object... params) {

    try {
        //EntityManager em = createEntityManager();
        final TypedQuery<T> query = PersistUtilHelper.createQuery(queryStr, resultType);
        //query.setHint("org.hibernate.cacheable", false);
        //  query.setHint("javax.persistence.cache.retrieveMode", javax.persistence.CacheRetrieveMode.BYPASS);
        //query.setHint("org.hibernate.cacheMode", CacheMode.IGNORE);

        if (params != null) {
            for (int i = 0; i < params.length; i++) {
                Object param = params[i];
                query.setParameter(i + 1, param); // JPA uses 1-based indexes
            }
        }
        try {
            return query.getSingleResult();
        } catch (NoResultException x) {
            return null;
        }
    } finally {

        PersistUtilHelper.closeEntityManager();
    }
}

Helper Util

 public class PersistUtilHelper {

private static EntityManagerFactory emf = null;
private static final ThreadLocal<EntityManager> threadLocal = new ThreadLocal<EntityManager>();
private static ConcurrentHashMap<String, EntityManager> entityManagers = new ConcurrentHashMap<String, EntityManager>();

PersistUtilHelper(Map<String, String> properties) {
    emf = Persistence.createEntityManagerFactory("xyz.schema", properties);
}

public static EntityManagerFactory getEntityManagerFactory() {

    return emf;
}

public static EntityManager getEntityManager() {
    EntityManager em = threadLocal.get();
    if (em == null || !em.isOpen()) {
        em = emf.createEntityManager();
        entityManagers.put(em.toString(), em);
        threadLocal.set(em);
    }
    return em;
}

public static <T> TypedQuery<T> createQuery(String qlString, Class<T> resultClass) {
    getEntityManager().clear();
    return getEntityManager().createQuery(qlString, resultClass);
}

public static Query createQuery(String qlString) {
    return getEntityManager().createQuery(qlString);
}

public static void closeEntityManager() {
    EntityManager em = threadLocal.get();
    if (em != null) {
        entityManagers.remove(em.toString());
        em.close();
        threadLocal.set(null);
    }
}

public static void clearEntityManager() {
    EntityManager em = threadLocal.get();
    if (em != null) {
        em.clear();
    }
}

public static void closeEntityManagerFactory() {
    emf.close();
    emf = null;
}

public static void beginTransaction() {
    getEntityManager().getTransaction().begin();
}

public static void rollback() {
    getEntityManager().getTransaction().rollback();
}

public static void commit() {
    getEntityManager().getTransaction().commit();
}

public static void detach(Object entity) {
    Iterator it = entityManagers.values().iterator();

    while (it.hasNext()) {
        EntityManager em = (EntityManager) it.next();
        if (em != null || em.isOpen())
            em.detach(entity);
    }
}

public static void evict(Object entity) {
    Iterator it = entityManagers.values().iterator();

    while (it.hasNext()) {
        EntityManager em = (EntityManager) it.next();
        if (em != null || em.isOpen())
            em.getEntityManagerFactory().getCache().evict(entity.getClass(), ((EntityBase) entity).getId());
        //em.getEntityManagerFactory().createEntityManager(SynchronizationType.)

    }
}

public static void merge(Object entity) {
    Iterator it = entityManagers.values().iterator();

    while (it.hasNext()) {
        EntityManager em = (EntityManager) it.next();
        if (em != null || em.isOpen())
            em.merge(entity);
    }
}

public static void refresh(Object entity) {
    Iterator it = entityManagers.values().iterator();
    while (it.hasNext()) {
        EntityManager em = (EntityManager) it.next();
        if (em != null || em.isOpen())
            em.refresh(entity);

    }
}

public static boolean isActive() {
    return getEntityManager().getTransaction().isActive();

}

public static boolean isOpen() {
    return emf.isOpen();
}

public static void evictAll() {
    emf.getCache().evictAll();

}

}

1 个答案:

答案 0 :(得分:0)

当您致电commit时,您的代码似乎毫无意义,请不要忘记在完成工作后提交您的工作。