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