SpringBoot应用多数据源支持[嗡汤圆的小笔记]
2016-12-30 20:22
405 查看
在某些应用场景中,SpringBoot应用可能需要同时连接多个数据源(同类型或不同类型数据库)进行数据处理和写入操作。下文将配置多数据源(两个Postgres数据库)为例进行说明。
其中:
* 数据库-1维护表1,表3
* 数据库-2维护表2,表3
* 分别说明如何分别往表1,表2(各库独占表)写数据,以及分别往数据库-1的表3、数据库-2的表3写入不同的数据。
已经建好的项目和样例代码请见链接:SpringBootMultipleDataSource
SpirngBoot的数据源组件(包含jpa)声明层级如下:
DataSource -> EntityManager -> TransactionManager
这些组件声明都可以写在一个类中,方便管理。
例子中的表1位于tbdsone包下,表3位于tbdsboth包下,表2位于tdbstwo包下。而两个EntityManager均管理tbdsboth,因此表3在两个数据源中都存在。
但是在多数据源场景下,需要调用不同的EntityManager来操作不同数据库,因此需要在提取出一个虚类来,代码结构如下:
具体到某张表的Dao时,则通过继承实体类来实现基本功能如有张表为TableOne,它仅在数据源-1中使用,则Dao如下:
某张具体表的实现类如下:
其中:
* 数据库-1维护表1,表3
* 数据库-2维护表2,表3
* 分别说明如何分别往表1,表2(各库独占表)写数据,以及分别往数据库-1的表3、数据库-2的表3写入不同的数据。
1、项目搭建
基础步骤,在start.spring.io中勾选JPA, JDBC, POSTGRESSQL组件,下载基础MAVEN项目。并导入IDE即可。已经建好的项目和样例代码请见链接:SpringBootMultipleDataSource
1.1、基础配置
刚构建好的项目包含spring-data相关组件,因此无初始配置时,会提示缺少默认配置而无法启动。以下演示配置过程。1.1.1、Properties文件配置
在application.properties声明数据源配置,分别包括数据库one,数据库two,和通用jpa设置。spring.datasource.one.url=jdbc:postgresql://localhost:5432/testdb1 spring.datasource.one.username=postgres spring.datasource.one.password=password spring.datasource.one.driverClassName=org.postgresql.Driver spring.datasource.two.url=jdbc:postgresql://localhost:5432/testdb2 spring.datasource.two.username=postgres spring.datasource.two.password=password spring.datasource.two.driverClassName=org.postgresql.Driver spring.jpa.hibernate.ddl-auto=update spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect spring.jpa.show-sql=true
1.1.2、Bean声明
由于存在两个数据源,因此不能使用Springboot的默认数据配置方式,而是自行声明bean。SpirngBoot的数据源组件(包含jpa)声明层级如下:
DataSource -> EntityManager -> TransactionManager
这些组件声明都可以写在一个类中,方便管理。
(1) Datasource
设置了各数据库的连接方式与参数,结合Spring的配置文件自动注入方式来分别声明两个数据源。/*通过不同的配置参数前缀来分别为不同datasource赋予参数*/ @Bean @Primary @ConfigurationProperties(prefix = "spring.datasource.one") public DataSource primaryDataSource() { return DataSourceBuilder.create().build(); } @Bean @ConfigurationProperties(prefix = "spring.datasource.two") public DataSource secondaryDataSource() { return DataSourceBuilder.create().build(); }
(2) EntityManager
通过EntityManagerFactoryBuild -> EntityManagerFactory,用于以后声明EntityManager使用。EntityManager定义了所使用的数据源,和所扫描的Entity包路径(packages)。EntityManager仅管理包路径下的Entity,以达到在不同数据源管理不同表的目的。例子中的表1位于tbdsone包下,表3位于tbdsboth包下,表2位于tdbstwo包下。而两个EntityManager均管理tbdsboth,因此表3在两个数据源中都存在。
@Bean(name = "primaryEMFB") @Primary public LocalContainerEntityManagerFactoryBean primaryEntityManagerFactory(EntityManagerFactoryBuilder builder) { return builder.dataSource(primaryDataSource()) .packages("com.rails.demoapp.core.module.tbdsboth", "com.rails.demoapp.core.module.tbdsone") .persistenceUnit("primary") .properties(buildProperties()).build(); } @Bean(name = "secondaryEMFB") public LocalContainerEntityManagerFactoryBean secondaryEntityManagerFactory(EntityManagerFactoryBuilder builder) { return builder.dataSource(primaryDataSource()) .packages("com.rails.demoapp.core.module.tbdsboth", "com.rails.demoapp.core.module.tbdstwo") .persistenceUnit("secondary") .properties(buildProperties()).build(); } // 公共jpa设置 @Value("${spring.jpa.hibernate.ddl-auto}") String dll; @Value("${spring.jpa.properties.hibernate.dialect}") String dialect; @Value("${spring.jpa.show-sql}") String showSql; private Map<String, Object> buildProperties() { Map<String, Object> properties = new HashMap<String, Object>(); properties.put("hibernate.ejb.naming_strategy", ImprovedNamingStrategy.class.getName()); properties.put("hibernate.hbm2ddl.auto", dll); properties.put("hibernate.dialect", dialect); properties.put("hibernate.show_sql", showSql); return properties; }
(3) TransactionManager
TransactionManager用于事务管理,基于EntityManager创建。@Bean(name="primaryTM") @Autowired public PlatformTransactionManager primaryTransactionManager(EntityManagerFactoryBuilder builder) { return new JpaTransactionManager(primaryEntityManagerFactory(builder).getObject()); } @Bean(name="secondaryTM") @Autowired public PlatformTransactionManager secondaryTransactionManager(EntityManagerFactoryBuilder builder) { return new JpaTransactionManager(primaryEntityManagerFactory(builder).getObject()); }
1.2、启动效果
可以在两个Postgres数据库中看到:testdb1中包含table1,table3;testdb2中包含table2,table3。即可说明两个EntityManager分别在不同数据库中创建了自己所管理的表。2、应用开发
2.1、Dao层
首先创建公共Dao层用于编写基础的增删改查操作代码。传统的单数据源代码结构大致如下:/*通过接口定义操作,以及实现类编写具体代码*/ public Interface CommonDao<T> { T findById(Object id) throws Exception; List<T> query(String sql) throws Exception; T save(Object t) throws Exception; T update(Object t) throws Exception; void delete(Object t) throws Exception; } public class CommonDaoImpl<T> implements CommonDao<T> { //由于只有一个entityManager,因此用Autowired注入默认即可 @Autowired EntityManager em; @Override T findById(Object id) throws Exception{ return (T) em.find(this.getPersistentClass(), id); } @Override List<T> query(String sql) throws Exception{ Query query = em.createNativeQuery(sql); List<T> results = query.getResultList(); return results; } // ...... // 以下省略...... }
但是在多数据源场景下,需要调用不同的EntityManager来操作不同数据库,因此需要在提取出一个虚类来,代码结构如下:
/*通过接口定义操作,以及抽象类编写具体代码,在实现类中注入各自的entityManager*/ public Interface CommonDao<T> { T findById(Object id) throws Exception; List<T> query(String sql) throws Exception; T save(Object t) throws Exception; T update(Object t) throws Exception; void delete(Object t) throws Exception; } /*统一的实现代码虚类*/ public abstract class AbsCommonDaoImpl<T> implements CommonDao<T>{ // 引入的EntityManager由具体的实现类引入,上例代码中的em变量统一通过getEntityManager()方法获取。 abstract EntityManager getEntityManager(); @Override T findById(Object id) throws Exception{ return (T) getEntityManager().find(this.getPersistentClass(), id); } @Override List<T> query(String sql) throws Exception{ Query query = getEntityManager().createNativeQuery(sql); List<T> results = query.getResultList(); return results; } // ...... // 以下省略...... } /*各数据源对应的实现类如下*/ // 数据源-1 @Repository("PrimaryCommonDaoImpl") public class PrimaryCommonDaoImpl<T> extends AbsCommonDaoImpl<T>{ // 注入数据库-1的EntityManager @Autowired @Qualifier("primaryEMFB") protected EntityManager em; @Override EntityManager getEntityManager() { return em; } } // 数据源-2 @Repository("ScondaryCommonDaoImpl") public class ScondaryCommonDaoImpl<T> extends AbsCommonDaoImpl<T>{ // 注入数据库-2的EntityManager @Autowired @Qualifier("secondaryEMFB") protected EntityManager em; @Override EntityManager getEntityManager() { return em; } }
具体到某张表的Dao时,则通过继承实体类来实现基本功能如有张表为TableOne,它仅在数据源-1中使用,则Dao如下:
public Interface TableOneDao extends CommonDao<TableOne> { // 这里写针对TableOne的操作 } @Repository("TableOneDaoImpl") public Class TableOneDaoImpl extends PrimaryCommonDaoImpl<TableOne> implements TableOneDao { // 针对TableOneDao接口声明方法的实现代码 }
2.2、Service层
Service层用于实现复杂业务逻辑,以及事务管理。通用Service设计如下:public Interface CommonService<T> { T findById(Object id) throws Exception; List<T> query(String sql) throws Exception; T save(Object t) throws Exception; T update(Object t) throws Exception; void delete(Object t) throws Exception; } // 由于具体表的实现需要制定具体的Dao,因此在这里无需实现公用的ServiceImpl,仅对接口做一下定义即可。
某张具体表的实现类如下:
@Service("TableOneServiceImpl ") public TableOneServiceImpl extends CommonService<TableOne> { // tableOneDaoImpl已经指定了使用数据源-1 @Resource(name = "TableOneDaoImpl") private TableOneDao tableOneDao; // 以实现save方法为例说明Transactional的声明方法 // !!! 这里的@Transactional注解不是原先单数据源时的Transactional // 而是org.springframework.transaction.annotation.Transactional // 这点需要注意,否则不支持下边的参数 @Transactional("primaryTM")//通过bean name制定具体的transactionManager @Override TableOne save(Object t) throws Exception { return tableOneDao.save(t); } }
相关文章推荐
- spring学习笔记(18)使用JNDI模拟访问应用服务器多数据源实例
- spring boot 学习笔记(二) 构建web支持jsp
- SpringBoot学习笔记 - web开发(Thymeleaf的应用)
- Zephyr应用笔记:关于支持zephyr-v1.11.0版本mcuboot加密编译错误问题
- SpringBoot项目中的多数据源支持的方法
- 使用 Spring Boot 快速构建 Spring 框架应用---学习笔记
- 使用Spring Boot快速构建基于SQLite数据源的应用
- SpringBoot学习笔记之JSP与freemarker支持
- 使用Spring Boot快速构建基于SQLite数据源的应用
- Spring Boot学习笔记之IntelliJ IDEA将应用打包发布
- spring-boot支持双数据源mysql+mongo
- SpringBoot多依赖模块应用中,如何处理多数据源的主数据源位置
- Spring Boot学习笔记二(创建第一个Spring Boot应用)
- SpringBoot项目中的多数据源支持
- 4. Spring Boot 1.2.5,Spring Data JPA多数据源支持
- Spring Boot基础教程11-web应用开发-CORS支持
- Spring Boot 学习笔记【8】Spring Boot支持MyBatis
- SpringBoot整合Mybatis,多数据源,事务,支持java -jar 启动.
- 搭建SpringBoot、Jsp支持学习笔记
- java鬼混笔记:springboot 6、springboot整合mybatis(支持多数源)