org.hibernate.PersistentObjectException: detached entity passed to persist
设置了主键生成方式:@GeneratedValue(strategy=GenerationType.AUTO) 就不需要再对实体类的id进行设置(mysql环境下)
使用JPA的EntityManager.persist()无法保存到数据库的问题
http://koen.iteye.com/blog/265709
我这两天刚开始使用JPA,遇到了一个问题,现象是这样的:使用EntityManager查询对象没有问题,但是持久化对象时,也就是使用entityMananger.persist()时,没有保存到数据库,此时程序没有也没有任何异常抛出。
忙了一天也没有搜索到解决方法,第二天和同事讨论,再次进行各种尝试,包括在persist前后加入transaction控制,如下:
Java代码
entityManager.getTransaction().begin();
entityManager.persist(it);
entityManager.getTransaction().commit();
entityManager.getTransaction().begin();
entityManager.persist(it);
entityManager.getTransaction().commit();
此时得到一个IllegalStateException: “A JTA EntityManager cannot use getTransaction()”.
Google以上异常描述,得到以下Hibernate的源代码页面:
http://viewvc.jboss.org/cgi-bin/viewvc.cgi/hibernate/branches/Branch_3_2/HibernateExt/entitymanager/src/java/org/hibernate/ejb/AbstractEntityManagerImpl.java?view=markup&pathrev=11268
其中有一段代码是关于该异常的:
Java代码
public EntityTransaction getTransaction() {
if ( transactionType == PersistenceUnitTransactionType.JTA ) {
throw new IllegalStateException( "A JTA EntityManager cannot use getTransaction()" );
}
return tx;
}
public EntityTransaction getTransaction() {
if ( transactionType == PersistenceUnitTransactionType.JTA ) {
throw new IllegalStateException( "A JTA EntityManager cannot use getTransaction()" );
}
return tx;
}
看到“transactionType”字样,灵机一动,联想到在persistence.xml中有以下配置:
Xml代码
<persistence-unit name="IncidentTicketServicePU" transaction-type="JTA">
<persistence-unit name="IncidentTicketServicePU" transaction-type="JTA">
这时我想到这里的“transaction-type”可能需要设成其他值。搜索persistence.xml的schema定义“http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd”,在其中发现如下内容:
Xml代码
<xsd:simpleType name="persistence-unit-transaction-type">
<xsd:annotation>
<xsd:documentation>public enum TransactionType { JTA, RESOURCE_LOCAL };</xsd:documentation>
</xsd:annotation>
<xsd:restriction base="xsd:token">
<xsd:enumeration value="JTA" />
<xsd:enumeration value="RESOURCE_LOCAL" />
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="persistence-unit-transaction-type">
<xsd:annotation>
<xsd:documentation>public enum TransactionType { JTA, RESOURCE_LOCAL };</xsd:documentation>
</xsd:annotation>
<xsd:restriction base="xsd:token">
<xsd:enumeration value="JTA" />
<xsd:enumeration value="RESOURCE_LOCAL" />
</xsd:restriction>
</xsd:simpleType>
当然,这时把persistence.xml中的“transaction-type”改成"RESOURCE_LOCAL",如下:
Java代码
<persistence-unit name="IncidentTicketServicePU" transaction-type="RESOURCE_LOCAL">
<persistence-unit name="IncidentTicketServicePU" transaction-type="RESOURCE_LOCAL">
再跑,数据成功插入数据库。
经过思考,我觉得问题的原因是这样的:首先,
在我的代码中使用了以下代码获得EntityManager实例:
Java代码
EntityManagerFactory emf =
Persistence.createEntityManagerFactory("IncidentTicketServicePU");
EntityManager em = emf.createEntityManager();
EntityManagerFactory emf =
Persistence.createEntityManagerFactory("IncidentTicketServicePU");
EntityManager em = emf.createEntityManager();
之所以使用这种方式而没有使用@PersistenceContext注入EntityManager,是因为当时使用注入方式不成功。今天得知在POJO上是无法使用@PersistenceContext注入的,只能在ejb上使用,这就是为什么之前我使用注入失败的原因。
再回到原来的问题,用工厂方式获得EntityManager发生错误的原因是:用工厂方式获得的EntityManager的transaction实际上应该由应用程序自己管理,而非JTA管理。但是由于设置了transaction-type="JTA",实际上并没有任何代码负责对transaction的管理,而且在代码中手工管理transaction还会报错。要解决这个问题有两种方法:
1. 按照我上面描述的方法修改persistence.xml中的“transaction-type”并编写手工管理transaction的代码;
2. 不修改transaction-type="JTA",使用session bean,在session bean中使用@PersistenceContext注入EntityManager。这样在程序里不用自己控制transaction,直接persist就可以。
两种方式都可以正常运行,但是为了是代码的优雅,最终选择了第二种方法。
分享到:
相关推荐
中文名: 经典Java EE企业应用实战--基于WebLogic/JBoss的JSF+EJB 3+JPA整合开发 原名: 经典Java EE企业应用实战--基于WebLogic/JBoss的JSF+EJB 3+JPA整合开发 作者: 李刚 资源格式: PDF 版本: 第一版 出版社: 电子...
- 行为日志:用于记录用户对系统的操作,同时监视系统运行时发生的错误。 - 文件上传:内置了文件上传接口,方便开发者使用文件上传功能。 - 代码生成:可以帮助开发者快速开发项目,减少不必要的重复操作,花更多...
积分管理系统java源码 Timo v2.0.3 项目介绍 TIMO后台管理系统,基于SpringBoot2.0 + Spring Data ...行为日志:用于记录用户对系统的操作,同时监视系统运行时发生的错误。 文件上传:内置了文件上
ArquillianDemo01 版本 1:在基本 JSF 和 JDBC 程序中演示 Arquillian 的... 被测试的方法使用了 JPA,它给出了一条错误消息,指出它无法检索 EntityManagerFactory。 该程序的一个类似版本仅使用注入的 DataSource 和
TIMO后台管理系统,基于SpringBoot2.0 + Spring Data Jpa + Thymeleaf + Shiro 开发的后台管理系统,采用分模块的方式便于开发和维护,目前支持的功能有:权限管理、部门管理、字典管理、日志记录、文件上传、代码...
spring boot中文文档,从安装到部署。 I. Spring Boot文件 ... 30.3.JPA和Spring Data JPA 30.3.1.实体类 30.3.2.Spring数据JPA存储库 30.3.3.创建和删除JPA数据库 30.3.4.在View中打开EntityM
API错误处理和建模 使用Bean验证进行验证 整合测试 API的良好做法和技巧 高级API建模和实施 建模预测,调查和报告 上传和下载文件 交易电子邮件和域事件 JavaScript和Java的CORS和API消耗 HTTP缓存 带有OpenAPI,...
积分管理系统java源码 Timo v2.0.3 项目介绍 TIMO后台管理系统,基于SpringBoot2.0 + Spring Data ...行为日志:用于记录用户对系统的操作,同时监视系统运行时发生的错误。 文件上传:内置了文件上
积分管理系统java源码 Timo v2.0.3 项目介绍 TIMO后台管理系统,基于SpringBoot2.0 + Spring Data ...行为日志:用于记录用户对系统的操作,同时监视系统运行时发生的错误。 文件上传:内置了文件上
积分管理系统java源码 Timo v2.0.3 项目介绍 TIMO后台管理系统,基于SpringBoot2.0 + Spring Data ...行为日志:用于记录用户对系统的操作,同时监视系统运行时发生的错误。 文件上传:内置了文件上
积分管理系统java源码 Timo v2.0.3 项目介绍 TIMO后台管理系统,基于SpringBoot2.0 + Spring Data ...行为日志:用于记录用户对系统的操作,同时监视系统运行时发生的错误。 文件上传:内置了文件上
积分管理系统java源码 Timo v2.0.3 项目介绍 TIMO后台管理系统,基于SpringBoot2.0 + Spring Data ...行为日志:用于记录用户对系统的操作,同时监视系统运行时发生的错误。 文件上传:内置了文件上
积分管理系统java源码 Timo v2.0.3 项目介绍 TIMO后台管理系统,基于SpringBoot2.0 + Spring Data ...行为日志:用于记录用户对系统的操作,同时监视系统运行时发生的错误。 文件上传:内置了文件上
积分管理系统java源码 Timo v2.0.3 项目介绍 TIMO后台管理系统,基于SpringBoot2.0 + Spring Data ...行为日志:用于记录用户对系统的操作,同时监视系统运行时发生的错误。 文件上传:内置了文件上
积分管理系统java源码 Timo v2.0.3 项目介绍 TIMO后台管理系统,基于SpringBoot2.0 + Spring Data ...行为日志:用于记录用户对系统的操作,同时监视系统运行时发生的错误。 文件上传:内置了文件上
积分管理系统java源码 Timo v2.0.3 项目介绍 TIMO后台管理系统,基于SpringBoot2.0 + Spring Data ...行为日志:用于记录用户对系统的操作,同时监视系统运行时发生的错误。 文件上传:内置了文件上