I am configuring by myself Spring Boot application to run with two databases (two transactionManager same). MariaDB and MongoDB. And in @Repository where I have @Autowired with @PersistenceContext, the annotation @Transactional is working with properly TransactionManager. But for me the most useful is having @Transacional on the @Services layer. But when I have done this, I have a problem with
No EntityManager with actual transaction available for current thread
This is the configuration for @Repository and for JpaRepository (I will be coding on two way abstraction for extend my knowledge :) )
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);
}
}
And in the @Service I have a problem with "No EntityManager with actual transaction ..." I think I have to say SpringBoot about "Use this Transaction on the method" but my SpringBoot doesn't see TransactionManager in @Service layer yes? Because of in @Repository is everything ok when I add @Transactional.
How to configure that? Could you help me with that?
And simple @repository which is working well with @transactional, but I prefer @transactional in service layer (but now it doesn't work for me).
@Repository example:
@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);
}
}
EDIT I tried @transactional for jpa and Spring context
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);
}
}
Update the service layer to this :
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);
}
}
Ok. The problem is solved. What was wrong? If I removed @PostConstruct it is working now. But I can read on the documentation why @PostConstruct is not working with @Transactional ? Maybe is some of condition or configuration for that type? Because If I would like to have a transaction with database after Application was started? How is it possible? Only with @PostConstruct?
Thanks for afford your time for my problem :)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.