Spring boot hibernate транзакция не выполняется - PullRequest
0 голосов
/ 01 июня 2018

Я использую весеннюю загрузку, и она отлично делает меня менеджером сущностей.И я решил проверить получение фабрики сессий от менеджера сущностей и использовать его в качестве примера.Но я получаю следующую проблему: 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);
    }
}

У вас естьесть идеи как это решить?

Ответы [ 2 ]

0 голосов
/ 16 февраля 2019

У меня та же ошибка при развертывании моего приложения весенней загрузки на сервере WebLogic.(Даже работает нормально, если я запускаю его напрямую через Eclipse (или развертываю в Tomcat)).

Я решил проблему, добавив @EnableTransactionManagement в UserService.

0 голосов
/ 02 июня 2018

Я не совсем понимаю, почему вы так усложняете свой метод обслуживания.Вы просто должны быть в состоянии сделать это следующим образом

@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 предоставляет вам уже работающий экземпляр EntityManager, используя аннотацию @PersistenceContext.Этот экземпляр будет безопасно использоваться текущим потоком, внутри которого выполняется ваш bean-компонент.

Во-вторых, при использовании @Transactional это заставляет управление транзакциями Spring автоматически проверять, что EntityManager привязан ктранзакция, будь то транзакция RESOURCE_LOCAL или JTA, основана на конфигурации вашей среды.

Вы столкнулись с проблемой из-за вызова #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

Так что следуйте парадигме, которую я упоминал выше, и вам больше не придется сталкиваться с проблемой.Вам никогда не нужно вызывать #getCurrentSession() или #openSession() в среде Spring, если вы правильно разрешаете Spring вводить ваш экземпляр EntityManager для вас.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...