spring多数据源配置笔记
本文阐述使用多数据源的额场景,以及如何使用springboot的配置多数据源。
关于后者,主要是直接引用其它博文:https://blog.csdn.net/u012060033/article/details/123759694
如果不想了解不太必要知道的,建议查看 https://www.cnblogs.com/chen-msg/p/7485701.html
一、多数据源的使用场景
使用多数据源的原因一般有:
- 数据采集
- 分库
- 其它
本文主要讨论的是分库问题。现在讨论的一般所谓“分库”是主要因为两个目的:
- 实现多租户
- 数据的水平分割,以便增加数据吞吐能力
- 读写分离
实现多租户
在某些前提下,通过分库来实现多租户也是可以,例如不想浪费应用服务器的资源,减少维护的压力。
但这个行为,本人并不是很认可。因为当你的客户没有多少数据量的时候,分库分表其实没有太大意义。
如果客户的数据很多,那么客户应该给出更多的钱,这种情况下也没有必要和其它客户共享一个硬件资源。
至于业界一直鼓吹的SAAS,云之类的,大部分业务场景下,对于大公司并没有特别的吸引力。因为财大气粗,这个时候他们主要考虑一个问题:数据安全性。
大一点的公司也是这个思路。例如字节自己建立数据中心,也是类似的心思:安全,不想受制于人等等。
所以,现今国内大公司更多的做法是:自己采购服务器,自己组建it团队。和其它公司共享一个别的公司运营的云平台,把关键的商务数据放上去,不太可能的。
读写分离
这个建议直接使用数据库自身的功能了。但如果的确有某些不得不用的理由,也是可以的。
不过项目做多了,总是有一些特别的要求,所以本章节不再讨论要不要使用多数据源。
二、配置多数据源
2.1配置多数据源所需要面临的几个问题
- 如果有ocrm等和数据源有关的组件,那么这些组件内部如何切换
- 多个数据源之间的事务一致性如何处理(如果它们有关系的话)
- 切换数据源的成本如何降低一些,即如何使用更少的资源和更少的计算能力来进行切换
如何保持事务一致性的话题内容太多,此处略过。
所以剩下的主要关心问题就是如何切换。
如果是mybatis或者mybatis-plus等orm还是相对友好的--因为是现成的。如果是自己编写的ocrm框架,那么需要稍微花费一些心思。
2.2一般的实现方式
spring本身支持多数据源的配置,所以难度上并没有什么。对于设计人员而言,主要工作是慎重选择实现的方式。
spring的方式步骤:
- 定义个数据源
- 定义数据源有关的bean对象:datasource,jdbcTemplate,事务管理器等等
其它变化都是基于以上基础实现的。
以下文章讲解的比较清楚:https://www.cnblogs.com/chen-msg/p/7485701.html
三、例子
例子上按照https://www.cnblogs.com/chen-msg/p/7485701.html来编写。
运行环境:windows11 ,mysql8.0.x,springboot 2.6.7
3.1 application.properties
spring.datasource.type=com.zaxxer.hikari.HikariDataSource spring.datasource.hikari.autoCommit=false spring.datasource.hikari.connectionTimeout=180000 spring.datasource.hikari.idleTimeout=600000 spring.datasource.hikari.maxLifetime=1800000 spring.datasource.hikari.minimumIdle=3 spring.datasource.hikari.maximumPoolSize=6 spring.datasource.hikari.connection-test-query=select 1 #多数据源演示 spring.datasource.school.driver-class-name=com.mysql.cj.jdbc.Driver spring.datasource.school.jdbcUrl=jdbc:mysql://localhost:7799/spring?rewriteBatchedStatements=true&autoReconnect=true&allowMultiQueries=true&useSSL=false&allowPublicKeyRetrieval=true spring.datasource.school.username=spring spring.datasource.school.password=123 spring.datasource.factory.driver-class-name=com.mysql.cj.jdbc.Driver spring.datasource.factory.jdbcUrl=jdbc:mysql://localhost:7799/factory?rewriteBatchedStatements=true&autoReconnect=true&allowMultiQueries=true&useSSL=false&allowPublicKeyRetrieval=true spring.datasource.factory.username=spring spring.datasource.factory.password=123
3.2 DataSourceConfig.java --配置数据源
package com.example.multids.config; import javax.sql.DataSource; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.jdbc.DataSourceBuilder; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.datasource.DataSourceTransactionManager; import org.springframework.transaction.PlatformTransactionManager; @Configuration public class DataSourceConfig { @Bean(name = "factoryDataSource") @Qualifier("factoryDataSource") @Primary @ConfigurationProperties(prefix = "spring.datasource.factory") public DataSource factoryDataSource() { System.out.println("-------------------- factoryDataSource init ---------------------"); return DataSourceBuilder.create().build(); } @Bean(name = "schoolDataSource") @Qualifier("schoolDataSource") @ConfigurationProperties(prefix = "spring.datasource.school") public DataSource schoolDataSource() { System.out.println("-------------------- schoolDataSource init ---------------------"); return DataSourceBuilder.create().build(); } @Bean(name = "schoolJdbcTemplate") @Qualifier("schoolJdbcTemplate") public JdbcTemplate schoolJdbcTemplate(@Qualifier("schoolDataSource") DataSource dataSource) { return new JdbcTemplate(dataSource); } @Bean(name = "factoryJdbcTemplate") @Qualifier("factoryJdbcTemplate") public JdbcTemplate factoryJdbcTemplate(@Qualifier("factoryDataSource") DataSource dataSource) { return new JdbcTemplate(dataSource); } /******配置事务管理********/ @Bean public PlatformTransactionManager schoolTransactionManager(@Qualifier("schoolDataSource")DataSource ds) { return new DataSourceTransactionManager(ds); } @Bean public PlatformTransactionManager factoryTransactionManager(@Qualifier("factoryDataSource")DataSource ds) { return new DataSourceTransactionManager(ds); } }
3.3 SqlController- 测试控制器
package com.example.multids.controller; import java.util.HashMap; import java.util.List; import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping(value = "/multids") public class SqlController { @Qualifier("schoolJdbcTemplate") @Autowired private JdbcTemplate jdbcTp; @Qualifier("factoryJdbcTemplate") @Autowired private JdbcTemplate factoryJdbcTp; @RequestMapping(value = "getAll", method = { RequestMethod.GET, RequestMethod.POST }) public Object getAll() { String sql = "select * from student limit 2"; List<Map<String, Object>> studentList = jdbcTp.queryForList(sql); String inventorySql = "select * from inventory limit 2"; List<Map<String, Object>> inventoryList = factoryJdbcTp.queryForList(inventorySql); Map<String, Object> result = new HashMap<>(); result.put("student-spring-ds", studentList); result.put("inventory-factory-ds", inventoryList); return result; } }
3.4 测试结果
浏览器执行结果:http://localhost:8081/multids/getAll
四、小结
总体而言,配置还是比较简单。