Spring boot + Hibernate + JPA没有事务性的EntityManager可用
我使用Spring引导1.2.3.RELEASE版本与JPA over hibernate。 我遇到以下exception
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 { List 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个抛出exception。
谢谢
首先,我引用Spring-Data JPA文档来certificate为什么delete
方法适用于你的情况(我的意思是选项2 )。
默认情况下,存储库实例上的CRUD方法是事务性的。 对于读取操作,事务配置
readOnly
标志设置为true,所有其他配置使用普通@Transactional
以便应用默认事务配置。 有关详细信息,请参阅CrudRepository的JavaDoc
delete
方法实际上是CrudRepository
一个方法。 您的存储库扩展了JpaRepository
,它扩展了CrudRespository
,因此它属于CrudRepository接口,根据上面的引用是事务性的。
如果您阅读了事务性查询方法部分,您将看到与选项4相同的部分,您将知道如何为存储库的所有方法应用自定义事务行为。 此外,文档的示例61显示了与选项3相同的方案。
现在请记住,您没有使用JDBC逻辑,在这种情况下,数据库会处理事务,但在基于ORM的框架内。 ORM框架需要事务才能触发对象缓存和数据库之间的同步。 因此,您必须了解并为执行ORM逻辑(如deleteByCustomerId
方法提供事务上下文。
默认情况下@Transactional
(我的意思是没有任何参数)将传播模式设置为REQUIRED
,将readOnly标志设置为false。 当您调用在其中注释的方法时,如果不存在任何一个事务,则会初始化事务。 这就是为什么@LucasSaldanha的解决方法 (与使用Facade定义多个存储库调用的事务的示例相同)和选项4的工作原理。 另外,没有事务,你会陷入选项1的抛出exception中。
好的,我发现了一种使其有效的方法。
只需在OrderService的deleteOrder方法中添加@Transactional
注释(org.springframework.transaction.annotation.Transactional) 即可 。
@Transactional public void deleteOrder(long customerId){ repo.deleteByCustomerId(customerId); }
我真的不知道为什么第二个有效。 我猜测,因为它是来自CrudRepository接口的直接方法,所以它知道如何以primefaces方式执行它。
前一个是对deleteByCustomerId的调用。 将处理此调用以找出具有指定标识的客户,然后将其删除。 由于某种原因,它使用了显式事务。
再一次,这只是一个猜测。 我将尝试联系一些弹簧开发人员,并可能会打开一个问题来validation此行为。
希望能帮助到你!
参考: http : //spring.io/guides/gs/managing-transactions/
即使用@Transactional
注释了我的search()
方法,我仍然得到No transactional EntityManager available
exception。
我按照本教程描述了如何在Spring Boot中设置Hibernate搜索。
对我来说问题是我对hibernate-search-orm
有不同的依赖。 对我没有任何问题的依赖是
compile("org.hibernate:hibernate-search-orm:5.7.0.Final")
将此添加到gradle构建文件后,一切都按预期工作。
希望这也有助于其他人。
- 如何在hibernate上指定Double的精度?
- 使用Hibernate映射FunctionalJava选项
- Hibernate @Proxy(lazy = false)注释有什么作用?
- Hibernate单向父/子关系 – delete()对子表而不是删除执行更新
- 理解hibernate中的session.get vs session.load方法
- Spring Data JPA:嵌套实体的批量插入
- Hibernate Criteria Api是否完全防止SQL注入
- 使用Spring进行Hibernate二级缓存
- Hibernate NoCacheRegionFactoryAvailableException