SpringBoot-Hikari-Mybatis集成,整合sharding-jdbc,实。。。
⼀、重点技术概述
为何要使⽤HiKari连接池?
字节码精简:优化代码,直到编译后的字节码最少,这样,CPU缓存可以加载更多的程序代码;
优化代理和:减少代码,例如HikariCP的Statement proxy只有100⾏代码,只有BoneCP的⼗分之⼀;
⾃定义数组类型(FastStatementList)代替ArrayList:避免每次get()调⽤都要进⾏range check,避免调⽤remove()时的从头到尾的扫描;
⾃定义集合类型(ConcurrentBag):提⾼并发读写的效率;
其他针对BoneCP缺陷的优化,⽐如对于耗时超过⼀个CPU时间⽚的⽅法调⽤的研究(但没说具体怎么优化)。
怎么使⽤Hikari连接池呢?
springboot版本是2.X,当使⽤spring-boot-starter-jdbc或者spring-boot-starter-data-jpa依赖,springboot就会⾃动引⼊HikariCP 的依赖。
⽔平分割原理
1、⽔平分库
1)、概念:
以字段为依据,按照⼀定策略,将⼀个库中的数据拆分到多个库中。
2)、结果
每个库的结构都⼀样;数据都不⼀样;
所有库的并集是全量数据;
2、⽔平分表
1)、概念
以字段为依据,按照⼀定策略,将⼀个表中的数据拆分到多个表中。
2)、结果
每个表的结构都⼀样;数据都不⼀样;
所有表的并集是全量数据;
⽔平分割使⽤Shard-jdbc中间件
1、架构图
2、特点
1)、Sharding-JDBC直接封装JDBC API,旧代码迁移成本⼏乎为零。
2)、适⽤于任何基于Java的ORM框架,如Hibernate、Mybatis等 。
3)、可基于任何第三⽅的数据库连接池,如DBCP、C3P0、 BoneCP、Druid等。
4)、以jar包形式提供服务,⽆proxy代理层,⽆需额外部署,⽆其他依赖。
5)、分⽚策略灵活,可⽀持等号、between、in等多维度分⽚,也可⽀持多分⽚键。
6)、SQL解析功能完善,⽀持聚合、分组、排序、limit、or等查询。
⼆、代码整合
1、l
spring:
messages:
encoding: utf-8
cache-seconds: 100000
profiles:
active: beta
2、数据库分库策略
/**
* 分库算法:编号后两位</br>
*
* @author zhoudoujun01
* @date 2019年8⽉6⽇14:55:06
*/
public class DatabaseShardingAlgorithm implements ComplexKeysShardingAlgorithm {
public Collection<String> doSharding(Collection<String> availableTargetNames, Collection<ShardingValue> shardingValues) {  // 根据分⽚键名取得分⽚值列表
Collection<String> orderIdValues = getShardingValue(shardingValues, Constant.COL_NAME_ID);
//
Collection<String> dsList = new LinkedHashSet(availableTargetNames.size());
// 优先按照pid分库
if (orderIdValues != null && orderIdValues.size() > 0) {
for (String orderId : orderIdValues) {
String dsName = getDsNameById(orderId, availableTargetNames);
if (dsName != null && dsName.length() > 0) {
dsList.add(dsName);
}
}
}
if (dsList.size() == 0) {
throw new UnsupportedOperationException("分库失败(编号不符合规范)");
}
return dsList;
}
/**
* 根据编号取得数据源名:编号后两位
*
* @param id
* @param availableTargetNames
* @return 数据源名
*/
private String getDsNameById(String id, Collection<String> availableTargetNames) {
String dsName = null;
for (String name : availableTargetNames) {
// 调⽤编号规则
if (DataSourceID(id))) {
System.out.println("================== id: " + id + ", name: " + name);
dsName = name;
break;
}
}
return dsName;
}
/**
* 根据分⽚键名取得分⽚值列表
*
* @param shardingValues
*            分⽚值对象
* @param key
*            分⽚键名
* @return 分⽚值列表
*/
private Collection<String> getShardingValue(Collection<ShardingValue> shardingValues, final String key) {  Collection<String> valueSet = new ArrayList();
Iterator<ShardingValue> iterator = shardingValues.iterator();
while (iterator.hasNext()) {
ShardingValue next = ();
if (next instanceof ListShardingValue) {
@SuppressWarnings("unchecked")
ListShardingValue<String> value = (ListShardingValue<String>) next;
if (ColumnName().equals(key)) {
System.out.println("===================== key: " + key + ", values: " + Values());
valueSet = Values();
}
}
}
return valueSet;
}
}
/**
* 产⽣编号
*
* @return
*/
public static String buildID() {
long seqId = nextId();
String id = String.format(SEQID_FORMAT, seqId);
// 超过所占位数,截取后⼏位
if (id.length() > SEQID_DIGITS) {
id = id.substring(id.length() - SEQID_DIGITS, id.length());
}
// seqId后四位与数据源个数取模,得到数据源编号
int useridLast4 = (int) (seqId % ((int) Math.pow(10, USERID_LAST_DIGITS)));
int ds = useridLast4 % DATASOURCE_CNT;
// 时间
Calendar cal = Instance();
return String.format(ORDERNO_FORMAT, cal, id, ds);
}
3、数据源集成配置
jdbc2.properties
test1.url=jdbc:mysql://localhost:3306/test1?autoReconnect=true&autoReconnectForPools=true&useUnicode=true&characterEncoding=UTF-8&zeroDateTi meBehavior=convertToNull
test1.username=root
test1.password=root
test1.initialSize=5
test1.maxActive=5
test1.maxIdle=5
test1.minIdle=1
test1.maxWait=6000
test1.validationQuery=SELECT 1 FROM DUAL
test2.url=jdbc:mysql://localhost:3306/test2?autoReconnect=true&autoReconnectForPools=true&useUnicode=true&characterEncoding=UTF-8&zeroDateTi meBehavior=convertToNull
test2.username=root
test2.password=root
test2.initialSize=5
test2.maxActive=5
test2.maxIdle=5
test2.minIdle=1
test2.maxWait=6000
test2.validationQuery=SELECT 1 FROM DUAL
ShardingDataSourceConfig
数据源集成配置
@Bean
@Primary
public DataSource shardingDataSource() throws SQLException {
ShardingRuleConfiguration shardingRuleConfig = new ShardingRuleConfiguration();
/
/ PERSON表分库规则
ateDataSource(createDataSourceMap(), shardingRuleConfig, new HashMap(),
new Properties());
}
PERSON表分库规则
/**
* 定义Person表分库规则
* @return
jpa mybatis*/
private TableRuleConfiguration getPersonRuleConfiguration() {
TableRuleConfiguration paymentRequestTableRule = new TableRuleConfiguration();
paymentRequestTableRule.setLogicTable(LOGIC_TABLE_PERSON);
paymentRequestTableRule.setActualDataNodes(ACTUAL_DATA_NODES_PERSON);
paymentRequestTableRule.setDatabaseShardingStrategyConfig(new ComplexShardingStrategyConfiguration(
SHARDING_COLUMN_ID, Name()));
paymentRequestTableRule.setKeyGeneratorColumnName(KEY_GENERATOR_COLUMN_NAME_ID);
return paymentRequestTableRule;
}
组装数据源map
Prd 4个库
Beta 2个库
取系统环境beta
/**
* 系统环境名
*/
private static final String ACTIVE_ENV = "spring.profiles.active";
/**
* 多数据源别名列表
*/
private static String[] DS_NAMES = { "ds_00", "ds_01", "ds_02", "ds_03" };
/**
* 加载创建dataSource:
*
* @return
*/
private Map<String, DataSource> createDataSourceMap() {
HashMap<String, DataSource> dataSourceMap = wHashMap();
String activeEnvPrd = "prd";
// 得到系统环境
String activeEnv = Property(ACTIVE_ENV);
log.info("dataSource 1 url:{} activeEnv:" + activeEnv + ","
+ Property(MYSQL_DS_PREFIX + 1 + MYSQL_DS_SUFFIX_URL));
// 未配置或者指定⽣产环境时,直接使⽤指定数据源配置
if (activeEnv == null || activeEnvPrd.equalsIgnoreCase(activeEnv)) {
for (int i = 1; i <= DS_NAMES.length; i++) {
dataSourceMap.put(DS_NAMES[i - 1], getDataSourceItem(i));
}
}
// 测试环境下,数据源00,01对应1数据库,数据源02,03对应2数据库
else {
for (int i = 1; i <= DS_NAMES.length; i++) {
if (i <= 2) {
dataSourceMap.put(DS_NAMES[i - 1], getDataSourceItem(1));
} else if (i <= 4) {
dataSourceMap.put(DS_NAMES[i - 1], getDataSourceItem(2));
}
}
}
return dataSourceMap;
}
Hikari根据指定数据源配置标识⽣成数据源对象
private DataSource getDataSourceItem(int i) {
HikariConfig config = new HikariConfig();
config.Property(MYSQL_DS_PREFIX + i + MYSQL_DS_SUFFIX_URL));
config.Property(MYSQL_DS_PREFIX + i + ".username"));
config.Property(MYSQL_DS_PREFIX + i + ".password"));
config.setMinimumIdle(Integer.Property(MYSQL_DS_PREFIX + i + ".minIdle")));
config.setMaximumPoolSize(Integer.Property(MYSQL_DS_PREFIX + i + ".maxIdle")));  config.setConnectionTimeout(Long.Property(MYSQL_DS_PREFIX + i + ".maxWait")));  config.Property(MYSQL_DS_PREFIX + i + ".validationQuery"));
config.setDriverClassName("sql.jdbc.Driver");
HikariDataSource ds = new HikariDataSource(config);
return ds;
}
SqlSessionFactoryConfig

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。