`
koen
  • 浏览: 81880 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

使用JPA的EntityManager.persist()无法保存到数据库的问题

阅读更多

 

我这两天刚开始使用JPA,遇到了一个问题,现象是这样的:使用EntityManager查询对象没有问题,但是持久化对象时,也就是使用entityMananger.persist()时,没有保存到数据库,此时程序没有也没有任何异常抛出。

 

忙了一天也没有搜索到解决方法,第二天和同事讨论,再次进行各种尝试,包括在persist前后加入transaction控制,如下:

 

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

 

其中有一段代码是关于该异常的:

 

public EntityTransaction getTransaction() {
		if ( transactionType == PersistenceUnitTransactionType.JTA ) {
			throw new IllegalStateException( "A JTA EntityManager cannot use getTransaction()" );
		}
		return tx;
	}

 

看到“transactionType”字样,灵机一动,联想到在persistence.xml中有以下配置:

 

<persistence-unit name="IncidentTicketServicePU" transaction-type="JTA">

 

这时我想到这里的“transaction-type”可能需要设成其他值。搜索persistence.xml的schema定义“http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd”,在其中发现如下内容:

 

<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",如下:

 

<persistence-unit name="IncidentTicketServicePU" transaction-type="RESOURCE_LOCAL">

 

再跑,数据成功插入数据库。

 

 

经过思考,我觉得问题的原因是这样的:首先,

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

 

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
0
分享到:
评论
3 楼 k1280000 2012-08-27  
建议你看看这篇文字 http://wenku.baidu.com/view/34332f6327d3240c8447ef48.html
2 楼 sxitzmg 2011-12-16  
感谢啊,困扰我48小数的bug解决了
1 楼 prosper 2010-03-24  
我也遇到了这样的问题。(Spring MVC 2 + JPA,  MySQL + Tomcat 6, )

我需要在JUnit里,手动读配置Spring文件,并获得DAO, Service的实例,然后测试
增删改等等操作。

我在里没有定义任何transaction-type,

只是陈列了要储存的类:     <persistence-unit name="punit">
<!-- provider>org.hibernate.ejb.HibernatePersistence</provider -->
   
<class>com.my.jpa.model.Customer</class>

我不能用EJB因为容器是Tomcat。但是我这样写出来的DAO只能在Web app
里运行,到了 JUNIT里就发生 javax.persistence.RollbackException: Transaction marked as rollbackOnly.
请问楼主应该怎么办?


在DAO里:

@Repository("customerDao")
class CustomerDAO{
@PersistenceContext
private EntityManager em;
...
}


在Service里:

@Service("customerService")
@Transactional
class CustomerService{
@Autowired
private CustomerDAO customerDao;

}

在Spring config file里:   

    <bean id="transactionManager"
        class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory" />
    </bean>
    <tx:annotation-driven transaction-manager="transactionManager" />   
    <bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />
<!-- persistence -->
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />



相关推荐

    JPA连接数据库增删改查

    1. **增加(Create)**: 创建一个新的实体实例,然后调用`EntityManager.persist()`方法将其保存到数据库。 ```java EntityManagerFactory emf = Persistence.createEntityManagerFactory("myPersistenceUnit"); ...

    JPA (一)

    - **持久化(Persist)**:使用 `entityManager.persist(entity)` 方法将新实体保存到数据库。 - **查找(Find)**:通过 `entityManager.find(Entity.class, id)` 可以根据实体类和主键找到对应的实体。 - **更新...

    JPA+Netbeans6直接操作数据库

    在这里,我们需要指定持久化单元(Persistence Unit)的名称,使用的JPA提供商,以及连接到数据库的相关属性。 3. **使用EntityManager**:JPA的核心接口,通过EntityManager我们可以执行CRUD(Create, Read, ...

    jpasql.rar

    **Entity Manager(实体管理器)** 是JPA的核心组件,它维护了实体对象的状态,并负责将这些对象保存到数据库或从数据库加载它们。`EntityManager`提供了方法如`persist()`, `merge()`, `remove()`, `find()`等来...

    jpa.rar_Java JPA

    1. 插入(Persist):使用`entityManager.persist(entity)`将新对象保存到数据库。 2. 更新(Merge):如果实体已经存在数据库中,`entityManager.merge(entity)`会更新其状态。 3. 删除(Remove):`...

    jpa对表的crud操作

    例如,创建一个新的`Person`对象并将其保存到数据库: ```java public void save() { Person person = new Person("aaa", 121); entityManager.persist(person); } ``` 这段代码首先创建了一个新的`Person`实例...

    JPA图书管理(连接数据库)

    - **保存(Persist)**: 使用`entityManager.persist(entity)`将新实体保存到数据库。 - **加载(Find)**: 通过`entityManager.find(Entity.class, id)`获取指定ID的实体。 - **更新(Merge)**: `entityManager....

    entitymanager(hibernate)

    - **创建(Create)**:使用`entityManager.persist(entity)`将新实体保存到数据库。 - **读取(Read)**:通过`entityManager.find(Class&lt;T&gt; entityClass, ID id)`方法查找特定ID的实体。 - **更新(Update)**...

    07_JPA详解_使用JPA加载_更新_删除对象.zip

    当实体处于持久化状态时,任何改变都会自动同步到数据库。通过`entityManager.persist()`方法可将瞬态对象变为持久态。已持久化的对象,其属性更改后调用`entityManager.flush()`会触发更新。 #### 3.2 merge()方法...

    springbootjpa.zip

    - Create:JPA通过`EntityManager.persist()`方法将新建的对象保存到数据库中。 - Read:`EntityManager.find()`或JPQL(Java Persistence Query Language)查询语言用于获取数据库中的数据。 - Update:更新操作...

    基于JPA的CRUD例子

    创建操作(Create):使用`EntityManager`的`persist()`方法将新实体保存到数据库。 ```java EntityManager entityManager = entityManagerFactory.createEntityManager(); EntityTransaction tx = entityManager....

    springboot整合mybatis整合jpa使用entityManger

    例如,你可以使用`entityManager.persist()`来保存新实体,`entityManager.find()`来查找实体,`entityManager.merge()`来更新实体,以及`entityManager.remove()`来删除实体。EntityManager还提供了事务管理和查询...

    jpa--15.jpa基本api

    2. **保存实体(Persist)**: 使用`EntityManager.persist(entity)`方法将新实体保存到数据库,如果实体已经存在,此操作会更新对应的数据库记录。 3. **查找实体(Find)**: `EntityManager.find(Class entity...

    JPA CRDU Programming Patterns

    在JPA中创建实体非常直观,可以通过构造器或setter方法设置实体属性,然后通过`EntityManager`的`persist()`方法将实体持久化到数据库中。例如,对于一个名为`User`的简单实体: ```java User user = new User(); ...

    jpa实现数据库操作

    - `entityManager.persist(entity)`:将对象持久化到数据库。 - `entityManager.find(Entity.class, id)`:根据ID查找对象。 - `entity.setProperty(value)` 和 `entityManager.merge(entity)`:更新对象。 - `...

    JPA (Java Persistence API)

    4. **更新(Merge)**: `EntityManager.merge()`方法将一个脱离管理的实体合并到当前的实体管理器上下文中,然后持久化到数据库。 5. **删除(Remove)**: `EntityManager.remove()`方法用来删除一个持久化实体,它...

    JPA.rar_JAVAEE系统_JavaEE_Javaee jpa_订单管理

    1. **实体类与表映射**:在`Order`类中,我们可以使用`@Entity`注解标识这是一个JPA实体,`@Table(name = "orders")`注解指定它映射到数据库中的`orders`表。此外,类的属性可能使用`@Id`、`@GeneratedValue`等注解...

    JPA(Java Persistence API) JPA中文教程

    - 插入(Persist):调用`entityManager.persist(entity)`将新实体保存到数据库。 - 更新(Merge):`entityManager.merge(entity)`用于更新现有实体。 - 删除(Remove):`entityManager.remove(entity)`从...

    hibernate_ jpa.jar

    1. **保存(Save)**:使用EntityManager的persist()方法保存新实体,或merge()方法更新已存在的实体。 2. **删除(Delete)**:调用remove()方法删除实体,实体必须是管理状态的。 3. **加载(Load)**:find()...

    关于SH JPA 简单的CRUD操作

    使用Hibernate JPA,开发者可以利用其强大的ORM(Object-Relational Mapping)能力,将Java对象直接映射到数据库表。 6. **Restful API** Restful API是一种Web服务设计模式,通过HTTP方法(GET, POST, PUT, ...

Global site tag (gtag.js) - Google Analytics