调用super的方法时出现JPA Transaction错误

Posted

技术标签:

【中文标题】调用super的方法时出现JPA Transaction错误【英文标题】:JPA Transaction error when calling super's method 【发布时间】:2013-09-04 23:42:59 【问题描述】:

我有一个类似的方法:

package com.abc.pkg.service.db.impl;



public class OperationServiceImpl extends BaseService implements OperationService 



    @Transactional
        @Override
        public String update(Operation operation,User user) 

        BigDecimal count=(BigDecimal)em.createNativeQuery("select count(*) from RBMCORE.T_RBM_OPSCREENS_OPERATIONS where s_name= ? and id!= ?").setParameter(1, operation.getName()).setParameter(2, operation.getId()).getSingleResult();

        if(count.intValue()>0)
            return "This operation name is used by another operation. Please change it";

        super.removeOpAppRelation(operation.getId(), -1);

        Operation oldOperation=operationRepository.save(operation);
        List<Operation> operations=new ArrayList<Operation>();
        operations.add(operation);


而super.insertOpAppRelation方法内容为:

package com.abc.pkg.service.db.impl;
public abstract class BaseService 


@PersistenceContext
protected EntityManager em;

@Transactional
    protected  void removeOpAppRelation(int opId,int appId)
        String sql="delete table a where 1=1";
        if(opId>0)
            sql+=" and op_id="+opId;

        if(appId>0)
            sql+=" and app_id="+appId;

        em.createNativeQuery(sql).executeUpdate();
    

并且触发了removeOpAppRelation方法,抛出了这个异常:

javax.persistence.TransactionRequiredException: 执行一个 更新/删除查询

在我的 appcontext.xml 中有这些:

<tx:annotation-driven transaction-manager="transactionManager"/>
<context:component-scan base-package="com.abc.pck"/>

<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="dataSource" ref="rbmDataSource"/>
    <property name="packagesToScan" value="com.ttech.rbm.model"/>
    <property name="jpaVendorAdapter">
        <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
            <property name="databasePlatform" value="org.hibernate.dialect.Oracle10gDialect"/>
            <property name="showSql" value="true"/>
            <property name="generateDdl" value="true"/>
        </bean>
    </property>
    <property name="jpaProperties">
        <props>
            <prop key="hibernate.hbm2ddl.auto">none</prop>
        </props>
    </property>
</bean>

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

作为事务管理器,我正在使用:

org.springframework.orm.jpa.JpaTransactionManager

有什么想法吗?跟继承有关系吗?

【问题讨论】:

类和超类都位于com.abc.pck包下吗? 它们在完全相同的包下。但完整的包名不是 com.abc.pck 。它是 com.abc.pck.service.db.impl。我已将其作为前缀包以使其扫描所有子包 嗯.. 没有足够的信息来进一步调试您的问题。我建议您将 org.hibernate.transaction 记录器设置为 DEBUG(或 hibernate 4.2 或更高版本上的 org.hibernate.engine.transaction),从您的日志中您将看到事务开始/提交 实际上我正在使用带有 JPA 的休眠。这里的另一个区别是,我从其他地方调用这个方法(@controller 注释类),我现在遇到了这个问题。 【参考方案1】:

您的代码非常简单。

使用的“em”没有在你的任何类中声明。

我期待一个

@PersistenceContext
EntityManager em;

在你的一门课上。

如果它在两个类中,它将解释您的错误,因为在这种情况下,将注入两个不同的实体管理器,它们不会共享相同的事务。

为避免这种情况,您应该在您的超类中使用抽象方法“getEm()”,并在您的子类中覆盖它,并提供在那里注入的 em。

另外,父类上的@Transactional 在子类调用时将不起作用,因为它是直接从子类调用的超方法,而不是通过spring-aop-proxy - spring 没有机会拦截。

【讨论】:

感谢您的回答。我已经编辑了这个问题。现在,您可以看到有一个实体管理器和事务管理器处理实体管理器的事务。而且我认为,由于 entityManager 对象是受保护的对象,它在子类和父类上是单例的(因为它们都共享一个 entityManager 对象)。那么在我更新问题之后,有什么想法吗? 如果根本没有交易,我会期待 OperationServiceImpl.update(..) 中的异常,因为那里已经需要它了。可以尝试将@Transactional移到接口方法OperationService.update(..)中。 而且 OperationServiceImpl.update(..) 不能从 OperationServiceImpl 内部调用。【参考方案2】:

找到了。我传递给事务管理器的实体管理器不是 AOP 安全的。因此,它在使用它执行查询时不会启动事务。我已经打开并管理了我自己的交易并且问题解决了。感谢回复

【讨论】:

以上是关于调用super的方法时出现JPA Transaction错误的主要内容,如果未能解决你的问题,请参考以下文章

尝试使用 Spring Data JPA 运行存储过程时出现“类型不能为空”异常

在具有双向连接的特定实体上运行 findById(Long id) Jpa 方法时出现“java.lang.***Error: null”

JPA 实体在实施物料清单概念时出现错误

使用jpa报No query defined for that name错误

运行 jar 时出现 Spring Boot 错误,但在 IDE 中工作正常(spring-boot-starter-data-jpa)

尝试使用 Spring JPA 从本地 Springboot 项目连接到 heroku-postgres 时出现 UnknownHostException