【SpringBoot 实战】整合 sharding-jdbc+mybatis

本贴最后更新于 2190 天前,其中的信息可能已经东海扬尘

背景介绍

如果你的系统需要提高并发,那么你需要进行分库,如果你的系统需要支持海量数据,那么你需要进行分表。分库分表之后,应用这边如何才能做到跟单库单表一样简单。有很多开源软件来支持分库分表,现在比较常用的是 sharding-jdbc,mycat 框架。今天来讲讲 sharding-jdbc,示例实现了:数据分片、读写分离、数据分片 + 读写分离、数据治理的功能。

整体项目

imagepng
说明:
数据分片:两个数据库 uc0、uc1 每个数据库两种表 user0、user1
读写分离:一个主库,一个从库
数据分片 + 读写分离:两个主库、两个从库、每个库里存在两种表

pom 配置

<dependency>
	<groupId>org.mybatis.spring.boot</groupId>
	<artifactId>mybatis-spring-boot-starter</artifactId>
	<version>1.3.2</version>
</dependency>
<!--  使用数据治理需要加入 -->
<dependency>
	<groupId>io.shardingsphere</groupId>
	<artifactId>sharding-orchestration-reg-zookeeper-curator</artifactId>
	<version>${sharding-sphere.version}</version>
</dependency>
<dependency>
	<groupId>io.shardingsphere</groupId>
	<artifactId>sharding-jdbc-spring-boot-starter</artifactId>
	<version>${sharding-sphere.version}</version>
</dependency>

核心代码

UserService:为 service 接口。
UserServiceImpl:为 service 实现类。
UserDao:

@Mapper
public interface UserDao {

  User getById(Long id);

 void insert(User user);

 void update(User user);

}

ShardingJdbcApplicationTests:为测试类。

配置

UserDao.xml

<?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.cimu.shardingjdbc.mapper.UserDao">

  <resultMap id="BaseResultMap" type="com.cimu.shardingjdbc.entity.User" >
	  <id column="id" property="id" jdbcType="INTEGER" />
	  <result column="real_name" property="realName" jdbcType="VARCHAR" />
	  <result column="mobile" property="mobile" jdbcType="VARCHAR" />
	  <result column="password" property="password" jdbcType="VARCHAR" />
  </resultMap>

  <sql id="Base_Column_List">
	  id, real_name, mobile, password
  </sql>

  <select id="getById" resultMap="BaseResultMap" parameterType="java.lang.Long">
	  select
	  <include refid="Base_Column_List" />
	  from user
	  where id=#{id}
  </select>

  <insert id="insert" parameterType="com.cimu.shardingjdbc.entity.User" useGeneratedKeys="true" keyProperty="id">
	  insert into user
	  (
	  `id`,
	  `real_name`,
	  `mobile`,
	  `create_time`,
	  `update_time`,
	  `del_flag`
	  )
	  values
	  (
	  #{id},
	  #{realName},
	  #{mobile},
	  #{createTime},
	  #{updateTime},
	  #{delFlag}
	  )
  </insert>

  <update id="update" parameterType="com.cimu.shardingjdbc.entity.User">
	  update user
	  <set>
		  <if test="realName != null ">`real_name` = #{realName},</if>
		  <if test="mobile != null ">`mobile` = #{mobile},</if>
		  <if test="createTime != null ">`create_time` = #{createTime},</if>
		  <if test="updateTime != null ">`update_time` = #{updateTime},</if>
		  <if test="delFlag != null ">`del_flag` = #{delFlag},</if>
	  </set>
	  where id = #{id}
  </update>

</mapper>

application.properties

