多數據源配置
創建一個Spring配置類,定義兩個DataSource用來讀取application.properties
中的不同配置。如下例子中,主數據源配置爲spring.datasource.primary
開頭的配置,第二數據源配置爲spring.datasource.secondary
開頭的配置。
public class DataSourceConfig { "primaryDataSource") (name = "primaryDataSource") ( "spring.datasource.primary") (prefix= public DataSource primaryDataSource() { return DataSourceBuilder.create().build(); } "secondaryDataSource") (name = "secondaryDataSource") ( "spring.datasource.secondary") (prefix= public DataSource secondaryDataSource() { return DataSourceBuilder.create().build(); } } |
對應的application.properties
配置如下:
spring.datasource.primary.url=jdbc:mysql://localhost:3306/test1 spring.datasource.primary.username=root spring.datasource.primary.password=root spring.datasource.primary.driver-class-name=com.mysql.jdbc.Driver spring.datasource.secondary.url=jdbc:mysql://localhost:3306/test2 spring.datasource.secondary.username=root spring.datasource.secondary.password=root spring.datasource.secondary.driver-class-name=com.mysql.jdbc.Driver |
JdbcTemplate支持
對JdbcTemplate的支持比較簡單,只需要爲其注入對應的datasource即可,如下例子,在創建JdbcTemplate的時候分別注入名爲primaryDataSource
和secondaryDataSource
的數據源來區分不同的JdbcTemplate。
"primaryJdbcTemplate") (name = public JdbcTemplate primaryJdbcTemplate( @Qualifier("primaryDataSource") DataSource dataSource) { return new JdbcTemplate(dataSource); } "secondaryJdbcTemplate") (name = public JdbcTemplate secondaryJdbcTemplate( @Qualifier("secondaryDataSource") DataSource dataSource) { return new JdbcTemplate(dataSource); } |
接下來通過測試用例來演示如何使用這兩個針對不同數據源的JdbcTemplate。
(SpringJUnit4ClassRunner.class) (Application.class)public class ApplicationTests { "primaryJdbcTemplate") ( protected JdbcTemplate jdbcTemplate1; "secondaryJdbcTemplate") ( protected JdbcTemplate jdbcTemplate2; public void setUp() { jdbcTemplate1.update("DELETE FROM USER "); jdbcTemplate2.update("DELETE FROM USER "); } public void test() throws Exception { // 往第一個數據源中插入兩條數據 jdbcTemplate1.update("insert into user(id,name,age) values(?, ?, ?)", 1, "aaa", 20); jdbcTemplate1.update("insert into user(id,name,age) values(?, ?, ?)", 2, "bbb", 30); // 往第二個數據源中插入一條數據,若插入的是第一個數據源,則會主鍵衝突報錯 jdbcTemplate2.update("insert into user(id,name,age) values(?, ?, ?)", 1, "aaa", 20); // 查一下第一個數據源中是否有兩條數據,驗證插入是否成功 Assert.assertEquals("2", jdbcTemplate1.queryForObject("select count(1) from user", String.class)); // 查一下第一個數據源中是否有兩條數據,驗證插入是否成功 Assert.assertEquals("1", jdbcTemplate2.queryForObject("select count(1) from user", String.class)); } } |
Spring-data-jpa支持
對於數據源的配置可以沿用上例中DataSourceConfig
的實現。
新增對第一數據源的JPA配置,注意兩處註釋的地方,用於指定數據源對應的Entity
實體和Repository
定義位置,用@Primary
區分主數據源。
( entityManagerFactoryRef="entityManagerFactoryPrimary", transactionManagerRef="transactionManagerPrimary", basePackages= { "com.didispace.domain.p" }) //設置Repository所在位置 public class PrimaryConfig { "primaryDataSource") ( private DataSource primaryDataSource; "entityManagerPrimary") (name = public EntityManager entityManager(EntityManagerFactoryBuilder builder) { return entityManagerFactoryPrimary(builder).getObject().createEntityManager(); } "entityManagerFactoryPrimary") (name = public LocalContainerEntityManagerFactoryBean entityManagerFactoryPrimary (EntityManagerFactoryBuilder builder) { return builder .dataSource(primaryDataSource) .properties(getVendorProperties(primaryDataSource)) .packages("com.didispace.domain.p") //設置實體類所在位置 .persistenceUnit("primaryPersistenceUnit") .build(); } private JpaProperties jpaProperties; private Map<String, String> getVendorProperties(DataSource dataSource) { return jpaProperties.getHibernateProperties(dataSource); } "transactionManagerPrimary") (name = public PlatformTransactionManager transactionManagerPrimary(EntityManagerFactoryBuilder builder) { return new JpaTransactionManager(entityManagerFactoryPrimary(builder).getObject()); } } |
新增對第二數據源的JPA配置,內容與第一數據源類似,具體如下:
( entityManagerFactoryRef="entityManagerFactorySecondary", transactionManagerRef="transactionManagerSecondary", basePackages= { "com.didispace.domain.s" }) //設置Repository所在位置 public class SecondaryConfig { "secondaryDataSource") ( private DataSource secondaryDataSource; "entityManagerSecondary") (name = public EntityManager entityManager(EntityManagerFactoryBuilder builder) { return entityManagerFactorySecondary(builder).getObject().createEntityManager(); } "entityManagerFactorySecondary") (name = public LocalContainerEntityManagerFactoryBean entityManagerFactorySecondary (EntityManagerFactoryBuilder builder) { return builder .dataSource(secondaryDataSource) .properties(getVendorProperties(secondaryDataSource)) .packages("com.didispace.domain.s") //設置實體類所在位置 .persistenceUnit("secondaryPersistenceUnit") .build(); } private JpaProperties jpaProperties; private Map<String, String> getVendorProperties(DataSource dataSource) { return jpaProperties.getHibernateProperties(dataSource); } "transactionManagerSecondary") (name = PlatformTransactionManager transactionManagerSecondary(EntityManagerFactoryBuilder builder) { return new JpaTransactionManager(entityManagerFactorySecondary(builder).getObject()); } } |
完成了以上配置之後,主數據源的實體和數據訪問對象位於:com.didispace.domain.p
,次數據源的實體和數據訪問接口位於:com.didispace.domain.s
。
分別在這兩個package下創建各自的實體和數據訪問接口
- 主數據源下,創建User實體和對應的Repository接口
public class User { private Long id; false) (nullable = private String name; false) (nullable = private Integer age; public User(){} public User(String name, Integer age) { this.name = name; this.age = age; } // 省略getter、setter } |
public interface UserRepository extends JpaRepository<User, Long> { } |
- 從數據源下,創建Message實體和對應的Repository接口
public class Message { private Long id; false) (nullable = private String name; false) (nullable = private String content; public Message(){} public Message(String name, String content) { this.name = name; this.content = content; } // 省略getter、setter } |
public interface MessageRepository extends JpaRepository<Message, Long> { } |
接下來通過測試用例來驗證使用這兩個針對不同數據源的配置進行數據操作。
(SpringJUnit4ClassRunner.class) (Application.class)public class ApplicationTests { private UserRepository userRepository; private MessageRepository messageRepository; public void test() throws Exception { userRepository.save(new User("aaa", 10)); userRepository.save(new User("bbb", 20)); userRepository.save(new User("ccc", 30)); userRepository.save(new User("ddd", 40)); userRepository.save(new User("eee", 50)); Assert.assertEquals(5, userRepository.findAll().size()); messageRepository.save(new Message("o1", "aaaaaaaaaa")); messageRepository.save(new Message("o2", "bbbbbbbbbb")); messageRepository.save(new Message("o3", "cccccccccc")); Assert.assertEquals(3, messageRepository.findAll().size()); } } |