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就可以。
两种方式都可以正常运行,但是为了是代码的优雅,最终选择了第二种方法。
分享到:
相关推荐
5. **Auditing**:Spring Data JPA 提供了审计功能,可以自动记录实体的创建时间和修改时间。这可以通过 `@CreatedDate` 和 `@LastModifiedDate` 注解实现。 6. **Integration with Spring MVC**:Spring Data JPA ...
首先,实体(Entity)是JPA中的核心概念,它代表数据库中的一个记录。实体的身份(Identity Fields)用于唯一标识每个记录,通常是主键的组成部分。在Java中,对象的身份有两种方式:numeric identity(基于内存地址...
此外,JPA还支持 Criteria API,这是一种类型安全的API,用于构建动态查询,避免了字符串拼接造成的潜在错误。 在实际应用中,JPA通常与Spring框架结合使用,通过Spring Data JPA提供更高级别的抽象,简化了持久层...
**JPA(Java Persistence API)相关资源收集** Java Persistence API是Java平台上的一个标准,用于管理关系数据库中的数据。它提供了对象/关系映射(ORM)功能,使得开发者可以使用面向对象的方式处理数据库操作,...
9. **JPA Querydsl**:作为可选扩展,项目可能还使用Querydsl,这是一个类型安全的查询API,允许开发者编写更清晰的查询表达式,避免了编译时错误。 通过这个“springData-jpa-demo”,开发者可以逐步学习如何配置...
8. 配置灵活性:Spring Data JPA允许通过Java配置或XML配置来设置JPA的相关属性,如实体管理工厂、事务管理器等。 9. 支持JPA供应商:如Hibernate、EclipseLink等,具备良好的兼容性。 10. 异常处理:统一的异常...
- 更新测试,修改实体属性并调用merge(),确认数据库记录被更新。 - 删除测试,调用remove()方法,确保实体从数据库中被移除。 3. **集成测试** - 集成测试将涉及真实的数据库环境,验证JPA与数据库的交互。 - ...
JPA 定义了一系列异常来处理运行时发生的错误情况,如 `PersistenceException`,它是所有 JPA 异常的父类。 #### 四、实体 实体是 JPA 中的核心概念之一,表示应用程序中的业务对象。它们必须满足一定的规则才能被...
- **更新图书**:调用`merge()`方法,传入已修改的图书对象,JPA会自动更新对应的数据库记录。 - **查询图书**:利用JPQL或 Criteria API 来编写查询语句,获取满足条件的图书。例如,`SELECT b FROM Book b WHERE b...
7. **错误处理和日志记录**:在导入过程中,可能会遇到文件格式错误、数据类型不匹配等问题,需要捕获异常并进行适当处理。同时,记录日志可以帮助追踪和调试问题。 通过这种方式,我们可以构建一个灵活且可扩展的...
接下来是JPA,它是Java平台上的ORM(对象关系映射)规范,允许开发者使用Java对象来操作数据库记录。JPA通过API简化了数据库访问,减少了SQL的编写工作。Spring 2.5对JPA提供了很好的支持,可以将数据访问层与业务...
在2.9.0版本中,修复了一些已知问题,提高了性能和稳定性,使得开发者能够更加顺畅地进行JPA相关的操作。 在Android环境中,日志记录是一个重要的工具,用于调试和监控应用的行为。SLF4J(Simple Logging Facade ...
- 在Spring配置文件中,我们需要引入JPA的相关依赖,如数据源、实体管理工厂(EntityManagerFactory)、事务管理器等。 - 使用`LocalContainerEntityManagerFactoryBean`来创建EntityManagerFactory,配置数据源、...
此外,源代码通常还包括了错误处理、日志记录、安全性等方面的实践,这些都是提高项目质量和可维护性的重要方面。 总之,Struts、JPA和Spring的整合使得Java Web开发变得更加高效和灵活。通过理解并掌握这种整合...
此外,JPA还提供了 Criteria API,这是一种更强大且类型安全的查询方式,可以避免拼写错误和SQL注入。通过构建Criteria查询,开发者可以在运行时动态生成查询表达式。 在实际项目中,我们经常需要使用到jar包,比如...
批注是JPA中一个重要的特性,允许开发者通过在Java类和属性上添加特定的元数据注解,来定义对象如何映射到数据库表以及相关的操作。 ### JPA基础 JPA的核心组件包括实体(Entity)、实体管理器(EntityManager)、...
JPA(Java Persistence API)是 Java 平台上的一个标准,用于对象关系映射(ORM),使得开发人员可以使用 Java 对象来操作数据库记录。Spring 对 JPA 的整合使得开发者能够方便地在 Spring 应用中利用 ORM 功能。 1...
Spring Data JPA 坑点记录总结 本文总结了使用 Spring Data JPA 时的一些坑点,通过示例代码进行详细的介绍,对读者的学习或者工作具有参考价值。 一、Spring Data JPA 的基本介绍 JPA(Java Persistence API)...
6. **Auditing**:Spring Data JPA提供审计功能,可以自动记录实体的创建时间和修改时间,只需在实体类上添加相应的注解。 7. **事件监听**:通过实现`PreSaveEventListener`、`PostSaveEventListener`等接口,可以...