##==========================只支持分片配置=====start======================================
##数据源的名称,多个以短号隔开
#sharding.jdbc.datasource.names=uc0,uc1
##数据源的配置
#sharding.jdbc.datasource.uc0.type=com.zaxxer.hikari.HikariDataSource
#sharding.jdbc.datasource.uc0.driver-class-name=com.mysql.jdbc.Driver
#sharding.jdbc.datasource.uc0.jdbcUrl=jdbc:mysql://127.0.0.1:3306/uc0?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=Asia/Shanghai
#sharding.jdbc.datasource.uc0.username=root
#sharding.jdbc.datasource.uc0.password=
##数据源的配置
#sharding.jdbc.datasource.uc1.type=com.zaxxer.hikari.HikariDataSource
#sharding.jdbc.datasource.uc1.driver-class-name=com.mysql.jdbc.Driver
#sharding.jdbc.datasource.uc1.jdbcUrl=jdbc:mysql://127.0.0.1:3306/uc1?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=Asia/Shanghai
#sharding.jdbc.datasource.uc1.username=root
#sharding.jdbc.datasource.uc1.password=
##默认的数据库分片策略,如果没有指定具体某个数据库的分片策略,那么使用默认分片策略
#sharding.jdbc.config.sharding.default-database-strategy.inline.sharding-column=id
#sharding.jdbc.config.sharding.default-database-strategy.inline.algorithm-expression=uc$->{id % 2}
##id.intdiv(2) % 2 : 根据id进行分片,先对数据库数量进行取余,在对表数量进行取模。这个作用是让数据可以更加均匀的分布在不同表中。
##$->{0..1}  是行表达式标识符,uc$->{0..1}表示uc0,uc1
#sharding.jdbc.config.sharding.tables.user.actual-data-nodes=uc$->{0..1}.user$->{0..1}
#sharding.jdbc.config.sharding.tables.user.table-strategy.inline.sharding-column=id
#sharding.jdbc.config.sharding.tables.user.table-strategy.inline.algorithm-expression=user$->{id.intdiv(2) % 2}
##是否开启SQL显示,默认值: false
#sharding.jdbc.config.sharding.props.sql.show=true
##==========================只支持分片配置======end=====================================

##==========================只支持读写分离配置=====start======================================
##数据源的名称,多个以短号隔开
#sharding.jdbc.datasource.names=ucmaster,ucslave0
##数据源的配置
#sharding.jdbc.datasource.ucmaster.type=com.zaxxer.hikari.HikariDataSource
#sharding.jdbc.datasource.ucmaster.driver-class-name=com.mysql.jdbc.Driver
#sharding.jdbc.datasource.ucmaster.jdbcUrl=jdbc:mysql://127.0.0.1:3306/uc0?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=Asia/Shanghai
#sharding.jdbc.datasource.ucmaster.username=root
#sharding.jdbc.datasource.ucmaster.password=
##数据源的配置
#sharding.jdbc.datasource.ucslave0.type=com.zaxxer.hikari.HikariDataSource
#sharding.jdbc.datasource.ucslave0.driver-class-name=com.mysql.jdbc.Driver
#sharding.jdbc.datasource.ucslave0.jdbcUrl=jdbc:mysql://127.0.0.1:3306/uc1?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=Asia/Shanghai
#sharding.jdbc.datasource.ucslave0.username=root
#sharding.jdbc.datasource.ucslave0.password=
##从库负载均衡算法类型,可选值:ROUND_ROBIN,RANDOM。若`load-balance-algorithm-class-name`存在则忽略该配置
#sharding.jdbc.config.masterslave.load-balance-algorithm-type=round_robin
#sharding.jdbc.config.masterslave.name=ms
##主库数据源名称
#sharding.jdbc.config.masterslave.master-data-source-name=ucmaster
##从库数据源名称列表,多个以逗号隔开
#sharding.jdbc.config.masterslave.slave-data-source-names=ucslave0
##是否开启SQL显示,默认值: false
#sharding.jdbc.config.masterslave.props.sql.show=true
##==========================只支持读写分离配置======end=====================================

