Gangmax Blog

My Tip 52

  1. 昨天的“保存没有写入数据库”的问题,原因已经找到:在persistence.xml中有如下配置:
1
<persistence-unit name="IncidentTicketServicePU" transaction-type="JTA">

同时,在我的代码中使用以下代码获得EntityManager实例:

1
2
3
EntityManagerFactory emf = 
Persistence.createEntityManagerFactory("IncidentTicketServicePU");
EntityManager em = emf.createEntityManager();

之所以使用这种方式而没有使用@PersistenceContext注入EntityManager,是因为当时使用注入方式不成功所以选择了使用工厂方式获得。今天得知在POJO上是无法使用@PersistenceContext注入的,只能在ejb上使用,这就是为什么注入失败的原因。

用工厂方式获得EntityManager的问题是:EntityManager的transaction实际上应该由应用程序管理,而非JTA管理。但是由于设置了transaction-type=”JTA”,实际上并没有任何代码负责对transaction的管理,所以persist执行之后transaction并没有commit,因此数据库里并没有发生改变。要解决这个问题有两种方法:

  1. 将transaction-type=”JTA”改为transaction-type=”RESOURCE_LOCAL”,并且在程序EntityManager前后手动处理transaction:
1
2
3
entityManager.getTransaction().begin();
entityManager.persist(it);
entityManager.getTransaction().commit();
  1. 不修改transaction-type=”JTA”,并且使用session bean,在session bean中使用@PersistenceContext注入EntityManager。两种方式都可以正常运行,但是为了使代码清晰,最终选择了第二种方法。

  2. 当设置entity bean中的多个”oneToMany”字段为”fetch=FetchType.EAGER”时,发生”HibernateException: cannot simultaneously fetch multiple bags”异常,参考该文章解决。

  3. 当persist已存在的的entity bean时,发生如下异常:

1
2
org.hibernate.PersistentObjectException: 
detached entity passed to persist: com.sun.itsp.itms.entity.IncidentTicket
解决方法:不能直接entityManager.persist(it);需要使用merge: entityManager.persist(entityManager.merge(it)).

Comments