Skip to main content
 首页 » 编程设计

Spring DATA JPA 配置多数据源

2022年07月19日134daizhj

Spring DATA JPA 配置多数据源

本文我们通过一个简单示例说明如何在spring data jpa中配置多数据源。

示例实体

首先,我们创建两个简单实体,每个独立存储在不同数据库中。
第一个是User:

package org.dataz.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; 
}

第二个是Product:

package org.dataz.persistence.multiple.model.product; 
 
@Entity 
@Table(schema = "spring_jpa_product") 
public class Product {
    
 
    @Id 
    private int id; 
 
    private String name; 
 
    private double price; 
}

这连个实体被放在不同的包中,这对后续实现多数据源配置很重要。

JPA Repositories

下面看各自的 JPA Repository —— UserRepository:

package org.dataz.persistence.multiple.dao.user; 
 
public interface UserRepository 
  extends JpaRepository<User, Integer> {
    } 
 
ProductRepository: 
 
package org.dataz.persistence.multiple.dao.product; 
 
public interface ProductRepository 
  extends JpaRepository<Product, Integer> {
    }

同样,两个Repository在不同的独立包中。

使用javaConfig方式配置JPA

接下来进行实际Spring 配置。我们设置两个配置类,一个为User,另一个为Product:
每个配置类都需要定义下面内容:

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

首先开始User配置:

@Configuration 
@PropertySource({ "classpath:persistence-multiple-db.properties" }) 
@EnableJpaRepositories( 
    basePackages = "org.dataz.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.dataz.persistence.multiple.model.user" }); 
 
        HibernateJpaVendorAdapter vendorAdapter 
          = new HibernateJpaVendorAdapter(); 
        em.setJpaVendorAdapter(vendorAdapter); 
        HashMap<String, Object> properties = new HashMap<>(); 
        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; 
    } 
}

注意我们通过@Primary注解标记userTransactionManager为首选TransactionManager ,后续无论要隐式或显式地注入事务管理器时无需指定事务名称。

下面我们讨论ProductConfig,定义内容同上:

@Configuration 
@PropertySource({ "classpath:persistence-multiple-db.properties" }) 
@EnableJpaRepositories( 
    basePackages = "org.dataz.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.dataz.persistence.multiple.model.product" }); 
 
        HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter(); 
        em.setJpaVendorAdapter(vendorAdapter); 
        HashMap<String, Object> properties = new HashMap<>(); 
        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; 
    } 
}

测试配置

最后,我们测试我们的配置。通过创建每个实体的实例进行简单测试,确保每个实例可以在不同的库中进行保存。测试示例如下:

@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())); 
    } 
}

总结

文本通过实战方式配置spring data Jpa的多数据源实现。需要提醒注意两点:

  • 无论通过xml或javaConfig方式配置,配置信息中@EnableJpaRepositories需要一致,至少都需要指明下面三项:
@EnableJpaRepositories( 
    basePackages = "org.dataz.persistence.multiple.dao.user",  
    entityManagerFactoryRef = "userEntityManager",  
    transactionManagerRef = "userTransactionManager" 
)

当然还可以指定repositoryBaseClass等。
- 属性文件key
本文采用一个属性文件,定义两种数据源。如果使用两个属性文件,则key命名不能相同,避免后续覆盖前者,无法实现多数据源。


本文参考链接:https://blog.csdn.net/neweastsun/article/details/80750027