Spring boot + Hibernate + JPA没有事务性的EntityManager可用

时间:2015-06-29 23:41:08

标签: java spring hibernate jpa spring-boot

我正在使用Spring引导1.2.3.RELEASE版本,JPA超过hibernate。我遇到了以下异常

username='artur',aadasdd='artur12',

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

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]

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

由于

3 个答案:

答案 0 :(得分:13)

首先,我引用Spring-Data JPA Documentation来证明为什么delete方法适用于您的情况(我的意思是选项 2 )。

  

默认情况下,存储库实例上的CRUD方法是事务性的。对于   读取操作设置了事务配置readOnly标志   为true,所有其他人都配置了普通@Transactional,以便   默认事务配置适用。有关详细信息,请参阅JavaDoc   CrudRepository

delete方法实际上是CrudRepository的一种方法。您的存储库扩展JpaRepository扩展CrudRespository,因此它属于CrudRepository接口,根据上面的引用是事务性的。

如果您阅读Transactional Query Method部分,您会看到与 4 选项相同,您将了解如何为存储库的所有方法应用自定义事务行为。 此外,文档的示例61 显示了选项 3 的相同方案。

现在请记住,您不使用JDBC逻辑,在这种情况下,数据库会处理事务,但在基于ORM的框架内。 ORM框架需要事务才能触发对象缓存和数据库之间的同步。 因此,您必须了解并为执行ORM逻辑的方法提供事务上下文,例如deleteByCustomerId

默认情况下@Transactional(我的意思是没有任何参数)将传播模式设置为REQUIRED,将readOnly标志设置为false。当您调用在其中注释的方法时,如果不存在,则会初始化事务。这就是为什么@LucasSaldanha的解决方法(与示例使用Facade定义多个存储库调用的事务相同)和选项 4 有效。其他明智的做法是,如果没有交易,您会遇到选项 1 的抛出异常。

答案 1 :(得分:2)

好的,我发现了一种使其有效的方法。

只需在订单服务 deleteOrder 方法中添加@Transactional注释(org.springframework.transaction.annotation.Transactional)。

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

我真的不知道为什么第二个有效。我猜测,因为它是来自 CrudRepository 接口的直接方法,所以它知道如何以原子方式执行它。

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

再一次只是猜测。我会尝试联系一些弹簧开发人员,并可能会打开一个问题来验证这种行为。

希望它有所帮助!

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

答案 2 :(得分:1)

即使使用No transactional EntityManager available注释了search()方法,我仍然遇到@Transactional异常。

我遵循this tutorial,它描述了如何在Spring Boot中设置Hibernate搜索。

对我来说,问题在于我对hibernate-search-orm有不同的依赖性。对我没有任何问题的依赖是

compile("org.hibernate:hibernate-search-orm:5.7.0.Final")

将其添加到gradle构建文件中后,一切都按预期工作。

希望这对其他人也有帮助。