Spring JPA – Multiple Databases

来源:互联网 发布:淘宝国新西兰能用吗 编辑:程序博客网 时间:2024/06/03 20:11

1. Overview

In this tutorial we’ll implement a simple Spring configuration for a Spring Data JPA system withmultiple databases.

2. The Entities

First – let’s create two simple entities – each living in a separate database.

Here is the first entity “User“:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package org.baeldung.persistence.multiple.model.user;
 
@Entity
@Table(schema ="spring_jpa_user")
public class User {
 
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    privateint id;
 
    privateString name;
 
    @Column(unique =true, nullable =false)
    privateString email;
 
    privateint age;
}

And the second entity – “Product“:

1
2
3
4
5
6
7
8
9
10
11
12
13
package org.baeldung.persistence.multiple.model.product;
 
@Entity
@Table(schema ="spring_jpa_product")
public class Product {
 
    @Id
    privateint id;
 
    privateString name;
 
    privatedouble price;
}

As you can see, the two entities are also placed in independent packages – this will be important as we move into the configuration.

3. The JPA Repositories

Next – let’s take a look at our two JPA repositories – UserRepository:

1
2
3
package org.baeldung.persistence.multiple.dao.user;
 
public interface UserRepository extendsJpaRepository<User, Integer> { }

And ProductRepository:

1
2
3
package org.baeldung.persistence.multiple.dao.product;
 
public interface ProductRepository extendsJpaRepository<Product, Integer> { }

Note, again how we created these two repositories in different packages.

4. Configure JPA with Java

Next – let’s get to the actual Spring configuration. We’ll start by setting up 2 configuration classes – one for theUser and the other for the Product.

In each one of this configuration classes, we’ll need to define the following:

  • User DataSource
  • User EntityManagerFactory (userEntityManager)
  • User TransactionManager (userTransactionManager)

Let’s start by looking the the User configuration:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
@Configuration
@PropertySource({"classpath:persistence-multiple-db.properties"})
@EnableJpaRepositories(
    basePackages ="org.baeldung.persistence.multiple.dao.user",
    entityManagerFactoryRef ="userEntityManager",
    transactionManagerRef ="userTransactionManager"
)
public class UserConfig {
    @Autowired
    privateEnvironment env;
     
    @Bean
    @Primary
    publicLocalContainerEntityManagerFactoryBean userEntityManager() {
        LocalContainerEntityManagerFactoryBean em =new LocalContainerEntityManagerFactoryBean();
        em.setDataSource(userDataSource());
        em.setPackagesToScan(newString[] { "org.baeldung.persistence.multiple.model.user"});
 
        HibernateJpaVendorAdapter vendorAdapter =new HibernateJpaVendorAdapter();
        em.setJpaVendorAdapter(vendorAdapter);
        HashMap<String, Object> properties =new HashMap<String, Object>();
        properties.put("hibernate.hbm2ddl.auto", env.getProperty("hibernate.hbm2ddl.auto"));
        properties.put("hibernate.dialect", env.getProperty("hibernate.dialect"));
        em.setJpaPropertyMap(properties);
 
        returnem;
    }
 
    @Primary
    @Bean
    publicDataSource userDataSource() {
        DriverManagerDataSource dataSource =new DriverManagerDataSource();
        dataSource.setDriverClassName(env.getProperty("jdbc.driverClassName"));
        dataSource.setUrl(env.getProperty("user.jdbc.url"));
        dataSource.setUsername(env.getProperty("jdbc.user"));
        dataSource.setPassword(env.getProperty("jdbc.pass"));
 
        returndataSource;
    }
 
    @Primary
    @Bean
    publicPlatformTransactionManager userTransactionManager() {
        JpaTransactionManager transactionManager =new JpaTransactionManager();
        transactionManager.setEntityManagerFactory(userEntityManager().getObject());
        returntransactionManager;
    }
}

Notice how we’re using the userTransactionManager as our PrimaryTransactionManager – by annotating the bean definition with @Primary. That’s helpful whenever we’re going to implicitly or explicitly inject the transaction manager without specifying which one by name.

