簡體   English   中英

Spring Boot休眠沒有事務進行中

[英]Spring boot hibernate no transaction is in progress

我使用的是Spring Boot,它使我成為實體經理。 我決定測試從實體管理器獲取會話工廠並將其用作示例。 但是我遇到了下一個問題: 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);
    }
}

您有任何解決方法的想法嗎?

我不太明白為什么您要使服務方法變得如此不必要地復雜。 您應該只可以這樣做

@Transactional
public void insertUser(User user) {
  entityManager.persist( user );
}

如果有些地方需要訪問本機Hibernate Session ,則可以像下面這樣直接打開和使用Session

@Transactional
public void doSomethingFancyWithASession() {
  Session session = entityManager.unwrap( Session.class );
  // use session as needed
}

這里的概念是Spring通過使用@PersistenceContext批注為您提供了一個已經正常運行的EntityManager實例。 該實例將在您的spring bean正在其中執行的當前線程中安全地使用。

其次,通過使用@Transactional ,這將導致Spring的事務管理自動確保EntityManager綁定到事務,無論是RESOURCE_LOCAL還是JTA事務都是基於您的環境配置。

由於調用#getCurrentSession() ,您#getCurrentSession()問題。

發生的事情是Spring創建了EntityManager ,然后在您的方法內部調用#getCurrentSession() ,您要讓Hibernate創建第二個會話,該會話未綁定到由@Transactional注釋啟動的事務。 簡而言之,它基本上類似於以下內容:

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()

將Spring Boot應用程序部署到WebLogic Server時,我也遇到同樣的錯誤。 (即使我直接通過Eclipse運行它(或部署到Tomcat),它也可以正常工作)。

我通過將@EnableTransactionManagement添加到UserService解決了該問題。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM