不允许在共享 EntityManager 上创建事务 - 使用 Spring 事务或 EJB CMT

Posted

技术标签:

【中文标题】不允许在共享 EntityManager 上创建事务 - 使用 Spring 事务或 EJB CMT【英文标题】:Not allowed to create transaction on shared EntityManager - use Spring transactions or EJB CMT 【发布时间】:2013-07-25 12:05:57 【问题描述】:

此帖是JPA How to get the value from database after persist的延续

当我执行以下操作时出现以下异常,我该如何解决?

Not allowed to create transaction on shared EntityManager - use Spring 
transactions or EJB CMT

DAOImpl代码

public void create(Project project) 
        entityManager.persist(project);
        entityManager.getTransaction().commit();
        project = entityManager.find(Project.class, project.getProjectId());
        entityManager.refresh(project);
        System.out.println("Id    -- " + project.getProjectId());
            System.out.println("no -- " + project.getProjectNo());
    

applicationContext.xml

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">

    <bean id="DataSource"
        class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="username" value="scott" />
        <property name="password" value="tiger" />
        <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
        <property name="url" value="jdbc:oracle:thin:@myserver:1521:ORCL" />
    </bean>

    <bean id="entityManagerFactory"
        class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="dataSource" ref="DataSource" />
        <property name="packagesToScan" value="test.entity" />
        <property name="jpaVendorAdapter">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
                <property name="showSql" value="true" />
                <property name="generateDdl" value="false" />
                <property name="databasePlatform" value="org.hibernate.dialect.Oracle10gDialect" />
            </bean>
        </property>
    </bean>

    <context:component-scan base-package="test.net" />

    <tx:annotation-driven transaction-manager="transactionManager"/> 

     <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory" />
    </bean>         

     <context:annotation-config/>

</beans>

【问题讨论】:

【参考方案1】:

我想这里的问题是,虽然你已经为事务管理器定义了 bean,但你没有用 @Transactional 注释 create() 方法,它启用了 spring 事务。

同时删除 entityManager.getTransaction().commit(); 语句,因为现在所有事务管理都将由 spring 处理,如果您保留该语句,那么您将再次遇到相同的错误。

【讨论】:

当您使用 @PersistenceContext 自动连接 entitymanager 时,即使我使用 Transactional 注释方法并删除提交语句,我仍然会收到相同的错误 就像莫里斯说的,这并不能解决我的问题。我得到:javax.persistence.TransactionRequiredException: Executing an update/delete query" 错误【参考方案2】:

在方法上注入 EntityManagerFactory 而不是 EntityManager 和 javax.transaction.Transactional 注释解决了我的问题,如下所示。

//Autowire EntityManagerFactory
@PersistenceUnit(unitName = "readwrite.config")
private EntityManagerFactory entityManagerFactory;


//Use below code on create/update
EntityManager entityManager = entityManagerFactory.createEntityManager();

entityManager.getTransaction().begin();
if (!ObjectUtils.isEmpty(entity) && !entityManager.contains(entity)) 
   entityManager.persist(entity);
   entityManager.flush();

entityManager.getTransaction().commit();

【讨论】:

这解决了我的问题,但我唯一的问题是我们是否可以从 entityManagerFactory 创建 entityManager 作为类成员属性并在我的 dao 类中使用的不同方法中使用它? org.springframework.beans.factory.NoSuchBeanDefinitionException:没有名为“readwrite.config”的bean可用 这解决了我的问题。但是为什么@Transactional 注解不能代替 begin() 工作呢?【参考方案3】:

您需要删除 entityManager.getTransaction().begin() 语句并使用启用 Spring 事务的 @Transactional 注释方法

【讨论】:

以上是关于不允许在共享 EntityManager 上创建事务 - 使用 Spring 事务或 EJB CMT的主要内容,如果未能解决你的问题,请参考以下文章

我应该多久创建一次 EntityManager?

如何在 Symfony 单命令应用程序中访问 EntityManager?

创建没有 persistence.xml 配置文件的 JPA EntityManager

安卓手机共享网络电脑连接不上怎么办

不允许同一用户使用多个用户名与服务器或共享资源建立多个连接

win10系统vpn连接不上怎么办