Sharding JDBC 基础概念

Apache ShardingSphere 是一套开源的分布式数据库解决方案组成的生态圈,它由 JDBC、Proxy 和 Sidecar(规划中)这 3 款既能够独立部署,又支持混合部署配合使用的产品组成。 它们均提供标准化的数据水平扩展、分布式事务和分布式治理等功能,可适用于如 Java 同构、异构语言、云原生等各种多样化的应用场景。

Apache ShardingSphere 旨在充分合理地在分布式的场景下利用关系型数据库的计算和存储能力,而并非实现一个全新的关系型数据库。 关系型数据库当今依然占有巨大市场份额,是企业核心系统的基石,未来也难于撼动,我们更加注重在原有基础上提供增量,而非颠覆。

Apache ShardingSphere 5.x 版本开始致力于可插拔架构,项目的功能组件能够灵活的以可插拔的方式进行扩展。 目前,数据分片、读写分离、数据加密、影子库压测等功能,以及 MySQL、PostgreSQL、SQLServer、Oracle 等 SQL 与协议的支持,均通过插件的方式织入项目。 开发者能够像使用积木一样定制属于自己的独特系统。Apache ShardingSphere 目前已提供数十个 SPI 作为系统的扩展点,仍在不断增加中。

简单使用

引入依赖

         <!-- sharding jdbc 依赖 --><dependency><groupId>org.apache.shardingsphere</groupId><artifactId>sharding-jdbc-spring-boot-starter</artifactId><version>4.0.0-RC1</version></dependency><dependency><groupId>org.apache.shardingsphere</groupId><artifactId>sharding-core-common</artifactId><version>4.0.0-RC1</version></dependency><!-- 分布式事务管理 --><dependency><groupId>io.shardingsphere</groupId><artifactId>sharding-transaction-spring-boot-starter</artifactId><version>3.1.0</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.1.4</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>1.1.21</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency>

编写application配置
我这边将配置文件拆开,方便演示不同策略进行分库分表。

