Spring Boot休眠没有事务进行中 [英] Spring boot hibernate no transaction is in progress
问题描述
我正在使用Spring Boot,它使我成为实体经理.我决定测试从实体管理器获取会话工厂并将其用作示例.但是我遇到了下一个问题:javax.persistence.TransactionRequiredException: no transaction is in progress
I'm using spring boot and it perfectly makes me entity manager. And I decided to test getting session factory from the entity manager and to use it for an example. But I get the next problem:javax.persistence.TransactionRequiredException: no transaction is in progress
属性
spring.datasource.url= jdbc:postgresql://localhost:5432/ring
spring.datasource.username=postgres
spring.datasource.password=root
spring.jpa.show-sql = false
spring.jpa.properties.hibernate.format_sql=false
#Note: The last two properties on the code snippet above were added to suppress an annoying exception
# that occurs when JPA (Hibernate) tries to verify PostgreSQL CLOB feature.
spring.jpa.database-platform=org.hibernate.dialect.PostgreSQL9Dialect
spring.jpa.properties.hibernate.temp.use_jdbc_metadata_defaults = false
spring.jpa.properties.hibernate.current_session_context_class = org.springframework.orm.hibernate5.SpringSessionContext
服务等级
package kz.training.springrest.service;
import kz.training.springrest.entity.User;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceUnit;
@Service
public class UserService {
@PersistenceContext
private EntityManager entityManager;
@Transactional
public void insertUser(User user) {
SessionFactory sessionFactory = entityManager.unwrap(Session.class).getSessionFactory();
Session session = sessionFactory.getCurrentSession();
session.save(user);
}
}
跑步者
package kz.training.springrest.run;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@SpringBootApplication
@EntityScan("kz.training.springrest.entity")
@EnableTransactionManagement
@ComponentScan(basePackages="kz.training.springrest")
public class SpringrestApplication {
public static void main(String[] args) {
SpringApplication.run(SpringrestApplication.class, args);
}
}
您有任何解决方法的想法吗?
Do you have any ideas how to solve it?
推荐答案
我不太理解为什么您将服务方法变得如此不必要地复杂.您应该可以简单地通过这种方式完成操作
I don't quite understand why you're making your service method so unnecessarily complex. You should simply be able to do it this way
@Transactional
public void insertUser(User user) {
entityManager.persist( user );
}
如果有些地方需要访问本机Hibernate Session
,则可以像下面这样直接打开并使用Session
:
If there are points where you need access to the native Hibernate Session
you can simply unwrap and use the Session
directly like this:
@Transactional
public void doSomethingFancyWithASession() {
Session session = entityManager.unwrap( Session.class );
// use session as needed
}
这里的概念是Spring通过使用@PersistenceContext
批注为您提供了一个已经起作用的EntityManager
实例.该实例将在您正在执行Spring bean的当前线程中安全地使用.
The notion here is that Spring provides you an already functional EntityManager
instance by you using the @PersistenceContext
annotation. That instance will safely be usable by the current thread your spring bean is being executed within.
其次,通过使用@Transactional
,这将导致Spring的事务管理自动确保EntityManager
绑定到事务,无论是RESOURCE_LOCAL
还是JTA
事务都是基于您的环境配置的.
Secondly, by using @Transactional
, this causes Spring's transaction management to automatically make sure that the EntityManager
is bound to a transaction, whether that is a RESOURCE_LOCAL
or JTA
transaction is based on your environment configuration.
由于调用#getCurrentSession()
,您遇到了问题.
You're running into your problem because of the call to #getCurrentSession()
.
发生的事情是Spring创建了EntityManager
,然后在您对#getCurrentSession()
进行调用时在您的方法内部,您要求Hibernate创建第二个会话,该会话未绑定到由
What is happening is Spring creates the EntityManager
, then inside your method when you make the call to #getCurrentSession()
, you're asking Hibernate to create a second session that is not bound to the transaction started by your @Transactional
annotation. In short its essentially akin to the following:
EntityManager entityManager = entityManagerFactory.createEntityManager();
entityManager.getTransaction().begin();
Session aNewSession = entityManager.unwrap( Session.class )
.getFactory()
.getCurrentSession();
// at this point entityManager is scoped to a transaction
// aNewSession is not scoped to any transaction
// this also likely uses 2 connections to the database which is a waste
因此,按照我上面提到的范例进行操作,您就不再遇到问题了.如果您正确地允许Spring为您注入EntityManager
实例,则在Spring环境中永远不需要调用#getCurrentSession()
或#openSession()
.
So follow the paradigm I mention above and you should no longer run into the problem. You should never need to call #getCurrentSession()
or #openSession()
in a Spring environment if you're properly allowing Spring to inject your EntityManager
instance for you.
这篇关于Spring Boot休眠没有事务进行中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!