Next, let’s discuss ProductConfig – where we define similar beans:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
@Configuration
@PropertySource({"classpath:persistence-multiple-db.properties"})
@EnableJpaRepositories(
    basePackages ="org.baeldung.persistence.multiple.dao.product",
    entityManagerFactoryRef ="productEntityManager",
    transactionManagerRef ="productTransactionManager"
)
public class ProductConfig {
    @Autowired
    privateEnvironment env;
 
    @Bean
    publicLocalContainerEntityManagerFactoryBean productEntityManager() {
        LocalContainerEntityManagerFactoryBean em =new LocalContainerEntityManagerFactoryBean();
        em.setDataSource(productDataSource());
        em.setPackagesToScan(newString[] { "org.baeldung.persistence.multiple.model.product"});
 
        HibernateJpaVendorAdapter vendorAdapter =new HibernateJpaVendorAdapter();
        em.setJpaVendorAdapter(vendorAdapter);
        HashMap<String, Object> properties =new HashMap<String, Object>();
        properties.put("hibernate.hbm2ddl.auto", env.getProperty("hibernate.hbm2ddl.auto"));
        properties.put("hibernate.dialect", env.getProperty("hibernate.dialect"));
        em.setJpaPropertyMap(properties);
 
        returnem;
    }
 
    @Bean
    publicDataSource productDataSource() {
        DriverManagerDataSource dataSource =new DriverManagerDataSource();
        dataSource.setDriverClassName(env.getProperty("jdbc.driverClassName"));
        dataSource.setUrl(env.getProperty("product.jdbc.url"));
        dataSource.setUsername(env.getProperty("jdbc.user"));
        dataSource.setPassword(env.getProperty("jdbc.pass"));
 
        returndataSource;
    }
 
    @Bean
    publicPlatformTransactionManager productTransactionManager() {
        JpaTransactionManager transactionManager =new JpaTransactionManager();
        transactionManager.setEntityManagerFactory(productEntityManager().getObject());
        returntransactionManager;
    }
}

5. Simple Test

Finally – let’s test our configurations.

We will try a simple test by creating an instance of each entity and make sure it is created – as in the following example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { UserConfig.class, ProductConfig.class})
@TransactionConfiguration
public class JPAMultipleDBTest {
    @Autowired
    privateUserRepository userRepository;
 
    @Autowired
    privateProductRepository productRepository;
 
    @Test
    @Transactional("userTransactionManager")
    publicvoid whenCreatingUser_thenCreated() {
        User user =new User();
        user.setName("John");
        user.setEmail("john@test.com");
        user.setAge(20);
        user = userRepository.save(user);
 
        assertNotNull(userRepository.findOne(user.getId()));
    }
 
    @Test
    @Transactional("userTransactionManager")
    publicvoid whenCreatingUsersWithSameEmail_thenRollback() {
        User user1 =new User();
        user1.setName("John");
        user1.setEmail("john@test.com");
        user1.setAge(20);
        user1 = userRepository.save(user1);
        assertNotNull(userRepository.findOne(user1.getId()));
 
        User user2 =new User();
        user2.setName("Tom");
        user2.setEmail("john@test.com");
        user2.setAge(10);
        try{
            user2 = userRepository.save(user2);
        }catch (DataIntegrityViolationException e) {
        }
 
        assertNull(userRepository.findOne(user2.getId()));
    }
 
    @Test
    @Transactional("productTransactionManager")
    publicvoid whenCreatingProduct_thenCreated() {
        Product product =new Product();
        product.setName("Book");
        product.setId(2);
        product.setPrice(20);
        product = productRepository.save(product);
 
        assertNotNull(productRepository.findOne(product.getId()));
    }
}

6. Conclusion

This article was a practical overview of how to configure your Spring Data JPA project to use multiple databases.

The full implementation of this article can be found in the github project – this is an Eclipse based project, so it should be easy to import and run as it is.

0 0