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
Spring boot allows you to connect to multiple databases by configuring multiple data sources in a single spring boot application using hibernate and JPA. Spring boot enables repositories to connect to multiple databases using JPA from a single application.
So, to use multiple data sources, we need to declare multiple beans with different mappings within Spring's application context. The configuration for the data sources must look like this: spring: datasource: todos: url: ... username: ...
Until now with spring 4 and XML configuration I was able to only put the DB URL like: jdbc:mysql://180.179.57.114:3306/?zeroDateTimeBehavior=convertToNull and in the entity class specify the schema to use and thus able to connect to multiple schemas.
I think the CMTTransaction
in the stack trace is the clue: Hibernate thinks you are in a container. I also think it might work if you just remove the javax.persistence.transactionType=JTA
property.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With