springboot【10】数据访问之多数据源配置使用
2017-08-07 10:10
495 查看
之前在介绍使用JdbcTemplate和Spring-data-jpa时,都使用了单数据源。在单数据源的情况下,Spring Boot的配置非常简单,只需要在
创建一个Spring配置类,定义两个DataSource用来读取
接下来通过测试用例来演示如何使用这两个针对不同数据源的JdbcTemplate。
新增对第一数据源的JPA配置,注意两处注释的地方,用于指定数据源对应的
PrimaryConfig.java:
新增对第二数据源的JPA配置,内容与第一数据源类似,具体如下:
SecondConfig.java:
完成了以上配置之后,主数据源的实体和数据访问对象位于:
分别在这两个package下创建各自的实体和数据访问接口
主数据源下,创建User实体和对应的Repository接口
UserRepository.java
从数据源下,创建Message实体和对应的Repository接口
MessageResitory.java
接下来通过测试用例来验证使用这两个针对不同数据源的配置进行数据操作。
下面是完整项目结构:
application.properties文件中配置连接参数即可。但是往往随着业务量发展,我们通常会进行数据库拆分或是引入其他数据库,从而我们需要配置多个数据源,下面基于之前的JdbcTemplate和Spring-data-jpa例子分别介绍两种多数据源的配置方式。
多数据源配置
对应的application.properties配置如下:
#数据源一 spring.datasource.primary.url=jdbc:mysql://localhost:3306/springboot 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/springboot1 spring.datasource.secondary.username=root spring.datasource.secondary.password=root spring.datasource.secondary.driver-class-name=com.mysql.jdbc.Driver
创建一个Spring配置类,定义两个DataSource用来读取
application.properties中的不同配置。如下例子中,主数据源配置为
spring.datasource.primary开头的配置,第二数据源配置为
spring.datasource.secondary开头的配置。
package com.lyd; import javax.sql.DataSource; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * * <p>Title: DataSourceConfig.java</p> * <p>Description: 多数据源配置读取</p> * @author lyd * @date 2017年8月3日 * @version 1.0 * @blog springboot学习http://blog.csdn.net/IT_lyd/article/category/6692929 */ @Configuration public class DataSourceConfig { @Bean(name = "primaryDataSource") @Qualifier("primaryDataSource") @ConfigurationProperties(prefix = "spring.datasource.primary") public DataSource primaryDataSource(){ return DataSourceBuilder.create().build(); } @Bean(name = "secondaryDataSource") @Qualifier("secondaryDataSource") @ConfigurationProperties(prefix = "spring.datasource.secondary") public DataSource secondaryDataSource(){ return DataSourceBuilder.create().build(); } }
一、JdbcTemplate支持
对JdbcTemplate的支持比较简单,只需要为其注入对应的datasource即可,如下例子,在创建JdbcTemplate的时候分别注入名为primaryDataSource和
secondaryDataSource的数据源来区分不同的JdbcTemplate。
package com.lyd; import javax.sql.DataSource; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; import org.springframework.jdbc.core.JdbcTemplate; /** * * <p> * Title: DataSourceConfig.java * </p> * <p> * Description: 多数据源配置读取 * </p> * * @author lyd * @date 2017年8月3日 * @version 1.0 * @blog springboot学习http://blog.csdn.net/IT_lyd/article/category/6692929 */ @Configuration public class DataSourceConfig { /** * 获取多数据源 </p> */ @Bean(name = "primaryDataSource") @Primary @Qualifier("primaryDataSource") @ConfigurationProperties(prefix = "spring.datasource.primary") public DataSource primaryDataSource() { return DataSourceBuilder.create().build(); } @Bean(name = "secondaryDataSource") @Qualifier("secondaryDataSource") @ConfigurationProperties(prefix = "spring.datasource.secondary") public Da d700 taSource secondaryDataSource() { return DataSourceBuilder.create().build(); } /** * JdbcTemplate支持 * @author lyd * @date 2017年8月3日 * @param dataSource * @return */ @Bean(name = "primaryJdbcTemplate") public JdbcTemplate primaryJdbcTemplate( @Qualifier("primaryDataSource") DataSource dataSource) { return new JdbcTemplate(dataSource); } @Bean(name = "secondaryJdbcTemplate") public JdbcTemplate secondaryJdbcTemplate( @Qualifier("secondaryDataSource") DataSource dataSource) { return new JdbcTemplate(dataSource); } }
接下来通过测试用例来演示如何使用这两个针对不同数据源的JdbcTemplate。
package com.lyd; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.test.SpringApplicationConfiguration; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @RunWith(SpringJUnit4ClassRunner.class) @SpringApplicationConfiguration(Application.class) public class ApplicationTest { @Autowired @Qualifier("primaryJdbcTemplate") protected JdbcTemplate jt1; @Autowired @Qualifier("secondaryJdbcTemplate") protected JdbcTemplate jt2; @Before public void setUp() { jt1.update("DELETE FROM USER"); jt2.update("DELETE FROM USER"); } @Test public void test() { // 往第一个数据源中插入两条数据 jt1.update("INSERT INTO user(id,name,age) VALUES(?,?,?)",1,"AAA",10); jt1.update("INSERT INTO user(id,name,age) VALUES(?,?,?)",2,"BBB",20); // 往第二个数据源中插入一条数据,若插入的是第一个数据源,则会主键冲突报错 jt2.update("INSERT INTO user(id,name,age) VALUES(?,?,?)",1,"AAA",10); // 查一下第一个数据源中是否有两条数据,验证插入是否成功 Assert.assertEquals("2", jt1.queryForObject("SELECT COUNT(*) FROM user", String.class)); // 查一下第二个数据源中是否有两条数据,验证插入是否成功 Assert.assertEquals("1", jt2.queryForObject("SELECT COUNT(*) FROM user", String.class)); } }
二、Spring-data-jpa支持
对于数据源的配置可以沿用上例中DataSourceConfig的实现。
新增对第一数据源的JPA配置,注意两处注释的地方,用于指定数据源对应的
Entity实体和
Repository定义位置,用
@Primary区分主数据源。
PrimaryConfig.java:
package com.lyd; import java.util.Map; import javax.persistence.EntityManager; import javax.sql.DataSource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties; import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; import org.springframework.data.jpa.repository.config.EnableJpaRepositories; import org.springframework.orm.jpa.JpaTransactionManager; import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.annotation.EnableTransactionManagement; @Configuration @EnableTransactionManagement @EnableJpaRepositories( entityManagerFactoryRef="entityManagerFactoryPrimary", transactionManagerRef="transactionManagerPrimary", basePackages={"com.lyd.domain.p"} //设置Repository所在位置 ) public class PrimaryConfig { @Autowired @Qualifier("primaryDataSource") private DataSource primaryDataSource; @Primary @Bean(name = "entityManagerPrimary") public EntityManager entityManager(EntityManagerFactoryBuilder builder){ return entityManagerFactoryPrimary(builder).getObject().createEntityManager(); } @Primary @Bean(name = "entityManagerFactoryPrimary") public LocalContainerEntityManagerFactoryBean entityManagerFactoryPrimary(EntityManagerFactoryBuilder builder){ return builder .dataSource(primaryDataSource) .properties(getVendorProperties(primaryDataSource)) .packages("com.lyd.domain.p") //设置实体类所在位置 .persistenceUnit("primaryPersistenceUnit") .build(); } @Autowired private JpaProperties jpaProperties; private Map<String, String> getVendorProperties(DataSource dataSource){ return jpaProperties.getHibernateProperties(dataSource); } @Primary @Bean(name = "transactionManagerPrimary") public PlatformTransactionManager transactionManagerPrimary(EntityManagerFactoryBuilder builder){ return new JpaTransactionManager(entityManagerFactoryPrimary(builder).getObject()); } }
新增对第二数据源的JPA配置,内容与第一数据源类似,具体如下:
SecondConfig.java:
package com.lyd; import java.util.Map; import javax.persistence.EntityManager; import javax.sql.DataSource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties; import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; import org.springframework.data.jpa.repository.config.EnableJpaRepositories; import org.springframework.orm.jpa.JpaTransactionManager; import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.annotation.EnableTransactionManagement; @Configuration @EnableTransactionManagement @EnableJpaRepositories( entityManagerFactoryRef="entityManagerFactorySecondary", transactionManagerRef="transactionManagerSecondary", basePackages={"com.lyd.domain.s"} //设置Repository所在位置 ) public class SecondaryConfig { @Autowired @Qualifier("secondaryDataSource") private DataSource secondaryDataSource; @Bean(name = "entityManagerSecondary") public EntityManager entityManager(EntityManagerFactoryBuilder builder){ return entityManagerFactorySecondary(builder).getObject().createEntityManager(); } @Bean(name = "entityManagerFactorySecondary") public LocalContainerEntityManagerFactoryBean entityManagerFactorySecondary(EntityManagerFactoryBuilder builder){ return builder .dataSource(secondaryDataSource) .properties(getVendorProperties(secondaryDataSource)) .packages("com.lyd.domain.s") //设置实体类所在位置 .persistenceUnit("secondaryPersistenceUnit") .build(); } @Autowired private JpaProperties jpaProperties; private Map<String, String> getVendorProperties(DataSource dataSource){ return jpaProperties.getHibernateProperties(dataSource); } @Bean(name = "transactionManagerSecondary") public PlatformTransactionManager transactionManagerSecondary(EntityManagerFactoryBuilder builder){ return new JpaTransactionManager(entityManagerFactorySecondary(builder).getObject()); } }
完成了以上配置之后,主数据源的实体和数据访问对象位于:
com.lyd.domain.p,次数据源的实体和数据访问接口位于:
com.lyd.domain.s。
分别在这两个package下创建各自的实体和数据访问接口
主数据源下,创建User实体和对应的Repository接口
package com.lyd.domain.p; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; @Entity public class User { @Id @GeneratedValue private Long id; @Column(nullable = false) private String name; @Column(nullable = false) private Integer age; // 构造函数 // get/set方法。。。 }
UserRepository.java
package com.lyd.domain.p; import org.springframework.data.jpa.repository.JpaRepository; /** * * <p>Title: UserRepository.java</p> * <p>Description: 主数据源下UserRepository接口</p> * @author lyd * @date 2017年8月4日 * @version 1.0 * @blog springboot学习http://blog.csdn.net/IT_lyd/article/category/6692929 */ public interface UserRepository extends JpaRepository<User, Long>{ }
从数据源下,创建Message实体和对应的Repository接口
package com.lyd.domain.s; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; @Entity public class Message { @Id @GeneratedValue private Long id; @Column(nullable = false) private String name; @Column(nullable = false) private String content; // 构造函数 // get/set方法。。。 }
MessageResitory.java
package com.lyd.domain.s; import org.springframework.data.jpa.repository.JpaRepository; /** * * <p>Title: UserRepository.java</p> * <p>Description: 从数据源下MessageRepository接口</p> * @author lyd * @date 2017年8月4日 * @version 1.0 * @blog springboot学习http://blog.csdn.net/IT_lyd/article/category/6692929 */ public interface MessageRepository extends JpaRepository<Message, Long>{ }
接下来通过测试用例来验证使用这两个针对不同数据源的配置进行数据操作。
package com.lyd; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.SpringApplicationConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import com.lyd.domain.p.User; import com.lyd.domain.p.UserRepository; import com.lyd.domain.s.Message; import com.lyd.domain.s.MessageRepository; @RunWith(SpringJUnit4ClassRunner.class) @SpringApplicationConfiguration(Application.class) public class ApplicationTest { @Autowired private UserRepository userService; @Autowired private MessageRepository messageService; @Before() public void serUp(){ } @Test public void test(){ userService.save(new User("aaa", 10)); userService.save(new User("bbb", 20)); userService.save(new User("ccc", 30)); userService.save(new User("ddd", 40)); userService.save(new User("eee", 50)); Assert.assertEquals(5, userService.findAll().size()); messageService.save(new Message("o1", "aaa")); messageService.save(new Message("o2", "bbb")); messageService.save(new Message("o3", "ccc")); Assert.assertEquals(3, messageService.findAll().size()); } }
下面是完整项目结构:
相关文章推荐
- SpringBoot开发详解(十) -- 使用JPA访问数据库下篇及使用Page进行数据分页
- iOS 10 不提示「是否允许应用访问数据」,导致应用无法使用的解决方案
- iOS 10 不提示「是否允许应用访问数据」,导致应用无法使用的解决方案
- 使用Powerbuilder中数据窗口表达式访问数据
- 数据访问:使用 ADO.NET 的最佳实践(ADO.NET 技术文档)
- 使用JavaScript访问XML数据
- 使用ADO操作SQL SERVER 通过'OLE DB 访问 ACCESS 数据库 ,实现数据交换
- 如何使用 ADO Stream 对象访问和修改 SQL Server BLOB 数据
- 使用JavaScript访问XML数据
- 使用OPENROWSET函数连接并访问远程数据库数据
- 使用 ADO.NET 和 Oracle 进行高级数据访问
- 数据访问:使用 ADO.NET 的最佳实践
- 使用Oracle9i全索引扫描快速访问数据
- 使用数据2分处理的通用分页存储过程 前半部分与后半部分数据访问时间相同
- 使用 ADO.NET 和 Oracle 进行高级数据访问
- 在DELPHI中使用ADO直接访问Excel数据文件(收藏)
- Spring Framework 开发参考手册 之十一 使用ORM工具进行数据访问
- Spring Reference 1.1第十一章-使用ORM工具进行数据访问
- 数据访问:使用 ADO.NET 的最佳实践(ADO.NET 技术文档)
- 数据访问:使用 ADO.NET 的最佳实践