With this configuration (MainConfig.java):
import javax.transaction.TransactionManager; import javax.transaction.UserTransaction; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.DependsOn; import org.springframework.orm.jpa.JpaVendorAdapter; import org.springframework.orm.jpa.vendor.Database; import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.jta.JtaTransactionManager; import com.atomikos.icatch.jta.UserTransactionImp; import com.atomikos.icatch.jta.UserTransactionManager; @Configuration @ComponentScan public class MainConfig { @Bean public JpaVendorAdapter jpaVendorAdapter() { HibernateJpaVendorAdapter hibernateJpaVendorAdapter = new HibernateJpaVendorAdapter(); hibernateJpaVendorAdapter.setShowSql(true); hibernateJpaVendorAdapter.setGenerateDdl(true); hibernateJpaVendorAdapter.setDatabase(Database.MYSQL); return hibernateJpaVendorAdapter; } @Bean(name = "userTransaction") public UserTransaction userTransaction() throws Throwable { UserTransactionImp userTransactionImp = new UserTransactionImp(); userTransactionImp.setTransactionTimeout(10000); return userTransactionImp; } @Bean(name = "atomikosTransactionManager", initMethod = "init", destroyMethod = "close") public TransactionManager atomikosTransactionManager() throws Throwable { UserTransactionManager userTransactionManager = new UserTransactionManager(); userTransactionManager.setForceShutdown(false); return userTransactionManager; } @Bean(name = "transactionManager") @DependsOn({ "userTransaction", "atomikosTransactionManager" }) public PlatformTransactionManager transactionManager() throws Throwable { UserTransaction userTransaction = userTransaction(); TransactionManager atomikosTransactionManager = atomikosTransactionManager(); return new JtaTransactionManager(userTransaction, atomikosTransactionManager); } }
(CustomerConfig.java)
import java.util.Properties; import javax.sql.DataSource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.jpa.repository.config.EnableJpaRepositories; import org.springframework.orm.jpa.JpaVendorAdapter; import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; import org.springframework.transaction.annotation.EnableTransactionManagement; import com.atomikos.jdbc.AtomikosDataSourceBean; import com.mysql.jdbc.jdbc2.optional.MysqlXADataSource; @Configuration @EnableTransactionManagement @EnableJpaRepositories(basePackages = "com.at.mul.repository.customer", entityManagerFactoryRef = "customerEntityManager", transactionManagerRef = "transactionManager") public class CustomerConfig { @Autowired private JpaVendorAdapter jpaVendorAdapter; @Bean(name = "customerDataSource", initMethod = "init", destroyMethod = "close") public DataSource customerDataSource() { MysqlXADataSource mysqlXaDataSource = new MysqlXADataSource(); mysqlXaDataSource.setUrl("jdbc:mysql://localhost:3306/atomikos_1"); mysqlXaDataSource.setPinGlobalTxToPhysicalConnection(true); mysqlXaDataSource.setPassword("password"); mysqlXaDataSource.setUser("root"); mysqlXaDataSource.setPinGlobalTxToPhysicalConnection(true); AtomikosDataSourceBean xaDataSource = new AtomikosDataSourceBean(); xaDataSource.setXaDataSource(mysqlXaDataSource); xaDataSource.setUniqueResourceName("xads1"); return xaDataSource; } @Bean(name = "customerEntityManager") public LocalContainerEntityManagerFactoryBean customerEntityManager() throws Throwable { LocalContainerEntityManagerFactoryBean entityManager = new LocalContainerEntityManagerFactoryBean(); entityManager.setDataSource(customerDataSource()); entityManager.setJpaVendorAdapter(jpaVendorAdapter); entityManager.setPackagesToScan("com.at.mul.domain.customer"); entityManager.setPersistenceUnitName("customerPersistenceUnit"); Properties properties = new Properties(); properties.put("javax.persistence.transactionType", "JTA"); entityManager.setJpaProperties(properties); return entityManager; } }
(OrderConfig.java)
import java.util.Properties; import javax.sql.DataSource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.jpa.repository.config.EnableJpaRepositories; import org.springframework.orm.jpa.JpaVendorAdapter; import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; import org.springframework.transaction.annotation.EnableTransactionManagement; import com.atomikos.jdbc.AtomikosDataSourceBean; import com.mysql.jdbc.jdbc2.optional.MysqlXADataSource; @Configuration @EnableTransactionManagement @EnableJpaRepositories(basePackages = "com.at.mul.repository.order", entityManagerFactoryRef = "orderEntityManager", transactionManagerRef = "transactionManager") public class OrderConfig { @Autowired private JpaVendorAdapter jpaVendorAdapter; @Bean(name = "orderDataSource", initMethod = "init", destroyMethod = "close") public DataSource orderDataSource() { MysqlXADataSource mysqlXaDataSource = new MysqlXADataSource(); mysqlXaDataSource.setUrl("jdbc:mysql://localhost:3306/atomikos_2"); mysqlXaDataSource.setPinGlobalTxToPhysicalConnection(true); mysqlXaDataSource.setPassword("password"); mysqlXaDataSource.setUser("root"); mysqlXaDataSource.setPinGlobalTxToPhysicalConnection(true); AtomikosDataSourceBean xaDataSource = new AtomikosDataSourceBean(); xaDataSource.setXaDataSource(mysqlXaDataSource); xaDataSource.setUniqueResourceName("xads2"); return xaDataSource; } @Bean(name = "orderEntityManager") public LocalContainerEntityManagerFactoryBean orderEntityManager() throws Throwable { LocalContainerEntityManagerFactoryBean entityManager = new LocalContainerEntityManagerFactoryBean(); entityManager.setDataSource(orderDataSource()); entityManager.setJpaVendorAdapter(jpaVendorAdapter); entityManager.setPackagesToScan("com.at.mul.domain.order"); entityManager.setPersistenceUnitName("orderPersistenceUnit"); Properties properties = new Properties(); properties.put("javax.persistence.transactionType", "JTA"); entityManager.setJpaProperties(properties); return entityManager; } }
(CustomerRepository.java)
import org.springframework.data.jpa.repository.JpaRepository; import com.at.mul.domain.customer.Customer; public interface CustomerRepository extends JpaRepository<Customer, Integer> { }
(OrderRepository.java)
import org.springframework.data.jpa.repository.JpaRepository; import com.at.mul.domain.order.Order; public interface OrderRepository extends JpaRepository<Order, Integer> { }
I get a NullPointerException on when running this test:
import javax.transaction.Transactional; import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.SpringApplicationConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import com.at.mul.MainConfig; import com.at.mul.domain.customer.Customer; import com.at.mul.repository.customer.CustomerRepository; @RunWith(SpringJUnit4ClassRunner.class) @SpringApplicationConfiguration(classes = MainConfig.class) @Transactional public class CustomerRepositoryTest { @Autowired private CustomerRepository customerRepository; @Test public void testCustomerConfig() { } @Test public void save() { Customer c = new Customer(); c.setName("test-name"); c.setAge(30); Customer cust = customerRepository.save(c); Assert.assertNotNull(cust.getId()); } }
The null object seems to be the transactionManager, so I suppose it's not properly injected. Relevant part of the stacktrace is here:
java.lang.NullPointerException at org.hibernate.engine.transaction.internal.jta.JtaStatusHelper.getStatus(JtaStatusHelper.java:76) at org.hibernate.engine.transaction.internal.jta.JtaStatusHelper.isActive(JtaStatusHelper.java:118) at org.hibernate.engine.transaction.internal.jta.CMTTransaction.join(CMTTransaction.java:149) at org.hibernate.jpa.spi.AbstractEntityManagerImpl.joinTransaction(AbstractEntityManagerImpl.java:1602) at org.hibernate.jpa.spi.AbstractEntityManagerImpl.postInit(AbstractEntityManagerImpl.java:210) at org.hibernate.jpa.internal.EntityManagerImpl.<init>(EntityManagerImpl.java:91) at org.hibernate.jpa.internal.EntityManagerFactoryImpl.internalCreateEntityManager(EntityManagerFactoryImpl.java:345) at org.hibernate.jpa.internal.EntityManagerFactoryImpl.createEntityManager(EntityManagerFactoryImpl.java:313) at sun.reflect.GeneratedMethodAccessor10.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.invokeProxyMethod(AbstractEntityManagerFactoryBean.java:388) at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean$ManagedEntityManagerFactoryInvocationHandler.invoke(AbstractEntityManagerFactoryBean.java:541) at com.sun.proxy.$Proxy29.createEntityManager(Unknown Source) at org.springframework.orm.jpa.EntityManagerFactoryUtils.doGetTransactionalEntityManager(EntityManagerFactoryUtils.java:285) at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:227) at com.sun.proxy.$Proxy34.persist(Unknown Source) at org.springframework.data.jpa.repository.support.SimpleJpaRepository.save(SimpleJpaRepository.java:369)
The pom file is here:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.0.0.RC5</version> </parent> <groupId>com.at.mul</groupId> <artifactId>mul-at</artifactId> <version>1.0-SNAPSHOT</version> <packaging>jar</packaging> <name>mul-at</name> <url>http://maven.apache.org</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> <repositories> <repository> <id>spring-snapshots</id> <url>http://repo.spring.io/libs-snapshot</url> <snapshots> <enabled>true</enabled> </snapshots> </repository> </repositories> <pluginRepositories> <pluginRepository> <id>spring-snapshots</id> <url>http://repo.spring.io/libs-snapshot</url> <snapshots> <enabled>true</enabled> </snapshots> </pluginRepository> </pluginRepositories> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.12.4</version> </dependency> <dependency> <groupId>com.atomikos</groupId> <artifactId>transactions</artifactId> <version>3.9.3</version> </dependency> <dependency> <groupId>com.atomikos</groupId> <artifactId>transactions-jta</artifactId> <version>3.9.3</version> </dependency> <dependency> <groupId>com.atomikos</groupId> <artifactId>transactions-hibernate3</artifactId> <version>3.9.3</version> <exclusions> <exclusion> <artifactId>hibernate</artifactId> <groupId>org.hibernate</groupId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <scope>test</scope> </dependency> </dependencies> </project>
Full code is available on Github: https://github.com/fabiomaffioletti/mul-at I could not find any working example, and even after looking at the Spring blog article I cannot get it to work. Has anyone any hint?
Following the console log of spring boot for the customer connection:
2014-04-01 11:29:48.645 INFO 22368 --- [ main] c.atomikos.jdbc.AbstractDataSourceBean : AtomikosDataSoureBean 'xads1': init... 2014-04-01 11:29:48.645 WARN 22368 --- [ main] c.atomikos.jdbc.AbstractDataSourceBean : AtomikosDataSoureBean 'xads1': poolSize equals default - this may cause performance problems! 2014-04-01 11:29:48.672 INFO 22368 --- [ main] c.atomikos.jdbc.AtomikosDataSourceBean : AtomikosDataSoureBean 'xads1': initializing with [ xaDataSourceClassName=null, uniqueResourceName=xads1, maxPoolSize=1, minPoolSize=1, borrowConnectionTimeout=30, maxIdleTime=60, reapTimeout=0, maintenanceInterval=60, testQuery=null, xaProperties=[], loginTimeout=0, maxLifetime=0] 2014-04-01 11:29:48.809 INFO 22368 --- [ main] c.a.icatch.imp.thread.TaskManager : THREADS: using JDK thread pooling... 2014-04-01 11:29:48.837 INFO 22368 --- [ main] j.LocalContainerEntityManagerFactoryBean : Building JPA container EntityManagerFactory for persistence unit 'customerPersistenceUnit' 2014-04-01 11:29:48.857 INFO 22368 --- [ main] o.hibernate.jpa.internal.util.LogHelper : HHH000204: Processing PersistenceUnitInfo [ name: customerPersistenceUnit ...] 2014-04-01 11:29:48.919 INFO 22368 --- [ main] org.hibernate.Version : HHH000412: Hibernate Core {4.3.1.Final} 2014-04-01 11:29:48.920 INFO 22368 --- [ main] org.hibernate.cfg.Environment : HHH000206: hibernate.properties not found 2014-04-01 11:29:48.922 INFO 22368 --- [ main] org.hibernate.cfg.Environment : HHH000021: Bytecode provider name : javassist 2014-04-01 11:29:49.057 INFO 22368 --- [ main] o.hibernate.annotations.common.Version : HCANN000001: Hibernate Commons Annotations {4.0.4.Final} 2014-04-01 11:29:49.086 INFO 22368 --- [ main] c.atomikos.jdbc.AbstractDataSourceBean : AtomikosDataSoureBean 'xads1': getConnection ( null )... 2014-04-01 11:29:49.087 INFO 22368 --- [ main] c.atomikos.jdbc.AbstractDataSourceBean : AtomikosDataSoureBean 'xads1': init... 2014-04-01 11:29:49.145 WARN 22368 --- [ main] c.atomikos.jdbc.AtomikosConnectionProxy : atomikos connection proxy for com.mysql.jdbc.jdbc2.optional.JDBC4ConnectionWrapper@63f9f0f2: WARNING: transaction manager not running? 2014-04-01 11:29:49.145 INFO 22368 --- [ main] c.atomikos.jdbc.AtomikosConnectionProxy : atomikos connection proxy for com.mysql.jdbc.jdbc2.optional.JDBC4ConnectionWrapper@63f9f0f2: calling getMetaData... 2014-04-01 11:29:49.166 INFO 22368 --- [ main] org.hibernate.dialect.Dialect : HHH000400: Using dialect: org.hibernate.dialect.MySQLDialect 2014-04-01 11:29:49.172 WARN 22368 --- [ main] c.atomikos.jdbc.AtomikosConnectionProxy : atomikos connection proxy for com.mysql.jdbc.jdbc2.optional.JDBC4ConnectionWrapper@63f9f0f2: WARNING: transaction manager not running? 2014-04-01 11:29:49.172 INFO 22368 --- [ main] c.atomikos.jdbc.AtomikosConnectionProxy : atomikos connection proxy for com.mysql.jdbc.jdbc2.optional.JDBC4ConnectionWrapper@63f9f0f2: calling getCatalog... 2014-04-01 11:29:49.174 WARN 22368 --- [ main] c.atomikos.jdbc.AtomikosConnectionProxy : atomikos connection proxy for com.mysql.jdbc.jdbc2.optional.JDBC4ConnectionWrapper@63f9f0f2: WARNING: transaction manager not running? 2014-04-01 11:29:49.175 INFO 22368 --- [ main] c.atomikos.jdbc.AtomikosConnectionProxy : atomikos connection proxy for com.mysql.jdbc.jdbc2.optional.JDBC4ConnectionWrapper@63f9f0f2: calling getMetaData... 2014-04-01 11:29:49.175 WARN 22368 --- [ main] c.atomikos.jdbc.AtomikosConnectionProxy : atomikos connection proxy for com.mysql.jdbc.jdbc2.optional.JDBC4ConnectionWrapper@63f9f0f2: WARNING: transaction manager not running? 2014-04-01 11:29:49.175 INFO 22368 --- [ main] c.atomikos.jdbc.AtomikosConnectionProxy : atomikos connection proxy for com.mysql.jdbc.jdbc2.optional.JDBC4ConnectionWrapper@63f9f0f2: calling createClob... 2014-04-01 11:29:49.177 WARN 22368 --- [ main] c.atomikos.jdbc.AtomikosConnectionProxy : atomikos connection proxy for com.mysql.jdbc.jdbc2.optional.JDBC4ConnectionWrapper@63f9f0f2: WARNING: transaction manager not running? 2014-04-01 11:29:49.177 INFO 22368 --- [ main] c.atomikos.jdbc.AtomikosConnectionProxy : atomikos connection proxy for com.mysql.jdbc.jdbc2.optional.JDBC4ConnectionWrapper@63f9f0f2: close()... 2014-04-01 11:29:49.258 INFO 22368 --- [ main] o.h.h.i.ast.ASTQueryTranslatorFactory : HHH000397: Using ASTQueryTranslatorFactory 2014-04-01 11:29:49.428 INFO 22368 --- [ main] org.hibernate.tool.hbm2ddl.SchemaUpdate : HHH000228: Running hbm2ddl schema update 2014-04-01 11:29:49.428 INFO 22368 --- [ main] org.hibernate.tool.hbm2ddl.SchemaUpdate : HHH000102: Fetching database metadata 2014-04-01 11:29:49.428 INFO 22368 --- [ main] c.atomikos.jdbc.AbstractDataSourceBean : AtomikosDataSoureBean 'xads1': getConnection ( null )... 2014-04-01 11:29:49.428 INFO 22368 --- [ main] c.atomikos.jdbc.AbstractDataSourceBean : AtomikosDataSoureBean 'xads1': init... 2014-04-01 11:29:49.428 WARN 22368 --- [ main] c.atomikos.jdbc.AtomikosConnectionProxy : atomikos connection proxy for com.mysql.jdbc.jdbc2.optional.JDBC4ConnectionWrapper@63f9f0f2: WARNING: transaction manager not running? 2014-04-01 11:29:49.428 INFO 22368 --- [ main] c.atomikos.jdbc.AtomikosConnectionProxy : atomikos connection proxy for com.mysql.jdbc.jdbc2.optional.JDBC4ConnectionWrapper@63f9f0f2: calling getAutoCommit... 2014-04-01 11:29:49.429 WARN 22368 --- [ main] c.atomikos.jdbc.AtomikosConnectionProxy : atomikos connection proxy for com.mysql.jdbc.jdbc2.optional.JDBC4ConnectionWrapper@63f9f0f2: WARNING: transaction manager not running? 2014-04-01 11:29:49.429 INFO 22368 --- [ main] c.atomikos.jdbc.AtomikosConnectionProxy : atomikos connection proxy for com.mysql.jdbc.jdbc2.optional.JDBC4ConnectionWrapper@63f9f0f2: calling getMetaData... 2014-04-01 11:29:49.429 WARN 22368 --- [ main] c.atomikos.jdbc.AtomikosConnectionProxy : atomikos connection proxy for com.mysql.jdbc.jdbc2.optional.JDBC4ConnectionWrapper@63f9f0f2: WARNING: transaction manager not running? 2014-04-01 11:29:49.430 WARN 22368 --- [ main] c.atomikos.jdbc.AtomikosConnectionProxy : atomikos connection proxy for com.mysql.jdbc.jdbc2.optional.JDBC4ConnectionWrapper@63f9f0f2: WARNING: transaction manager not running? 2014-04-01 11:29:49.430 INFO 22368 --- [ main] c.atomikos.jdbc.AtomikosConnectionProxy : atomikos connection proxy for com.mysql.jdbc.jdbc2.optional.JDBC4ConnectionWrapper@63f9f0f2: calling createStatement... 2014-04-01 11:29:49.431 INFO 22368 --- [ main] org.hibernate.tool.hbm2ddl.SchemaUpdate : HHH000396: Updating schema 2014-04-01 11:29:49.446 INFO 22368 --- [ main] o.hibernate.tool.hbm2ddl.TableMetadata : HHH000261: Table found: atomikos_1.customer 2014-04-01 11:29:49.446 INFO 22368 --- [ main] o.hibernate.tool.hbm2ddl.TableMetadata : HHH000037: Columns: [id, age, name] 2014-04-01 11:29:49.446 INFO 22368 --- [ main] o.hibernate.tool.hbm2ddl.TableMetadata : HHH000108: Foreign keys: [] 2014-04-01 11:29:49.446 INFO 22368 --- [ main] o.hibernate.tool.hbm2ddl.TableMetadata : HHH000126: Indexes: [primary] 2014-04-01 11:29:49.447 INFO 22368 --- [ main] org.hibernate.tool.hbm2ddl.SchemaUpdate : HHH000232: Schema update complete