##==========================数据分片+读写分离配置=====start======================================
#数据源的名称,多个以短号隔开
sharding.jdbc.datasource.names=master0,master1,uc0slave0,uc1slave0
#master数据源的配置
sharding.jdbc.datasource.master0.type=com.zaxxer.hikari.HikariDataSource
sharding.jdbc.datasource.master0.driver-class-name=com.mysql.jdbc.Driver
sharding.jdbc.datasource.master0.jdbcUrl=jdbc:mysql://127.0.0.1:3306/uc0?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=Asia/Shanghai
sharding.jdbc.datasource.master0.username=root
sharding.jdbc.datasource.master0.password=
#slave数据源的配置
sharding.jdbc.datasource.uc0slave0.type=com.zaxxer.hikari.HikariDataSource
sharding.jdbc.datasource.uc0slave0.driver-class-name=com.mysql.jdbc.Driver
sharding.jdbc.datasource.uc0slave0.jdbcUrl=jdbc:mysql://127.0.0.1:3306/uc0slave0?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=Asia/Shanghai
sharding.jdbc.datasource.uc0slave0.username=root
sharding.jdbc.datasource.uc0slave0.password=
#master数据源的配置
sharding.jdbc.datasource.master1.type=com.zaxxer.hikari.HikariDataSource
sharding.jdbc.datasource.master1.driver-class-name=com.mysql.jdbc.Driver
sharding.jdbc.datasource.master1.jdbcUrl=jdbc:mysql://127.0.0.1:3306/uc1?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=Asia/Shanghai
sharding.jdbc.datasource.master1.username=root
sharding.jdbc.datasource.master1.password=
#slave数据源的配置
sharding.jdbc.datasource.uc1slave0.type=com.zaxxer.hikari.HikariDataSource
sharding.jdbc.datasource.uc1slave0.driver-class-name=com.mysql.jdbc.Driver
sharding.jdbc.datasource.uc1slave0.jdbcUrl=jdbc:mysql://127.0.0.1:3306/uc1slave0?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=Asia/Shanghai
sharding.jdbc.datasource.uc1slave0.username=root
sharding.jdbc.datasource.uc1slave0.password=

##默认的数据库分片策略,如果没有指定具体某个数据库的分片策略,那么使用默认分片策略
sharding.jdbc.config.sharding.default-database-strategy.inline.sharding-column=id
sharding.jdbc.config.sharding.default-database-strategy.inline.algorithm-expression=aa$->{id % 2}

#id.intdiv(2) % 2 : 根据id进行分片,先对数据库数量进行取余,在对表数量进行取模。这个作用是让数据可以更加均匀的分布在不同表中。
#$->{0..1}  是行表达式标识符,aa$->{0..1}表示aa0,aa1
sharding.jdbc.config.sharding.tables.user.actual-data-nodes=aa$->{0..1}.user$->{0..1}
sharding.jdbc.config.sharding.tables.user.table-strategy.inline.sharding-column=id
sharding.jdbc.config.sharding.tables.user.table-strategy.inline.algorithm-expression=user$->{id.intdiv(2) % 2}
sharding.jdbc.config.sharding.tables.user.key-generator-column-name=id

#这里的aa0需要和上面的default-database-strategy.inline.algorithm-expression,sharding.tables.user.actual-data-nodes的对应
sharding.jdbc.config.sharding.master-slave-rules.aa0.master-data-source-name=master0
sharding.jdbc.config.sharding.master-slave-rules.aa0.slave-data-source-names=uc0slave0
sharding.jdbc.config.sharding.master-slave-rules.aa1.master-data-source-name=master1
sharding.jdbc.config.sharding.master-slave-rules.aa1.slave-data-source-names=uc1slave0
##==========================数据分片+读写分离配置======end=====================================

##==========================数据治理配置======start===================================
sharding.jdbc.config.sharding.orchestration.name=demo-orchestration
#本地配置是否覆盖注册中心配置。如果可覆盖,每次启动都以本地配置为准
sharding.jdbc.config.sharding.orchestration.overwrite=true
sharding.jdbc.config.sharding.orchestration.registry.server-lists=xxxx:2181
sharding.jdbc.config.sharding.orchestration.registry.namespace=demo-orchestration
##==========================数据治理配置======end=====================================

