diff --git a/spring-jpa/pom.xml b/spring-jpa/pom.xml index 675f893133..0e55c9988f 100644 --- a/spring-jpa/pom.xml +++ b/spring-jpa/pom.xml @@ -53,6 +53,12 @@ compile + + + com.atomikos + transactions-jta + 3.9.3 + diff --git a/spring-jpa/src/main/java/org/baeldung/config/MultipleDBJPAConfig.java b/spring-jpa/src/main/java/org/baeldung/config/MultipleDBJPAConfig.java new file mode 100644 index 0000000000..fc0cb8fb8e --- /dev/null +++ b/spring-jpa/src/main/java/org/baeldung/config/MultipleDBJPAConfig.java @@ -0,0 +1,54 @@ +package org.baeldung.config; + +import javax.transaction.TransactionManager; +import javax.transaction.UserTransaction; + +import org.springframework.beans.factory.annotation.Autowired; +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.core.env.Environment; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.annotation.EnableTransactionManagement; +import org.springframework.transaction.jta.JtaTransactionManager; + +import com.atomikos.icatch.jta.UserTransactionImp; +import com.atomikos.icatch.jta.UserTransactionManager; + +@Configuration +@ComponentScan({ "org.baeldung.persistence.multiple" }) +@EnableTransactionManagement +public class MultipleDBJPAConfig { + @Autowired + private Environment env; + + public MultipleDBJPAConfig() { + super(); + } + + @Bean(name = "userTransaction") + public UserTransaction userTransaction() { + final UserTransactionImp userTransactionImp = new UserTransactionImp(); + return userTransactionImp; + } + + @Bean(name = "atomikosTransactionManager") + public TransactionManager atomikosTransactionManager() { + final UserTransactionManager userTransactionManager = new UserTransactionManager(); + MyJtaPlatform.transactionManager = userTransactionManager; + + return userTransactionManager; + } + + @Bean(name = "transactionManager") + @DependsOn({ "userTransaction", "atomikosTransactionManager" }) + public PlatformTransactionManager transactionManager() { + final UserTransaction userTransaction = userTransaction(); + + MyJtaPlatform.transaction = userTransaction; + + final TransactionManager atomikosTransactionManager = atomikosTransactionManager(); + return new JtaTransactionManager(userTransaction, atomikosTransactionManager); + } +} diff --git a/spring-jpa/src/main/java/org/baeldung/config/MyJtaPlatform.java b/spring-jpa/src/main/java/org/baeldung/config/MyJtaPlatform.java new file mode 100644 index 0000000000..2d00f782ad --- /dev/null +++ b/spring-jpa/src/main/java/org/baeldung/config/MyJtaPlatform.java @@ -0,0 +1,22 @@ +package org.baeldung.config; + +import javax.transaction.TransactionManager; +import javax.transaction.UserTransaction; + +import org.hibernate.engine.transaction.jta.platform.internal.AbstractJtaPlatform; + +public class MyJtaPlatform extends AbstractJtaPlatform { + + public static TransactionManager transactionManager; + public static UserTransaction transaction; + + @Override + protected TransactionManager locateTransactionManager() { + return transactionManager; + } + + @Override + protected UserTransaction locateUserTransaction() { + return transaction; + } +} diff --git a/spring-jpa/src/main/java/org/baeldung/config/ProductConfig.java b/spring-jpa/src/main/java/org/baeldung/config/ProductConfig.java new file mode 100644 index 0000000000..d5f582fc20 --- /dev/null +++ b/spring-jpa/src/main/java/org/baeldung/config/ProductConfig.java @@ -0,0 +1,59 @@ +package org.baeldung.config; + +import java.util.HashMap; + +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.context.annotation.PropertySource; +import org.springframework.core.env.Environment; +import org.springframework.data.jpa.repository.config.EnableJpaRepositories; +import org.springframework.jdbc.datasource.DriverManagerDataSource; +import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; +import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter; + +import com.google.common.base.Preconditions; + +@Configuration +@PropertySource({ "classpath:persistence-multiple-db.properties" }) +@EnableJpaRepositories(basePackages = "org.baeldung.persistence.multiple.dao.product", entityManagerFactoryRef = "productEntityManager", transactionManagerRef = "transactionManager") +public class ProductConfig { + @Autowired + private Environment env; + + public ProductConfig() { + super(); + } + + @Bean(name = "productEntityManager") + public LocalContainerEntityManagerFactoryBean productEntityManagerFactory() { + final LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean(); + em.setDataSource(productDataSource()); + em.setPackagesToScan(new String[] { "org.baeldung.persistence.multiple.model.product" }); + + final HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter(); + em.setJpaVendorAdapter(vendorAdapter); + final HashMap properties = new HashMap(); + properties.put("hibernate.transaction.jta.platform", MyJtaPlatform.class.getName()); + properties.put("javax.persistence.transactionType", "JTA"); + properties.put("hibernate.hbm2ddl.auto", env.getProperty("hibernate.hbm2ddl.auto")); + properties.put("hibernate.dialect", env.getProperty("hibernate.dialect")); + em.setJpaPropertyMap(properties); + + return em; + } + + @Bean + public DataSource productDataSource() { + final DriverManagerDataSource dataSource = new DriverManagerDataSource(); + dataSource.setDriverClassName(Preconditions.checkNotNull(env.getProperty("jdbc.driverClassName"))); + dataSource.setUrl(Preconditions.checkNotNull(env.getProperty("product.jdbc.url"))); + dataSource.setUsername(Preconditions.checkNotNull(env.getProperty("jdbc.user"))); + dataSource.setPassword(Preconditions.checkNotNull(env.getProperty("jdbc.pass"))); + + return dataSource; + } + +} diff --git a/spring-jpa/src/main/java/org/baeldung/config/UserConfig.java b/spring-jpa/src/main/java/org/baeldung/config/UserConfig.java new file mode 100644 index 0000000000..d7edcc7072 --- /dev/null +++ b/spring-jpa/src/main/java/org/baeldung/config/UserConfig.java @@ -0,0 +1,59 @@ +package org.baeldung.config; + +import java.util.HashMap; + +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.context.annotation.PropertySource; +import org.springframework.core.env.Environment; +import org.springframework.data.jpa.repository.config.EnableJpaRepositories; +import org.springframework.jdbc.datasource.DriverManagerDataSource; +import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; +import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter; + +import com.google.common.base.Preconditions; + +@Configuration +@PropertySource({ "classpath:persistence-multiple-db.properties" }) +@EnableJpaRepositories(basePackages = "org.baeldung.persistence.multiple.dao.user", entityManagerFactoryRef = "userEntityManager", transactionManagerRef = "transactionManager") +public class UserConfig { + @Autowired + private Environment env; + + public UserConfig() { + super(); + } + + @Bean(name = "userEntityManager") + public LocalContainerEntityManagerFactoryBean userEntityManagerFactory() { + final LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean(); + em.setDataSource(userDataSource()); + em.setPackagesToScan(new String[] { "org.baeldung.persistence.multiple.model.user" }); + + final HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter(); + em.setJpaVendorAdapter(vendorAdapter); + final HashMap properties = new HashMap(); + properties.put("hibernate.transaction.jta.platform", MyJtaPlatform.class.getName()); + properties.put("javax.persistence.transactionType", "JTA"); + properties.put("hibernate.hbm2ddl.auto", env.getProperty("hibernate.hbm2ddl.auto")); + properties.put("hibernate.dialect", env.getProperty("hibernate.dialect")); + em.setJpaPropertyMap(properties); + + return em; + } + + @Bean + public DataSource userDataSource() { + final DriverManagerDataSource dataSource = new DriverManagerDataSource(); + dataSource.setDriverClassName(Preconditions.checkNotNull(env.getProperty("jdbc.driverClassName"))); + dataSource.setUrl(Preconditions.checkNotNull(env.getProperty("user.jdbc.url"))); + dataSource.setUsername(Preconditions.checkNotNull(env.getProperty("jdbc.user"))); + dataSource.setPassword(Preconditions.checkNotNull(env.getProperty("jdbc.pass"))); + + return dataSource; + } + +} diff --git a/spring-jpa/src/main/java/org/baeldung/persistence/multiple/dao/product/ProductRepository.java b/spring-jpa/src/main/java/org/baeldung/persistence/multiple/dao/product/ProductRepository.java new file mode 100644 index 0000000000..bad0170a3a --- /dev/null +++ b/spring-jpa/src/main/java/org/baeldung/persistence/multiple/dao/product/ProductRepository.java @@ -0,0 +1,8 @@ +package org.baeldung.persistence.multiple.dao.product; + +import org.baeldung.persistence.multiple.model.product.Product; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface ProductRepository extends JpaRepository { + +} diff --git a/spring-jpa/src/main/java/org/baeldung/persistence/multiple/dao/user/UserRepository.java b/spring-jpa/src/main/java/org/baeldung/persistence/multiple/dao/user/UserRepository.java new file mode 100644 index 0000000000..e250a291bc --- /dev/null +++ b/spring-jpa/src/main/java/org/baeldung/persistence/multiple/dao/user/UserRepository.java @@ -0,0 +1,8 @@ +package org.baeldung.persistence.multiple.dao.user; + +import org.baeldung.persistence.multiple.model.user.User; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface UserRepository extends JpaRepository { + +} diff --git a/spring-jpa/src/main/java/org/baeldung/persistence/multiple/model/product/Product.java b/spring-jpa/src/main/java/org/baeldung/persistence/multiple/model/product/Product.java new file mode 100644 index 0000000000..3db96ed9dc --- /dev/null +++ b/spring-jpa/src/main/java/org/baeldung/persistence/multiple/model/product/Product.java @@ -0,0 +1,44 @@ +package org.baeldung.persistence.multiple.model.product; + +import javax.persistence.Entity; +import javax.persistence.Id; + +@Entity +public class Product { + + @Id + private int id; + + private String name; + + private double price; + + public Product() { + super(); + } + + public int getId() { + return id; + } + + public void setId(final int id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(final String name) { + this.name = name; + } + + public double getPrice() { + return price; + } + + public void setPrice(final double price) { + this.price = price; + } + +} diff --git a/spring-jpa/src/main/java/org/baeldung/persistence/multiple/model/user/User.java b/spring-jpa/src/main/java/org/baeldung/persistence/multiple/model/user/User.java new file mode 100644 index 0000000000..9cdc1fe311 --- /dev/null +++ b/spring-jpa/src/main/java/org/baeldung/persistence/multiple/model/user/User.java @@ -0,0 +1,57 @@ +package org.baeldung.persistence.multiple.model.user; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; + +@Entity +public class User { + + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + private int id; + + private String name; + + private String email; + + private int age; + + public User() { + super(); + } + + public int getId() { + return id; + } + + public void setId(final int id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(final String name) { + this.name = name; + } + + public String getEmail() { + return email; + } + + public void setEmail(final String email) { + this.email = email; + } + + public int getAge() { + return age; + } + + public void setAge(final int age) { + this.age = age; + } + +} \ No newline at end of file diff --git a/spring-jpa/src/test/java/org/baeldung/persistence/service/JPAMultipleDBTest.java b/spring-jpa/src/test/java/org/baeldung/persistence/service/JPAMultipleDBTest.java new file mode 100644 index 0000000000..43a28743f0 --- /dev/null +++ b/spring-jpa/src/test/java/org/baeldung/persistence/service/JPAMultipleDBTest.java @@ -0,0 +1,51 @@ +package org.baeldung.persistence.service; + +import static org.junit.Assert.assertNotNull; + +import org.baeldung.config.MultipleDBJPAConfig; +import org.baeldung.config.ProductConfig; +import org.baeldung.config.UserConfig; +import org.baeldung.persistence.multiple.dao.product.ProductRepository; +import org.baeldung.persistence.multiple.dao.user.UserRepository; +import org.baeldung.persistence.multiple.model.product.Product; +import org.baeldung.persistence.multiple.model.user.User; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.context.transaction.TransactionConfiguration; +import org.springframework.transaction.annotation.Transactional; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(classes = { MultipleDBJPAConfig.class, UserConfig.class, ProductConfig.class }) +@Transactional +@TransactionConfiguration(transactionManager = "transactionManager") +public class JPAMultipleDBTest { + @Autowired + private UserRepository userRepository; + + @Autowired + private ProductRepository productRepository; + + @Test + public void whenCreateUser_thenCreated() { + User user = new User(); + user.setName("John"); + user.setAge(20); + user = userRepository.save(user); + + assertNotNull(userRepository.findOne(user.getId())); + } + + @Test + public void whenCreateProduct_thenCreated() { + Product product = new Product(); + product.setName("Book"); + product.setId(2); + product.setPrice(20); + product = productRepository.save(product); + + assertNotNull(productRepository.findOne(product.getId())); + } +}