春季启动 + 休眠 + JPA 没有可用的事务性实体管理器

2022-09-03 06:14:16

我正在使用带有JPA的Spring Boot 1.2.3.RELEASE版本。我遇到以下异常

org.springframework.dao.InvalidDataAccessApiUsageException: No transactional EntityManager available; nested exception is javax.persistence.TransactionRequiredException: No transactional EntityManager available
at org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(EntityManagerFactoryUtils.java:410) ~[EntityManagerFactoryUtils.class:4.1.6.RELEASE]
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:223) ~[HibernateJpaDialect.class:4.1.6.RELEASE]
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:417) ~[AbstractEntityManagerFactoryBean.class:4.1.6.RELEASE]
at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:59) ~[ChainedPersistenceExceptionTranslator.class:4.1.6.RELEASE]
at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:213) ~[DataAccessUtils.class:4.1.6.RELEASE]
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:147) ~[PersistenceExceptionTranslationInterceptor.class:4.1.6.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) [ReflectiveMethodInvocation.class:4.1.6.RELEASE]
at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodIntercceptor.invoke(CrudMethodMetadataPostProcessor.java:122) ~[CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodIntercceptor.class:na]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) [ReflectiveMethodInvocation.class:4.1.6.RELEASE]
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92) [ExposeInvocationInterceptor.class:4.1.6.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) [ReflectiveMethodInvocation.class:4.1.6.RELEASE]
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207) [JdkDynamicAopProxy.class:4.1.6.RELEASE]
at com.sun.proxy.$Proxy110.deleteByCustomerId(Unknown Source) ~[na:na]

Caused by: javax.persistence.TransactionRequiredException: No transactional EntityManager available
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:275) ~[SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.class:4.1.6.RELEASE]
at com.sun.proxy.$Proxy102.remove(Unknown Source) ~[na:na]
at org.springframework.data.jpa.repository.query.JpaQueryExecution$DeleteExecution.doExecute(JpaQueryExecution.java:270) ~[JpaQueryExecution$DeleteExecution.class:na]
at org.springframework.data.jpa.repository.query.JpaQueryExecution.execute(JpaQueryExecution.java:74) ~[JpaQueryExecution.class:na]
at org.springframework.data.jpa.repository.query.AbstractJpaQuery.doExecute(AbstractJpaQuery.java:97) ~[AbstractJpaQuery.class:na]
at org.springframework.data.jpa.repository.query.AbstractJpaQuery.execute(AbstractJpaQuery.java:88) ~[AbstractJpaQuery.class:na]
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:395) ~[RepositoryFactorySupport$QueryExecutorMethodInterceptor.class:na]
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:373) ~[RepositoryFactorySupport$QueryExecutorMethodInterceptor.class:na]

以下是我的程序结构
配置类

@Configuration
@ComponentScan
@EnableAutoConfiguration
@EnableTransactionManagement
public class WSApplication {
    public static void main(final String[] args) {
        SpringApplication.run(WSApplication.class, args);
    }
}

@Entity
@Table(Orders)
public class Order {
    @id
    @GeneratedValue
    private long id;

    @Column(name = "customerId")
    private Long customerId;

    // getter & setter methods
    // equals & hashCode methods
}

public interface OrderRepository extends JpaRepository<Order, Long> {

    List<Order> findByCustomerId(Long customerId);

    // 4- @Transactional works fine
    void deleteByCustomerId(Long cusotmerId);

}

public class OrderService {

    @Autowired
    private OrderRepository repo;

    // 3- @Transactional works fine
    public void deleteOrder(long customerId){
        //1- throws exception
        repo.deleteByCustomerId(customerId); 

        //2- following works fine
        //repo.delete(repo.findByCustomerId(customerId).get(0));
    }

}

在上面的服务类代码中,任何人都可以指导我为什么2工作和1抛出异常。

谢谢


答案 1

首先,我引用了Spring-Data JPA文档,以证明为什么该方法在您的案例中有效(我的意思是选项2)。delete

默认情况下,存储库实例上的 CRUD 方法是事务性的。对于读取操作,事务配置标志设置为 true,所有其他标志都使用纯值进行配置,以便应用默认事务配置。有关详细信息,请参阅 CrudRepository 的 JavaDocreadOnly@Transactional

该方法实际上是 .您的存储库扩展了 扩展 ,因此它属于 CrudRepository 接口,并且根据上面的引用是事务性的。deleteCrudRepositoryJpaRepositoryCrudRespository

如果您阅读事务查询方法部分,您将看到它与选项 4 相同,并且您将知道如何为存储库的所有方法应用自定义事务行为。此外,文档的示例 61 显示了与选项 3 相同的方案。

现在请记住,您不是在使用JDBC逻辑,在这种情况下,数据库负责事务,而是在基于ORM的框架内。ORM 框架需要一个事务来触发对象缓存和数据库之间的同步。因此,您必须知道并为执行 ORM 逻辑的方法提供事务上下文,例如 .deleteByCustomerId

默认情况下(我的意思是没有任何参数)将传播模式设置为 false,并将 readOnly 标志设置为 false。调用 在其中带批注的方法时,如果不存在事务,则事务将初始化。这就是为什么@LucasSaldanha(与示例使用外观定义多个存储库调用的事务)和选项 4解决方法的工作原理。其他明智的做法是,如果没有事务,您将落入选项1的抛出异常中。@TransactionalREQUIRED


答案 2

好吧,我找到了一种使它工作的方法。

只需在 OrderService 的 deleteOrder 方法中放置一个注释 (org.springframework.transaction.annotation.Transactional)。@Transactional

@Transactional
public void deleteOrder(long customerId){
    repo.deleteByCustomerId(customerId);
}

我真的不知道为什么第二个有效。我猜想,因为它是CrudRepository接口中的直接方法,它知道如何原子地执行它。

前者是对 deleteByCustomerId 的调用。将处理此调用以找出具有指定 ID 的客户,然后将其删除。出于某种原因,它使用显式事务。

同样,这只是一个猜测。我会尝试联系一些spring开发人员,也许会提出一个问题来验证这种行为。

希望它有帮助!

参考资料: http://spring.io/guides/gs/managing-transactions/


推荐