server:port: 8085spring:main:allow-bean-definition-overriding: trueprofiles:active: submybatis:mapper-locations: classpath:mapper/*.xml

在处理分库分表的时候,我们可以分库分表同时进行,或者单独分库或者分表,通过设置相应的策略实现相应的功能。

spring:main:allow-bean-definition-overriding: trueshardingsphere:# 参数配置 ,显示SQLprops:sql:show: true# 配置数据源datasource:# 给每个数据源取别名 任意取names: ds0,ds1# 给master-ds1配置数据库连接信息ds0:type: com.alibaba.druid.pool.DruidDataSourcedriver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://192.168.26.128:3306/myslave?useSSL=false&useUnicode=true&characterEncoding=utf-8username: rootpassword: 123456maxPoolSize: 100minPoolSize: 5ds1:type: com.alibaba.druid.pool.DruidDataSourcedriver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://192.168.26.129:3306/myslave?useSSL=false&useUnicode=true&characterEncoding=utf-8username: rootpassword: 123456maxPoolSize: 100minPoolSize: 5#配置默认数据源ds0sharding:# 默认数据源,主要用于写,注意一定要配置;如果不配置就会把三个节点都当作从slave节点,新增,修改和删除会出错。default-data-source-name: ds0# 配置分表规则 --》单数存储在user1中,偶数存放在user0中tables:# 逻辑表名 useruser:# 数据节点 : 数据源${0..N}.逻辑表名${0..N},# ds0.user0 代表ds0数据中的user0表actual-data-nodes: ds${0..1}.user${0..1}# 只分表不分库# actual-data-nodes: ds0.user${0..1}# 拆分库策略 将数据存放到指定库中database-strategy:inline:sharding-column: age  # 分片字段algorithm-expression: ds${age % 2}  # 分片算法表达式table-strategy:inline:sharding-column: age  # 分片字段algorithm-expression: user${age % 2}  # 分片算法表达式

创建数据库
由上文的配置可知,我们需要在两台虚拟机中分表创建两张user表,分别是user0,user1;如果不创建的话会导致我们插入数据失败。

编写业务代码
实体类

@Data
public class User {private Long id;private String nickname;private String password;private Integer age;private Integer sex;private Date birthday;
}

Mapper

@Mapper
public interface UserMapper {@Insert("insert into user(nickname,password,age,sex,birthday) values(#{nickname},#{password},#{age},#{sex},#{birthday})")void addUser(User user);@Select("select * from user")List<User> findUsers();
}

测试

 @Autowiredprivate UserMapper userMapper;@Testvoid contextLoads() {User user = new User();user.setNickname("张三" + new Random().nextInt());user.setPassword("123");user.setAge(22);user.setSex(22);user.setBirthday(new Date());userMapper.addUser(user);}

可以看到将数据插入到ds0数据库中的user0表中。

将测试代码中的年龄修改为单数后,可以发现数据插入到ds1数据库中的user1表中。

使用standard策略进行分片

该案例根据上述用户表中的birthday字段进行分片。
编写application配置

spring:main:allow-bean-definition-overriding: trueshardingsphere:# 参数配置 ,显示SQLprops:sql:show: true# 配置数据源datasource:# 给每个数据源取别名 任意取names: ds0,ds1# 给master-ds1配置数据库连接信息ds0:type: com.alibaba.druid.pool.DruidDataSourcedriver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://192.168.26.128:3306/myslave?useSSL=false&useUnicode=true&characterEncoding=utf-8username: rootpassword: 123456maxPoolSize: 100minPoolSize: 5ds1:type: com.alibaba.druid.pool.DruidDataSourcedriver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://192.168.26.129:3306/myslave?useSSL=false&useUnicode=true&characterEncoding=utf-8username: rootpassword: 123456maxPoolSize: 100minPoolSize: 5#配置默认数据源ds0sharding:# 默认数据源,主要用于写,注意一定要配置;如果不配置就会把三个节点都当作从slave节点,新增,修改和删除会出错。default-data-source-name: ds0# 配置分表规则 --》单数存储在user1中,偶数存放在user0中tables:# 逻辑表名 useruser:actual-data-nodes: ds${0..1}.user${0..1}# 拆分库策略 将数据存放到指定库中database-strategy:standard:shardingColumn: birthdaypreciseAlgorithmClassName: com.example.springbootshardingjdbc.algorithm.BirthdayAlgorithmtable-strategy:inline:sharding-column: age  # 分片字段algorithm-expression: user${age % 2}  # 分片算法表达式

编写策略配置文件
datalist的数量要根据你定义的数据库数量来,否则会出错。

public class BirthdayAlgorithm implements PreciseShardingAlgorithm<Date> {List<Date> dateList = new ArrayList<>();{Calendar calendar1 = Calendar.getInstance();calendar1.set(2021, 1, 1, 0, 0, 0);Calendar calendar2 = Calendar.getInstance();calendar2.set(2022, 1, 1, 0, 0, 0);dateList.add(calendar1.getTime());dateList.add(calendar2.getTime());}@Overridepublic String doSharding(Collection<String> collection, PreciseShardingValue<Date> preciseShardingValue) {// 获取属性数据库的值Date date = preciseShardingValue.getValue();// 获取数据源的名称消息列表Iterator<String> iterable = collection.iterator();String target = null;for (Date date1 : dateList) {target = iterable.next();//如果数据晚于指定日期if (date.before(date1)) {break;}}return target;}
}

测试

     @Testvoid contextLoads() {User user = new User();user.setNickname("张三" + new Random().nextInt());user.setPassword("123");user.setAge(1);user.setSex(22);user.setBirthday(new Date());userMapper.addUser(user);}

由于当前时间晚于datalist时间,所以直接返回第一个数据库,将数据插入到ds0数据库中。

插入数据时主键使用雪花算法

只需要在application中进行配置即可;配置雪花算法之后,我们需要将数据库中主键的类型改为bigint型。

 #配置默认数据源ds1sharding:# 默认数据源,主要用于写,注意一定要配置读写分离;如果不配置就会把三个节点都当作从slave节点,新增,修改和删除会出错。default-data-source-name: ds0# 配置分表规则 --》单数存储在user1中,偶数存放在user0中tables:# 逻辑表名 useruser:key-generator:# 主键 雪花算法column: idtype: SNOWFLAKE# 只分表不分库actual-data-nodes: ds0.user${0..1}table-strategy:inline:sharding-column: age  # 分片字段algorithm-expression: user${age % 2}  # 分片算法表达式

按照日期将数据插入到对应的表中

我们可以将数据按照日期分别存放到对应的表中,比如订单数据,我们可以将其区分为1月的订单,2月的订单等。这里采用最简单的方法,直接通过字段进行匹配存放。
创建数据库
这边只演示分表,没进行分库,所以只需要在本地数据库创建3张order表即可,分别是order_202101,order_202102,order_202103。

编写application配置

spring:main:allow-bean-definition-overriding: trueshardingsphere:# 参数配置 ,显示SQLprops:sql:show: true# 配置数据源datasource:# 给每个数据源取别名 任意取names: ds0,ds1# 给master-ds1配置数据库连接信息ds0:type: com.alibaba.druid.pool.DruidDataSourcedriver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://192.168.26.128:3306/myslave?useSSL=false&useUnicode=true&characterEncoding=utf-8username: rootpassword: 123456maxPoolSize: 100minPoolSize: 5ds1:type: com.alibaba.druid.pool.DruidDataSourcedriver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://192.168.26.129:3306/myslave?useSSL=false&useUnicode=true&characterEncoding=utf-8username: rootpassword: 123456maxPoolSize: 100minPoolSize: 5#配置默认数据源ds1sharding:# 默认数据源,主要用于写,注意一定要配置读写分离;如果不配置就会把三个节点都当作从slave节点,新增,修改和删除会出错。default-data-source-name: ds0# 配置分表规则 --》单数存储在user1中,偶数存放在user0中tables:# 逻辑表名 userorder:key-generator:# 主键 雪花算法需要修改column: idtype: SNOWFLAKE# collect 的作用是补0 order_2021_01actual-data-nodes: ds0.order_2021${(1..3).collect{t->t.toString().padLeft(2,'0')}}table-strategy:inline:sharding-column: yearmonth  # 分片字段algorithm-expression: order_${yearmonth}  # 分片算法表达式

编写业务代码
实体类

@Data
public class Order {private Long id;private String ordernumber;private Long userid;private String yearmonth;private Date createTime;
}

mapper
由于我们使用yearmonth进行分片,所以我们插入数据时必须带上该属性,如果不带的话则会插入到所有表中。

@Mapper
public interface OrderMapper {@Insert("insert into order(ordernumber,userid,create_time,yearmonth) values(#{ordernumber},#{userid},#{createTime},#{yearmonth})")void addUserOrder(Order order);@Select("select count(1) from order")Integer count();}

测试
可以看到将yearmonth设置为202102后,将该条数据插入到order_202102表中。

 @Testvoid order() {Order order = new Order();order.setUserid(1L);order.setOrdernumber("123");order.setCreateTime(new Date());order.setYearmonth("202102");orderMapper.addUserOrder(order);}

分布式事务处理

在处理事务的时候,如果发生错误,我们需要进行数据的回滚,确保数据的一致性。sharding jdbc 也提供了相对应的方法。
首先需要添加相关依赖

 <dependency><groupId>io.shardingsphere</groupId><artifactId>sharding-transaction-spring-boot-starter</artifactId><version>3.1.0</version></dependency>
     // 分布式事务回滚@ShardingTransactionType(TransactionType.XA)//单库 事务回滚@Transactional(rollbackFor = Exception.class)public int saveUserOrder(User user, Order order) {userMapper.addUser(user);//int a = 1 / 0;orderMapper.addUserOrder(order);return 1;}

如果是单数据库,我们可以使用Transactional注解进行事务的回滚;
如果是微服务架构,我们则可以使用ShardingTransactionType注解处理;

Spring boot + Sharding JDBC 分库分表 及 分布式事务处理相关推荐

  1. SSM项目引入sharding JDBC进行分表

    SSM项目引入sharding JDBC进行分表 注意点: 本次集成sharing-jdbc 4.1.1,由于各个版本差别比较大,配置方式差别也特别大,请根据官方文档进行配置! 官方配置路径:http ...

  2. 强!分库分表与分布式数据库技术选项分析

    最近经常被问到分库分表与分布式数据库如何选择,网上也有很多关于中间件+传统关系数据库(分库分表)与NewSQL分布式数据库的文章,但有些观点与判断是我觉得是偏激的,脱离环境去评价方案好坏其实有失公允. ...

  3. ShardingSphere JDBC 分库分表 读写分离 数据加密

    简介 在上篇文章中,在本地搭建了运行环境,本地来体验下ShardingSphere JDBC的三个功能:分库分表.读写分离.数据加密 示例运行 首先把概念先捋一捋,参考下面的文档: 数据分片 读写分离 ...

  4. Netty游戏服务器实战开发(11):Spring+mybatis 手写分库分表策略(续)

    在大型网络游戏中,传统的游戏服务器无法满足性能上的需求.所以有了分布式和微服务新起,在传统web服务器中,我们保存用户等信息基本都是利用一张单表搞定,但是在游戏服务器中,由于要求比较高,我们不能存在大 ...

  5. 使用sharding做分库分表,使用jpa,发生的save不报错,数据库缺插不进去数据的问题

    先讲讲问题的诞生,我们项目起初没有引进 sharding分库,而是在项目上线前,才做的分库分表.也就是之前的业务都写好的,所以知道业务代码没有任何问题. 然后引入 sharding 的相关的依赖以后, ...

  6. ShardingShpere分库分表5-ShardingSphere分布式事务详解

    文章目录 一.ShardingJDBC分布式事务快速上手 LOCAL本地事务 XA事务快速上手 BASE柔性事务快速上手 seata部署方式: 客户端使用Base事务 二.分布式事务原理详解 XA事务 ...

  7. 【预告】千亿数据的潘多拉魔盒:从分库分表到分布式数据库

    近年来,随着国内互联网行业的加速发展,以及摩尔定律的实效,千亿数据的潘多拉魔盒早已打开,传统的开源/商业关系数据库早已遇到了容量的瓶颈.而容量告警则不仅意味着业务发展收到影响,同时对现有系统的稳定性和 ...

  8. mysql sharding 方案_mysql sharding 方案 分库分表(sharding)系列(4)

    图1. Sharding实现层面与相关框架/产品 在DAO层实现 当团队决定自行实现sharding的时候,DAO层可能是嵌入sharding逻辑的首选位置,因为在这个层面上,每一个DAO的方法都明确 ...

  9. MySQL数据库性能优化--数据分库分表

    目录 前言 1.什么时候需要分库分表? 1.1.第一次改造 1.2.分库分表的必要性 1.3.第二次改造 2.分库分表应该怎么分? 3.垂直分库会带来哪些问题? 3.1.跨库的关联查询 3.2.分布式 ...

最新文章

  1. Oracle PL/SQL编程之基础
  2. ALV中动态内表+行转化为列
  3. boost::histogram::detail::argument_traits用法的测试程序
  4. 在User Control 中使用 CustomValidator
  5. cpp [Error] reference to ‘count‘ is ambiguous(全局变量的使用模糊不清)
  6. Oracle中insert into select和select into的区别
  7. 自然语言处理系列-1.什么是NLP?
  8. selenium问题记录
  9. co.js异步回调原理理解
  10. 白话java_白话Java
  11. 16.微信登入与授权
  12. 归并算法 merge
  13. 硬盘分区故障修复全攻略
  14. 【学习周记】学习之路,任重而道远
  15. ziheng -接小球游戏
  16. 陌陌八成营收靠直播 直播行业已进入两极分化
  17. Android单应用开多进程与单进程跑多应用
  18. 一个生日微信小程序 生日动画_生日当天发朋友圈的文案 生日快乐微信小句子...
  19. 森林防火远程监控解决方案,再隐秘的角落也难逃天眼
  20. 怎样写一个简单的操作系统?

热门文章

  1. windows10 系统中,双屏下,设置各自屏的任务栏显示各自显示器中的任务。
  2. 【耀扬表情包语音包】
  3. Maven2的相关知识[zt]
  4. 使用Intrinsics优化
  5. 高洛峰2015年新版视频发布
  6. mysql数据库中邮箱的属性_MySQL——数据库的操作、属性
  7. 「中国好SaaS」重装升级,真正以用户视角,发现SaaS好项目
  8. 企业微信三方开发:注册企业微信服务商
  9. 知路,然后智行远;懂行,所以万业兴
  10. R语言使用lm函数构建简单线性回归模型(建立线性回归模型)、拟合回归直线、可视化散点图并添加简单线性回归直线、添加模型拟合值数据点、添加拟合值点和实际数据点之间的线段表示残差大小、col参数自定义设置