SpringBoot + Hibernate JPA Нет EntityManager с действительной транзакцией в слое @Service - PullRequest
1 голос
/ 29 февраля 2020

Я сам настраиваю приложение Spring Boot для работы с двумя базами данных (две транзакции одинаковые). MariaDB и MongoDB. А в @Repository, где у меня @Autowired с @PersistenceContext, аннотация @Transactional работает с должным образом TransactionManager. Но для меня самым полезным является наличие @Transacional на слое @Services. Но когда я это сделал, у меня возникла проблема с

No EntityManager with actual transaction available for current thread

Это конфигурация для @Repository и для JpaRepository (я буду писать двухстороннюю абстракцию для расширения моих знаний :))

    package com.kamil.serwis.config;


@Configuration
@EnableJpaRepositories(entityManagerFactoryRef = "entityManagerFactoryMySQL",
        basePackages = "com.kamil.serwis.repository",
        transactionManagerRef = "MySQLTransactionManager")
@EnableTransactionManagement
@ComponentScan(basePackages = {"com.kamil.serwis.repository.dao.SQL"})
public class HibernateConfiguration {

    private final String URLDatabase = "jdbc:mariadb://localhost:3306/SerwisDB";
    private final String User = "test";
    private final String Password = "password";
    private final String SQLDatabase = "org.mariadb.jdbc.Driver";


    @Bean(name ="entityManagerFactoryMySQL")
    @Primary
    LocalContainerEntityManagerFactoryBean entityManagerFactory() {
        LocalContainerEntityManagerFactoryBean emf =
                new LocalContainerEntityManagerFactoryBean();
        emf.setPackagesToScan("com.kamil.serwis.model.SQL");
        emf.setDataSource(createDataSource());
        emf.setJpaVendorAdapter(createJpaVendorAdapter());
        emf.setJpaProperties(createHibernateProperties());
        emf.setPersistenceUnitName("MySQLPersistence");
//        emf.afterPropertiesSet();
        System.out.println("Data source do bazy" + emf.getDataSource().toString() + " " +emf.getPersistenceUnitName());
        return emf;
    }
    @Primary
    private DataSource createDataSource() {
        DataSource dataSource= DataSourceBuilder.create()
                .url(this.URLDatabase)
                .username(User)
                .password(Password)
                .driverClassName(SQLDatabase)
                .build();
        return dataSource;
    }
    @Primary
    private JpaVendorAdapter createJpaVendorAdapter() {
        return new HibernateJpaVendorAdapter();
    }
    @Primary
    private Properties createHibernateProperties() {
        Properties properties = new Properties();
        properties.setProperty("hibernate.hbm2ddl.auto", "create");
        properties.setProperty(
                "hibernate.dialect", "org.hibernate.dialect.MySQL55Dialect");
        properties.setProperty("hibernate.show_sql","true");
        /*properties.setProperty("com.mysql.cj.jdbc.Driver","");*/
        return properties;
    }

    @Bean(name = "MySQLTransactionManager")
    @Primary
    PlatformTransactionManager transactionManager(@Qualifier("entityManagerFactoryMySQL") EntityManagerFactory emf) {
        return new JpaTransactionManager(emf);
    }

}

И в @Service у меня проблема с «Нет EntityManager с реальной транзакцией ...» Я думаю, что должен сказать SpringBoot о «Использовать эту транзакцию в методе», но мой SpringBoot не видит TransactionManager в слое @Service да? Потому что в @Repository все нормально, когда я добавляю @ Transactional.

Как это настроить? Не могли бы вы помочь мне с этим?

И простой @repository, который хорошо работает с @transactional, но я предпочитаю @transactional на уровне сервиса (но теперь он не работает для меня).

@ Пример репозитория:

@Repository
public class UserRepository {

    @PersistenceContext(name = "MySQLPersistence")
    @Autowired
    private EntityManager entityManager;


    public User addUserToDB(User newUser){
        entityManager.persist(newUser);
        return newUser;
    }

    public User findUserByName(String userName){
        User user = (User)entityManager.createQuery( "select u from User u").getResultStream().findFirst().get();
        return user;
    }

    public boolean deleteUser(User userToDelete){
        entityManager.remove(userToDelete);
        return entityManager.find(User.class,userToDelete.getId()).equals(userToDelete);
    }
}

РЕДАКТИРОВАТЬ Я пытался @transactional для контекста jpa и Spring

    import org.springframework.stereotype.Service;
    import org.springframework.transaction.annotation.Transactional;

    import javax.annotation.PostConstruct;
    import javax.transaction.TransactionManager;

    @Service
    public class UserService {

        private UserRepository userRepository;

        @Autowired
        public UserService(UserRepository userRepository){
            this.userRepository = userRepository;
        }

        @Transactional(transactionManager = "entityManagerFactoryMySQL")
        //@javax.transaction.Transactional
        @PostConstruct
        public void createUser(){
            User newUser = new User("test");
            User usersaved = userRepository.addUserToDB(newUser);
        }
    }

Ответы [ 2 ]

0 голосов
/ 03 марта 2020

Хорошо. Проблема решена. Что случилось? Если я удалил @PostConstruct, он работает сейчас. Но я могу прочитать в документации, почему @PostConstruct не работает с @Transactional? Может быть, некоторые условия или конфигурации для этого типа? Потому что, если я хотел бы иметь транзакцию с базой данных после запуска приложения? Как это возможно? Только с @PostConstruct?

Спасибо, что уделили мне время на мою проблему:)

0 голосов
/ 29 февраля 2020

Обновите уровень обслуживания до этого:

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;

@Service
public class UserService {

    private UserRepository userRepository;

    @Autowired
    public UserService(UserRepository userRepository){
        this.userRepository = userRepository;
    }

    @Transactional("MySQLTransactionManager")
    @PostConstruct
    public void createUser(){
        User newUser = new User("test");
        User usersaved = userRepository.addUserToDB(newUser);
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...