Spring JPA – Multiple Databases

本文介绍如何使用 Spring Data JPA 在一个项目中配置并使用多个数据库,包括定义实体类、创建仓库接口及配置数据源等步骤。

1. Overview

In this tutorial we’ll implement a simple Spring configuration for a Spring Data JPA system with multiple 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)
     private int id;
 
     private String name;
 
     @Column (unique = true , nullable = false )
     private String email;
 
     private int 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
     private int id;
 
     private String name;
 
     private double 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 extends JpaRepository<User, Integer> { }

And ProductRepository:

1
2
3
package org.baeldung.persistence.multiple.dao.product;
 
public interface ProductRepository extends JpaRepository<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 the User 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
     private Environment env;
     
     @Bean
     @Primary
     public LocalContainerEntityManagerFactoryBean userEntityManager() {
         LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
         em.setDataSource(userDataSource());
         em.setPackagesToScan( new String[] { "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);
 
         return em;
     }
 
     @Primary
     @Bean
     public DataSource 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" ));
 
         return dataSource;
     }
 
     @Primary
     @Bean
     public PlatformTransactionManager userTransactionManager() {
         JpaTransactionManager transactionManager = new JpaTransactionManager();
         transactionManager.setEntityManagerFactory(userEntityManager().getObject());
         return transactionManager;
     }
}

Notice how we’re using the userTransactionManager as our Primary TransactionManager – 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
     private Environment env;
 
     @Bean
     public LocalContainerEntityManagerFactoryBean productEntityManager() {
         LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
         em.setDataSource(productDataSource());
         em.setPackagesToScan( new String[] { "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);
 
         return em;
     }
 
     @Bean
     public DataSource 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" ));
 
         return dataSource;
     }
 
     @Bean
     public PlatformTransactionManager productTransactionManager() {
         JpaTransactionManager transactionManager = new JpaTransactionManager();
         transactionManager.setEntityManagerFactory(productEntityManager().getObject());
         return transactionManager;
     }
}

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
     private UserRepository userRepository;
 
     @Autowired
     private ProductRepository productRepository;
 
     @Test
     @Transactional ( "userTransactionManager" )
     public void 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" )
     public void 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" )
     public void 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.

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值