mybatis.typeAliasesPackage=com.cimu.shardingjdbc.entity
mybatis.mapperLocations=classpath:mapper/*.xml

user.sql

CREATE TABLE `user0` (
  `id` BIGINT(64) NOT NULL PRIMARY KEY COMMENT '主键ID',
  `real_name` VARCHAR(100) DEFAULT NULL COMMENT '真实名称',
  `mobile` VARCHAR(11) DEFAULT NULL COMMENT '手机号码',
  `password` VARCHAR(20) DEFAULT NULL COMMENT '密码',
  `create_time` DATETIME DEFAULT NULL COMMENT '创建日期',
  `update_time` DATETIME DEFAULT NULL COMMENT '修改日期',
  `del_flag` CHAR(1) NOT NULL DEFAULT '0' COMMENT '删除标记 1:删除;0:未删除'
)COMMENT='用户表';

CREATE TABLE `user1` (
  `id` BIGINT(64) NOT NULL PRIMARY KEY COMMENT '主键ID',
  `real_name` VARCHAR(100) DEFAULT NULL COMMENT '真实名称',
  `mobile` VARCHAR(11) DEFAULT NULL COMMENT '手机号码',
  `password` VARCHAR(20) DEFAULT NULL COMMENT '密码',
  `create_time` DATETIME DEFAULT NULL COMMENT '创建日期',
  `update_time` DATETIME DEFAULT NULL COMMENT '修改日期',
  `del_flag` CHAR(1) NOT NULL DEFAULT '0' COMMENT '删除标记 1:删除;0:未删除'
)COMMENT='用户表';

源码地址

  • B3log

    B3log 是一个开源组织,名字来源于“Bulletin Board Blog”缩写,目标是将独立博客与论坛结合,形成一种新的网络社区体验,详细请看 B3log 构思。目前 B3log 已经开源了多款产品:SymSoloVditor思源笔记

    1063 引用 • 3454 回帖 • 191 关注
  • Spring

    Spring 是一个开源框架,是于 2003 年兴起的一个轻量级的 Java 开发框架,由 Rod Johnson 在其著作《Expert One-On-One J2EE Development and Design》中阐述的部分理念和原型衍生而来。它是为了解决企业应用开发的复杂性而创建的。框架的主要优势之一就是其分层架构,分层架构允许使用者选择使用哪一个组件,同时为 JavaEE 应用程序开发提供集成的框架。

    943 引用 • 1460 回帖 • 1 关注
  • MyBatis

    MyBatis 本是 Apache 软件基金会 的一个开源项目 iBatis,2010 年这个项目由 Apache 软件基金会迁移到了 google code,并且改名为 MyBatis ,2013 年 11 月再次迁移到了 GitHub。

    170 引用 • 414 回帖 • 387 关注

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...
  • hefeng 1

    文章结尾处的关注公众号再回复有点不好吧,这和以前那些论坛“回复后看见”有啥区别?另外这样的文章(我不评价文章内容,主要指的就是文章结尾处的“牛皮癣”广告)发在自己博客没问题,但是同步到社区就不太好了吧,@88250 @Vanessa 能不能编辑整理一下,不然太影响社区体验了。

    我相信肯定不只有我一个人这么看,大家应该都会觉得这浏览体验很糟糕。文章作者想让人关注他这没错,但是社区如果随处都是这样的内容会严重影响社区将来的发展的。

    1 回复
  • 其他回帖
  • chaigx
    作者

    此木的博客 http://www.chaiguanxin.com/
    不冲突的,示例里面有一个 数据分片+读写分离配置 可以看看

  • 88250 1 1 赞同

    感谢帮忙考虑,这是一个对我来说有点“小纠结”的事情。一方面我不想对文章作者的内容做太多干预,因为我想大家都不大喜欢别人去修改自己的作品(建议或者修缮可以,但是改掉特意留的内容就肯定很难接受了);而另一方面,随着社区的逐步发展,确实也出现了越来越多这样的现象,大多是出于推广引流目的,但只要不是违反社区参与规则的行为,我们都是接受的。但“接受”并不意味着“受欢迎”,我个人对这样的行为也是不大赞同的。

    @chaigx 楼主,你的所有帖子我刚刚都编辑了一次,去掉了文章结尾处的推广二维码。以后如果你还会同步文章过来的话,请不要带二维码,留文字是一个比较折中的方案,既不会太影响浏览者的视觉体验,也达到了你推广的目的,谢谢!

  • yizhishang

    请问下楼主:针对同一个表的分库分表和读写主从配置,是不是只能选择一种,两者针对同一个表的是冲突的吗

    1 回复
chaigx
欢迎关注我的公众号:程序之声。有些文章没办法同步过来,访问个人博客:http://www.chaiguanxin.com 杭州