写在前面
诚然 Sharding-shpere
是一款非常优秀的技术产品, 下面介绍的自研的技术产品,在生态和完善度上是无法与之相提并论的。
但是笔者自己开发的这个项目: sharding-mybatis
,目前已用于生产环境,且承载TPS超过数万的这个项目, 在某些特殊场景或许更好用一些, 如果您感兴趣, 可以耐心读完以下的文档。
如果您赶时间, 可以看下介绍不必观看使用说明,日后用到再来看。
为啥要使用 sharding-mybatis
sharding-mybatis
与springboot/mybatis 生态无缝集成,无业务入侵,轻量,够用sharding-sphere
存在一些不支持的SQL,您的业务必须要使用这种SQL;sharding-mybatis
支持任何对应数据库的SQL语法, 这个是基于AST语法树的ShardingSphere不具备的sharding-mybatis
效率非常高, 整个组件在性能损耗方面可以忽略不计,底层采用内存缓存,经万级别TPS生产环境验证,性能与Sharding-Sphere 无异附: sharding-sphere 不支持的一些SQL列表
INSERT INTO tbl_name (col1, col2, …) VALUES(1+2, ?, …) VALUES语句不支持运算表达式
INSERT INTO tbl_name (col1, col2, …) SELECT col1, col2, … FROM tbl_name WHERE col3 = ? -- INSERT .. SELECT
SELECT COUNT(col1) as count_alias FROM tbl_name GROUP BY col1 HAVING count_alias > ? -- HAVING
SELECT * FROM tbl_name1 UNION SELECT * FROM tbl_name2 -- UNION
SELECT * FROM tbl_name1 UNION ALL SELECT * FROM tbl_name2 -- UNION ALL
SELECT * FROM ds.tbl_name1 -- 包含schema
SELECT SUM(DISTINCT col1), SUM(col1) FROM tbl_name -- 详见DISTINCT支持情况详细说明
SELECT * FROM tbl_name WHERE to_date(create_time, ‘yyyy-mm-dd’) = ? -- 会导致全路由
SELECT SUM(DISTINCT col1), SUM(col1) FROM tbl_name -- 同时使用普通聚合函数和DISTINCT聚合函数
项目简介:
项目地址:sharing-mybatis
注: 本文不是写来收集star的, 当然你觉得项目帮助到了你, 你想给的话,我也不反对
功能列表
- 多数据源支持
- 支持分库分表(仅支持整数类型的sharding Key)
- 支持只分库、支持只分表、支持不分库分表
- 支持使用事务 (见下面使用说明)
- 支持分库分表规则自定义(aviator 表达式引擎)
- 支持不同数据源混用
使用说明
1. 引入依赖, 最好禁用掉spring-boot 的自身datasource装配,因为没用
<dependency>
<groupId>com.winjeg.spring</groupId>
<artifactId>sharding-mybatis</artifactId>
<version>1.0.0-SNAPSHOT</version>
</dependency>
2. 配置好数据源
下面是 spring boot
的项目配置,一般可以配置再配置中心,或者直接配置在 application.yaml
中;
对于非springboot项目,我奉劝一句,升级到Springboot 把
datasource:
list:
- name: demo-1
driver-class-name: com.mysql.cj.jdbc.Driver
jdbc-url: jdbc:mysql://10.10.10.10:3306/demo_1?useSSL=false&useUnicode=true&characterEncoding=UTF-8
username: demo_user
password: 123456
- name: demo-2
driver-class-name: com.mysql.cj.jdbc.Driver
jdbc-url: jdbc:mysql://10.10.10.10:3306/demo_2?useSSL=false&useUnicode=true&characterEncoding=UTF-8
username: demo_user
password: 123456
3. 开启分库分表支持的配置
@SpringBootApplication
@EnableSharding(packages = {"com.winjeg.spring.test.mapper", "com.winjeg.spring.test.dao"})
public class SpringApplicationDemo {
public static void main(String[] args) {
SpringApplication.run(SpringApplicationDemo.class, args);
}
}
4. 在mapper上添加注解 & 标记出分表键, 如不需要分库分表, 仅配置datasource 和 mapperLocation
@Sharding(datasource = {"demo-1", "demo-2"},
mapperLocation = "classpath:mappers/demo/*.xml",
dbRule = "'demo-' + (id % 16 / 8 + 1)",
tableRule = "'user_' + (id % 16 % 4)",
shardingKey = "id")
public interface ShardingMapper {
int updateUser(@ShardingKey @Param("id") final long id,
@Param("name") final String name);
}
样例Mapper
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.winjeg.spring.sharding.test.mapper.ShardingMapper">
<insert id="addUser">
INSERT INTO ${tableName}
(id, name) VALUES(#{id}, #{name})
</insert>
<update id="updateUser">
UPDATE ${tableName}
SET name=#{name}
WHERE id = #{id}
</update>
</mapper>
注: 在不分库分表的时候, datasource只能设置一个, 设置多个则无用
仅分库的时候,只设置 dbRule, 仅分表的时候设置 tableRule
5. 代码中使用
@Autowired
private NormalMapper testMapper;
@Autowired
private WonderMapper wonderMapper;
@GetMapping("/normal")
public List<String> noneSharding(@RequestParam(value = "uid", defaultValue = "1") final long userId){
val tables=testMapper.getTables();
tables.add(wonderMapper.getUser());
return tables;
}
使用事务
@GetMapping("/trans")
public String Sharding(@RequestParam(value = "uid", defaultValue = "1") final long userId,
@RequestParam(value = "name", defaultValue = "") final String name){
val manager=transactionManager.getTransactionManager(ShardingMapper.class,userId);
TransactionStatus status=manager.getTransaction(definition);
try{
if(shardingMapper.addUser(userId,name)< 1){
manager.rollback(status);
return"add_trans_fail";
}
if(shardingMapper.updateUser(userId,name+"updated")< 1){
manager.rollback(status);
return"update_trans_fail";
}
manager.commit(status);
return"trans_success";
}catch(Exception e){
manager.rollback(status);
}
return"trans_fail";
}
写在最后
如果有感兴趣而当同学, 可以在本文回复咨询, 或者在github仓库留言咨询,或者 email我