Search code examples
spring-bootspring-jdbcspring-transactions

Spring boot configuration for @Transactional for both JPA and spring-JDBC-templete


in my project, I am using both JPA and spring-jdbc-template & NamedParameterTemplate. I need to get transaction support for both.

So how to configure @Transactional for both JPA & spring-JDBC ?

Here are the 2 classes I used for configuring those.

Class number 1: PersistenceConfiguration This is the class that declares transaction-management should be enabled.

            @Configuration
        @EnableTransactionManagement
        @EnableJpaRepositories(basePackages = {"com.google.product.repository"},
                excludeFilters = @ComponentScan.Filter(type = FilterType.REGEX, pattern = "com.google.product.repository.mongoRepository.*.*Repository"))
        public class PersistenceConfiguration {

            @Autowired
            private DataSource dataSource;

            @Autowired
            private Properties entityManagerProperties;

            @Bean
            public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
                final LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
                em.setDataSource(dataSource);
                em.setPackagesToScan("com.google.product.model");
                final HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
                em.setJpaVendorAdapter(vendorAdapter);
                em.setJpaProperties(entityManagerProperties);
                return em;
            }

        }

Class number 2: ProdDatabaseConfiguration This is the class that declares beans releted toJDBC & JPA. for example primaryJdbcTemplate ,secondaryJdbcTemplate & entityManagerProperties.

@Configuration
    @PropertySource({"classpath:database-prod.properties"})
    @Profile("prod")
    public class ProdDatabaseConfiguration {

        private static final Logger LOG = LoggerFactory.getLogger(ProdDatabaseConfiguration.class);


        @Value("${jdbc.jndiName}")
        private String jndiName;


        @Value("${hibernate.dialect}")
        private String hibernateDialect;

        @Value("${hibernate.show_sql}")
        private String hibernateShowSql;

        @Value("${hibernate.cache.use_second_level_cache}")
        private String hibernateSecondLevelCache;

        @Value("${hibernate.cache.use_query_cache}")
        private String hibernateQueryCache;

        @Value("${jadira.usertype.databaseZone}")
        private String databaseZone;

        @Value("${jadira.usertype.javaZone}")
        private String javaZone;

        @Value("${mongo.jndiName}")
        private String mongoJndiName;

        @Bean
        public DataSource dataSource() {
            JndiDataSourceLookup jndiDataSourceLookup = new JndiDataSourceLookup();
            return jndiDataSourceLookup.getDataSource(jndiName);
        }

        @Bean(name = "entityManagerProperties")
        public Properties additionalProperties() {
            final Properties hibernateProperties = new Properties();
            hibernateProperties.setProperty("hibernate.hbm2ddl.auto", "none");
            hibernateProperties.setProperty("hibernate.dialect", hibernateDialect);
            hibernateProperties.setProperty("hibernate.show_sql", hibernateShowSql);
            hibernateProperties.setProperty("hibernate.cache.use_second_level_cache", hibernateSecondLevelCache);
            hibernateProperties.setProperty("hibernate.cache.use_query_cache", hibernateQueryCache);
            hibernateProperties.setProperty("jadira.usertype.databaseZone", databaseZone);
            hibernateProperties.setProperty("jadira.usertype.javaZone", javaZone);
            return hibernateProperties;
        }

        @Bean(name = "primaryJdbcTemplate")
        public JdbcTemplate primaryJdbcTemplate() {
            JndiDataSourceLookup jndiDataSourceLookup = new JndiDataSourceLookup();
            return new JdbcTemplate(jndiDataSourceLookup.getDataSource(jndiName));
        }

        @Bean(name = "secondaryJdbcTemplate")
        public NamedParameterJdbcTemplate secondaryJdbcTemplate() {
            JndiDataSourceLookup jndiDataSourceLookup = new JndiDataSourceLookup();
            return new NamedParameterJdbcTemplate(jndiDataSourceLookup.getDataSource(jndiName));
        }

Solution

  • Because you are only using one datasource you can remove all the configuration and just use the spring.datasource properties.

    Transaction will also work out of the box because you will have only this datasource.

    Read more about this topic in the official documentation:

    https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-sql