serhii
serhii

Reputation: 1177

Spring TransactionRequiredException exception

Here is my Repository configuration:

@Configuration
public class RepositoryConfing {
    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean(DataSource dataSource, JpaVendorAdapter jpaVendorAdapter){
        LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
        entityManagerFactoryBean.setDataSource(dataSource);
        entityManagerFactoryBean.setJpaVendorAdapter(jpaVendorAdapter);
        entityManagerFactoryBean.setPackagesToScan("com.imdb.model");
        return entityManagerFactoryBean;
    }

    @Bean
    public BasicDataSource dataSource(){
        BasicDataSource ds = new BasicDataSource();
        ds.setDriverClassName("org.postgresql.Driver");
        ds.setUrl("jdbc:postgresql://localhost:5432/imdb");
        ds.setUsername("***");
        ds.setPassword("***");
        ds.setInitialSize(5);
        return ds;
    }

    @Bean
    public JpaVendorAdapter jpaVendorAdapter(){
        HibernateJpaVendorAdapter adapter = new HibernateJpaVendorAdapter();
        adapter.setDatabase(Database.POSTGRESQL);
        adapter.setShowSql(true);
        adapter.setGenerateDdl(false);
        adapter.setDatabasePlatform("org.hibernate.dialect.PostgreSQLDialect");
        return adapter;
    }
}

When I call merge method, I get an exception: javax.persistence.TransactionRequiredException: No EntityManager with actual transaction available for current thread - cannot reliably process 'merge' call

May be my RepositoryConfig is lacking of some additional configurations?

EDIT: My new Repository configuration:

@Configuration
@EnableTransactionManagement
public class RepositoryConfing {
    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean(DataSource dataSource, JpaVendorAdapter jpaVendorAdapter){
        LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
        entityManagerFactoryBean.setDataSource(dataSource);
        entityManagerFactoryBean.setJpaVendorAdapter(jpaVendorAdapter);
        entityManagerFactoryBean.setPackagesToScan("com.imdb.model");
        return entityManagerFactoryBean;
    }

    @Bean
    public BasicDataSource dataSource(){
        BasicDataSource ds = new BasicDataSource();
        ds.setDriverClassName("org.postgresql.Driver");
        ds.setUrl("jdbc:postgresql://localhost:5432/imdb");
        ds.setUsername("***");
        ds.setPassword("***");
        ds.setInitialSize(5);
        return ds;
    }

    @Bean
    public JpaVendorAdapter jpaVendorAdapter(){
        HibernateJpaVendorAdapter adapter = new HibernateJpaVendorAdapter();
        adapter.setDatabase(Database.POSTGRESQL);
        adapter.setShowSql(true);
        adapter.setGenerateDdl(false);
        adapter.setDatabasePlatform("org.hibernate.dialect.PostgreSQLDialect");
        return adapter;
    }

    @Bean
    public PlatformTransactionManager txManager() {
        return new DataSourceTransactionManager(dataSource());
    }
}

Now it fails with StackOverflow. May be DataSourceTransactionManager is not suit for JPA?

Upvotes: 1

Views: 10797

Answers (1)

Alexandre Jacob
Alexandre Jacob

Reputation: 3041

@Bean
public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
    return new JpaTransactionManager(entityManagerFactory);
}
  • Your txManager method should be renamed to transactionManager.
  • You need to have a JpaTransactionManager instead of a DataSourceTransactionManager

EDIT

In order to have fully functional transaction with JPA you need to :

  • Use @EnableTransactionManagement on your configuration file
  • Declare an EntityManagerFactoryBean
  • Declare a JpaTransactionManager (the bean must be named transactionManager) created with your previously declared EntityManagerFactoryBean
  • Inject (with @PersistenceContext or @Autowired) an EntityManager in your @Repository (which must be a spring bean)
  • Call your repository from a @Service and use a public method anotated with @Transactional

Of course this is simplified and I assume you are using java config, annotations, and autocomponent scanning.

Upvotes: 8

Related Questions