赞
踩
垂直拆分
操作数据库中某张表,把这张表中一部分字段数据存到一张新表里面,再把这张表另一 部分字段数据存到另外一张表里面 例如:将商品基本信息放在一张表,商品详情放在一张表
水平拆分
将一个数据库,拆分为两个相同结构的数据库,存储数据
存储方式
方式一:按id取模方式实现,缺点:不好扩容
方式二:按id分片实现,缺点:因为id连续,热点数据可能会集中到一个数据库
其他思路:大范围按时间分,小范围取模分
分库分表可能出现的问题:
事务一致性问题:单表操作事务执行失败可以回滚,分表之后可能会插入到多条数据库
跨节点关联查询:当查询固定范围的数据也在多个数据库中
主键避重问题:数据库表主键冲突
所以在开发中:数据增加不要立马做水平拆分,首先考虑缓存处理,读写分离,使用索引等
开源分布式数据库中间件解决方案,主要有Sharding-JDBC和Sharding-Proxy
客户端分库分表:以jar包形式放在java应用里,通过Sharding-JDBC去找对应数据,主要作用数据分片,读写分离
服务端分库分表:利用Sharding-Proxy伪装成数据库,分库分表由Sharding-Proxy实现
Sharding-JDBC实现水平分表
创建数据库,按水平分表方式
在数据库创建两张表 course_1 和 course_2
约定规则:如果添加课程 id 是偶数把数据添加 course_1,如果奇数添加到 course_2
创建springboot项目,添加依赖
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter</artifactId>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-test</artifactId>
- </dependency>
- <dependency>
- <groupId>com.alibaba</groupId>
- <artifactId>druid-spring-boot-starter</artifactId>
- <version>1.1.20</version>
- </dependency>
- <dependency>
- <groupId>mysql</groupId>
- <artifactId>mysql-connector-java</artifactId>
- </dependency>
- <dependency>
- <groupId>org.apache.shardingsphere</groupId>
- <artifactId>sharding-jdbc-spring-boot-starter</artifactId>
- <version>4.0.0-RC1</version>
- </dependency>
- <dependency>
- <groupId>com.baomidou</groupId>
- <artifactId>mybatis-plus-boot-starter</artifactId>
- <version>3.0.5</version>
- </dependency>
- <dependency>
- <groupId>org.projectlombok</groupId>
- <artifactId>lombok</artifactId>
- </dependency>
实体类
- @Data
- public class Course {
- private Long cid;
- private String cname;
- private Long userId;
- private String cstatus;
- }
mapper层
- @Repository
- public interface CourseMapper extends BaseMapper<Course> {
- }
启动类加注解
@MapperScan("com.lzq.mapper")
配置 Sharding-JDBC 分片策略
在配置文件中配置
- # shardingjdbc 分片策略
- # 配置数据源,给数据源起名称
- spring.shardingsphere.datasource.names=m1
-
- # 一个实体类对应两张表,覆盖
- spring.main.allow-bean-definition-overriding=true
-
- #配置数据源具体内容,包含连接池,驱动,地址,用户名和密码
- spring.shardingsphere.datasource.m1.type=com.alibaba.druid.pool.DruidDataSource
- spring.shardingsphere.datasource.m1.driver-class-name=com.mysql.cj.jdbc.Driver
- spring.shardingsphere.datasource.m1.url=jdbc:mysql://localhost:3306/sharding?serverTimezone=GMT%2B8
- spring.shardingsphere.datasource.m1.username=root
- spring.shardingsphere.datasource.m1.password=root
- #指定 course 表分布情况,配置表在哪个数据库里面,表名称都是什么 m1.course_1 ,m1.course_2
- spring.shardingsphere.sharding.tables.course.actual-data-nodes=m1.course_$->{1..2}
- # 指定 course 表里面主键 cid 生成策略 SNOWFLAKE 雪花算法
- spring.shardingsphere.sharding.tables.course.key-generator.column=cid
- spring.shardingsphere.sharding.tables.course.key-generator.type=SNOWFLAKE
- # 指定分片策略 约定 cid 值偶数添加到 course_1 表,如果 cid 是奇数添加到 course_2表
- spring.shardingsphere.sharding.tables.course.table-strategy.inline.sharding-column=cid
- spring.shardingsphere.sharding.tables.course.table-strategy.inline.algorithm-expression=course_$->{cid % 2 + 1}
- # 打开 sql 输出日志
- spring.shardingsphere.props.sql.show=true
测试
- @SpringBootTest
- class ShardingJdbcApplicationTests {
- @Autowired
- private CourseMapper courseMapper;
- @Test
- void add() {
- Course course = new Course();
- course.setCname("java");
- course.setUserId(10l);
- course.setCstatus("normal");
- courseMapper.insert(course);
- }
- @Test
- public void find(){
- QueryWrapper<Course> wrapper = new QueryWrapper<>();
- wrapper.eq("cid",714887289653690369l);
- Course course = courseMapper.selectOne(wrapper);
- System.out.println(course);
- }
- }
springboot版本不同可能会报错,由于一个实体类对应两个数据库,在配置文件添加
spring.main.allow-bean-definition-overriding=true
水平分库
创建两个数据库,每个数据库里创建两个表分别为course_1 和 course_2
约定分片规则:userid为偶数加入第一个数据库,cid为偶数放入course_1表
修改之前代码:配置分片规则,在配置文件中加入
- # 配置数据源,给数据源起名称,
- # 水平分库,配置两个数据源
- spring.shardingsphere.datasource.names=m1,m2
-
- # 一个实体类对应两张表,覆盖
- spring.main.allow-bean-definition-overriding=true
-
- #配置第一个数据源具体内容,包含连接池,驱动,地址,用户名和密码
- spring.shardingsphere.datasource.m1.type=com.alibaba.druid.pool.DruidDataSource
- spring.shardingsphere.datasource.m1.driver-class-name=com.mysql.cj.jdbc.Driver
- spring.shardingsphere.datasource.m1.url=jdbc:mysql://localhost:3306/edu_db_1?serverTimezone=GMT%2B8
- spring.shardingsphere.datasource.m1.username=root
- spring.shardingsphere.datasource.m1.password=root
-
- #配置第二个数据源具体内容,包含连接池,驱动,地址,用户名和密码
- spring.shardingsphere.datasource.m2.type=com.alibaba.druid.pool.DruidDataSource
- spring.shardingsphere.datasource.m2.driver-class-name=com.mysql.cj.jdbc.Driver
- spring.shardingsphere.datasource.m2.url=jdbc:mysql://localhost:3306/edu_db_2?serverTimezone=GMT%2B8
- spring.shardingsphere.datasource.m2.username=root
- spring.shardingsphere.datasource.m2.password=root
-
- #指定数据库分布情况,数据库里面表分布情况
- # m1 m2 course_1 course_2
- spring.shardingsphere.sharding.tables.course.actual-data-nodes=m$->{1..2}.course_$->{1..2}
-
- # 指定 course 表里面主键 cid 生成策略 SNOWFLAKE
- spring.shardingsphere.sharding.tables.course.key-generator.column=cid
- spring.shardingsphere.sharding.tables.course.key-generator.type=SNOWFLAKE
-
- # 指定表分片策略 约定 cid 值偶数添加到 course_1 表,如果 cid 是奇数添加到course_2 表
- spring.shardingsphere.sharding.tables.course.table-strategy.inline.sharding.column=cid
- spring.shardingsphere.sharding.tables.course.table-strategy.inline.algorithm.expression=course_$->{cid % 2 + 1}
-
- # 指定数据库分片策略 约定 user_id 是偶数添加 m1,是奇数添加 m2
- #spring.shardingsphere.sharding.default-database-strategy.inline.sharding.column=user_id
- #spring.shardingsphere.sharding.default-database-strategy.inline.algorithm.expression=m$->{user_id % 2 + 1}
- #写法二 对具体表有固定规则
- spring.shardingsphere.sharding.tables.course.database-strategy.inline.sharding-column=user_id
- spring.shardingsphere.sharding.tables.course.database-strategy.inline.algorithm-expression=m$->{user_id % 2 + 1}
测试同上
垂直分库:
专库专用,查询用户信息时去用户数据库查用户表
创建数据库user_db,创建用户信息表t_user
创建实体类与mapper
- @Data
- @TableName(value = "t_user") //指定对应表
- public class User {
- private Long userId;
- private String username;
- private String ustatus;
- }
-
- @Repository
- public interface UserMapper extends BaseMapper<User> {
- }
配置文件添加
- # 配置数据源,给数据源起名称
- spring.shardingsphere.datasource.names=m1,m2,m0
- .....
- #配置第三个数据源具体内容,包含连接池,驱动,地址,用户名和密码
- spring.shardingsphere.datasource.m0.type=com.alibaba.druid.pool.DruidDataSource
- spring.shardingsphere.datasource.m0.driver-class-name=com.mysql.cj.jdbc.Driver
- spring.shardingsphere.datasource.m0.url=jdbc:mysql://localhost:3306/user_db?serverTimezone=GMT%2B8
- spring.shardingsphere.datasource.m0.username=root
- spring.shardingsphere.datasource.m0.password=root
-
- # 配置 user_db 数据库里面 t_user 专库专表
- spring.shardingsphere.sharding.tables.t_user.actual-data-nodes=m$->{0}.t_user
-
- # 指定 course 表里面主键 cid 生成策略 SNOWFLAKE
- spring.shardingsphere.sharding.tables.t_user.key-generator.column=user_id
- spring.shardingsphere.sharding.tables.t_user.key-generator.type=SNOWFLAKE
公共表
存储固定数据,很少发生变化,查询时需要进行关联,例如用户的状态表,字典等
在多个数据需中都创建相同结构的表
在配置文件中添加
- # 配置公共表
- spring.shardingsphere.sharding.broadcast-tables=t_udict
- spring.shardingsphere.sharding.tables.t_udict.key-generator.column=dictid
- spring.shardingsphere.sharding.tables.t_udict.key-generator.type=SNOWFLAKE
当有修改操作时,会向多个数据库中t_udict表进行修改
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。