Sharding-JDBC——分库分表+读写分离

2024-04-10 19:08

本文主要是介绍Sharding-JDBC——分库分表+读写分离,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一、简介

定位为轻量级Java框架,在Java的JDBC层提供的额外服务。 它使用客户端直连数据库,以jar包形式提供服务,无需额外部署和依赖,可理解为增强版的JDBC驱动,完全兼容JDBC和各种ORM框架。

  • 适用于任何基于JDBC的ORM框架,如:JPA, Hibernate, Mybatis, Spring JDBC Template或直接使用JDBC。
  • 支持任何第三方的数据库连接池,如:DBCP, C3P0, BoneCP, Druid, HikariCP等。
  • 支持任意实现JDBC规范的数据库。目前支持MySQL,Oracle,SQLServer,PostgreSQL以及任何遵循SQL92标准的数据库。
    在这里插入图片描述
    ——摘自官方网站

二、数据分片——水平切分

1. 创建数据库和表
CREATE DATABASE `order-db1`;CREATE TABLE `t_order_1` (`oid` bigint(20) NOT NULL COMMENT '订单id',`comment` varchar(100) CHARACTER  DEFAULT NULL COMMENT '订单备注',`user_id` bigint(20) DEFAULT NULL COMMENT '用户id'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;CREATE TABLE `t_order_2` (`oid` bigint(20) NOT NULL COMMENT '订单id',`comment` varchar(100) CHARACTER DEFAULT NULL COMMENT '订单备注',`user_id` bigint(20) DEFAULT NULL COMMENT '用户id'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;

根据订单号的奇偶对数据进行分片。

2. java代码

pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.3.5.RELEASE</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.example</groupId><artifactId>sharding-jdbc-demo</artifactId><version>0.0.1-SNAPSHOT</version><name>sharding-jdbc-demo</name><description>Demo project for Spring Boot</description><properties><java.version>1.8</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><!--不能使用druid-spring-boot-starter--><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.1.21</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.3.2</version></dependency><dependency><groupId>org.apache.shardingsphere</groupId><artifactId>sharding-jdbc-spring-boot-starter</artifactId><version>4.1.1</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><configuration><excludes><exclude><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></exclude></excludes></configuration></plugin></plugins></build>
</project>

application.yml:

spring:shardingsphere:datasource:names: d0d0:type: com.alibaba.druid.pool.DruidDataSourcedriverClassName: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/order-db1?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf-8username: rootpassword: rootsharding:tables:t_order:actualDataNodes: d0.t_order_$->{1..2}#如果添加订单的id是偶数把数据添加t_order_1,如果奇数添加到t_order_2tableStrategy:inline:shardingColumn: oidalgorithmExpression: t_order_$->{oid % 2 + 1}keyGenerator:type: SNOWFLAKEcolumn: oidprops:sql.show: true# 一个实体类对应两张表,覆盖main:allowBeanDefinitionOverriding: true

主启动类:

@SpringBootApplication
@MapperScan("com.example.shardingJdbcDemo.mapper")
public class ShardingJdbcDemoApplication {public static void main(String[] args) {SpringApplication.run(ShardingJdbcDemoApplication.class, args);}
}

实体类:

@Data
@TableName("t_order")
public class Order {private Long oid;private String comment;private Long userId;
}

注意:加上@TableName注解
Mapper接口:

@Repository
public interface OrderMapper extends BaseMapper<Order> {
}

测试类:

@RunWith(SpringRunner.class)
@SpringBootTest
class ShardingJdbcDemoApplicationTests {@Autowiredprivate OrderMapper orderMapper;/*** 测试添加订单*/@Testpublic void addOrder() {for (int i = 1; i <= 10; i++) {Order order = new Order();//使用雪花算法生产id//order.setOid((long) i);order.setComment("course" + i);order.setUserId((long) i);orderMapper.insert(order);}}/*** 测试查询订单*/@Testpublic void getOrders() {List<Order> orders = orderMapper.selectList(null);System.out.println(orders.size());}
}

三、数据分片——垂直切分

1. 创建数据库和表
CREATE DATABASE `user-db`;CREATE TABLE `user-db`.t_user (uid BIGINT NOT NULL COMMENT '用户id',uname varchar(100) NOT NULL COMMENT '用户姓名'
)
ENGINE=InnoDB
DEFAULT CHARSET=utf8mb4
COLLATE=utf8mb4_general_ci;

将用户表存放在order-db的t_user表中

2. java代码

application.yml

spring:shardingsphere:datasource:names: d0, d1d0:type: com.alibaba.druid.pool.DruidDataSourcedriverClassName: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/order-db1?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf-8username: rootpassword: rootd1:type: com.alibaba.druid.pool.DruidDataSourcedriverClassName: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/user-db?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf-8username: rootpassword: rootsharding:tables:t_order:actualDataNodes: d$->{0}.t_order_$->{1..2}#如果添加课程id是偶数把数据添加course_1,如果奇数添加到course_2tableStrategy:inline:shardingColumn: oidalgorithmExpression: t_order_$->{oid % 2 + 1}keyGenerator:type: SNOWFLAKEcolumn: oid#配置user-db数据库里面t_user专库专表t_user:actualDataNodes: d$->{1}.t_userprops:sql.show: true# 一个实体类对应两张表,覆盖main:allowBeanDefinitionOverriding: true

增加分库配置

User实体类:

package com.example.shardingJdbcDemo.entity;import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;/*** @author Castle* @Date 2021/4/26 8:49*/
@Data
@TableName("t_user")
public class User {private Long uid;private String uname;
}

UserMapper:

@Repository
public interface UserMapper extends BaseMapper<User> {
}

测试类:

    /*** 测试添加用户*/@Testpublic void addUser() {for (int i = 1; i <= 10; i++) {User user = new User();user.setUid((long) i);user.setUname("user" + i);userMapper.insert(user);}}

四、公共表

1. 建表

在order-db1和user-db中分别创建字典表:

CREATE TABLE t_dict (tid BIGINT NOT NULL COMMENT '字典id',tname varchar(100) NOT NULL COMMENT '字典名称',CONSTRAINT t_dict_pk PRIMARY KEY (tid)
)
ENGINE=InnoDB
DEFAULT CHARSET=utf8mb4
COLLATE=utf8mb4_general_ci;

字典表的数据将同时存储在2个数据库中

2.代码

修改application.yml:

spring:shardingsphere:datasource:names: d0, d1d0:type: com.alibaba.druid.pool.DruidDataSourcedriverClassName: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/order-db1?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf-8username: rootpassword: rootd1:type: com.alibaba.druid.pool.DruidDataSourcedriverClassName: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/user-db?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf-8username: rootpassword: rootsharding:tables:t_order:actualDataNodes: d$->{0}.t_order_$->{1..2}#如果添加课程id是偶数把数据添加course_1,如果奇数添加到course_2tableStrategy:inline:shardingColumn: oidalgorithmExpression: t_order_$->{oid % 2 + 1}keyGenerator:type: SNOWFLAKEcolumn: oid#配置user-db数据库里面t_user专库专表t_user:actualDataNodes: d$->{1}.t_user#配置公共表broadcast-tables: t_dictprops:sql.show: true# 一个实体类对应两张表,覆盖main:allowBeanDefinitionOverriding: true

实体类:

@Data
@TableName("t_dict")
public class Dict {private Long tid;private String tname;
}

mapper:

@Repository
public interface DictMapper extends BaseMapper<Dict> {
}

测试类:

    /*** 测试添加字典*/@Testpublic void addDict() {for (int i = 1; i <= 10; i++) {Dict dict = new Dict();dict.setTid((long) i);dict.setTname("name" + i);dictMapper.insert(dict);}}

五、 读写分离

参考MySQL(10)——主从复制搭建主从数据库。

主库:192.168.30.132,从库:192.168.30.133
在test库中创建user表:

CREATE TABLE t_course (id BIGINT NOT NULL COMMENT '用户id',name varchar(100) NOT NULL COMMENT '用户姓名'
)insert into t_course values (1,@@hostname);

修改application.yml:

spring:shardingsphere:datasource:names: d0, d1,m0,s0d0:type: com.alibaba.druid.pool.DruidDataSourcedriverClassName: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/order-db1?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf-8username: rootpassword: rootd1:type: com.alibaba.druid.pool.DruidDataSourcedriverClassName: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/user-db?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf-8username: rootpassword: rootm0:type: com.alibaba.druid.pool.DruidDataSourcedriverClassName: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://192.168.30.132:3306/test?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf-8username: rootpassword: roots0:type: com.alibaba.druid.pool.DruidDataSourcedriverClassName: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://192.168.30.133:3306/test?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf-8username: rootpassword: root##配置读写分离masterslave:name: msmaster-data-source-name: m0slave-data-source-names: s0sharding:tables:t_order:actualDataNodes: d$->{0}.t_order_$->{1..2}#如果添加课程id是偶数把数据添加course_1,如果奇数添加到course_2tableStrategy:inline:shardingColumn: oidalgorithmExpression: t_order_$->{oid % 2 + 1}keyGenerator:type: SNOWFLAKEcolumn: oid#配置user-db数据库里面t_user专库专表t_user:actualDataNodes: d$->{1}.t_user#配置读写分离的t_course专库专表t_course:actualDataNodes: m$->{0}.t_course#配置公共表broadcast-tables: t_dictprops:sql.show: true# 一个实体类对应两张表,覆盖main:allowBeanDefinitionOverriding: true

实体类:

@Data
@TableName("t_course")
public class Course {private Long id;private String name;
}

mapper:

@Repository
public interface CourseMapper extends BaseMapper<Course> {
}

测试类:

    /*** 测试添加课程*/@Testpublic void addCourse() {for (int i = 5; i <= 10; i++) {Course course = new Course();course.setId((long) i);course.setName("name" + i);courseMapper.insert(course);}}/*** 测试获取课程*/@Testpublic void getCourse() {QueryWrapper<Course> wrapper = new QueryWrapper<>();wrapper.eq("id", 1L);List<Course> courses = courseMapper.selectList(wrapper);System.out.println(courses.get(0));}

由于建表后的insert语句中的@@hostname,会被主从解析成不同的值。通过查询id为1的值,获取到来自从库的信息:

Course(id=1, name=server4)

这篇关于Sharding-JDBC——分库分表+读写分离的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/891895

相关文章

C#实现文件读写到SQLite数据库

《C#实现文件读写到SQLite数据库》这篇文章主要为大家详细介绍了使用C#将文件读写到SQLite数据库的几种方法,文中的示例代码讲解详细,感兴趣的小伙伴可以参考一下... 目录1. 使用 BLOB 存储文件2. 存储文件路径3. 分块存储文件《文件读写到SQLite数据库China编程的方法》博客中,介绍了文

Mycat搭建分库分表方式

《Mycat搭建分库分表方式》文章介绍了如何使用分库分表架构来解决单表数据量过大带来的性能和存储容量限制的问题,通过在一对主从复制节点上配置数据源,并使用分片算法将数据分配到不同的数据库表中,可以有效... 目录分库分表解决的问题分库分表架构添加数据验证结果 总结分库分表解决的问题单表数据量过大带来的性能

异构存储(冷热数据分离)

异构存储主要解决不同的数据,存储在不同类型的硬盘中,达到最佳性能的问题。 异构存储Shell操作 (1)查看当前有哪些存储策略可以用 [lytfly@hadoop102 hadoop-3.1.4]$ hdfs storagepolicies -listPolicies (2)为指定路径(数据存储目录)设置指定的存储策略 hdfs storagepolicies -setStoragePo

10. 文件的读写

10.1 文本文件 操作文件三大类: ofstream:写操作ifstream:读操作fstream:读写操作 打开方式解释ios::in为了读文件而打开文件ios::out为了写文件而打开文件,如果当前文件存在则清空当前文件在写入ios::app追加方式写文件ios::trunc如果文件存在先删除,在创建ios::ate打开文件之后令读写位置移至文件尾端ios::binary二进制方式

滚雪球学Java(87):Java事务处理:JDBC的ACID属性与实战技巧!真有两下子!

咦咦咦,各位小可爱,我是你们的好伙伴——bug菌,今天又来给大家普及Java SE啦,别躲起来啊,听我讲干货还不快点赞,赞多了我就有动力讲得更嗨啦!所以呀,养成先点赞后阅读的好习惯,别被干货淹没了哦~ 🏆本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,助你一臂之力,带你早日登顶🚀,欢迎大家关注&&收藏!持续更新中,up!up!up!! 环境说明:Windows 10

计算机毕业设计 大学志愿填报系统 Java+SpringBoot+Vue 前后端分离 文档报告 代码讲解 安装调试

🍊作者:计算机编程-吉哥 🍊简介:专业从事JavaWeb程序开发,微信小程序开发,定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事,生活就是快乐的。 🍊心愿:点赞 👍 收藏 ⭐评论 📝 🍅 文末获取源码联系 👇🏻 精彩专栏推荐订阅 👇🏻 不然下次找不到哟~Java毕业设计项目~热门选题推荐《1000套》 目录 1.技术选型 2.开发工具 3.功能

【STM32】SPI通信-软件与硬件读写SPI

SPI通信-软件与硬件读写SPI 软件SPI一、SPI通信协议1、SPI通信2、硬件电路3、移位示意图4、SPI时序基本单元(1)开始通信和结束通信(2)模式0---用的最多(3)模式1(4)模式2(5)模式3 5、SPI时序(1)写使能(2)指定地址写(3)指定地址读 二、W25Q64模块介绍1、W25Q64简介2、硬件电路3、W25Q64框图4、Flash操作注意事项软件SPI读写W2

分库分表核心理念

文章目录 分库,分表,分库分表什么时候分库?什么时候分表?什么时候既分库又分表?横向拆分 & 纵向拆分 分表算法Range 范围Hash 取模一致性 Hash斐波那契散列 严格雪崩标准(SAC)订单分库分表实战全局 ID 的生成UUID基于某个单表做自增主键雪花算法时间回拨问题 分库分表迁移停机迁移方案双写迁移方案 分库分表带来的问题参考 & 推荐文章 分库,分表,分库分表

Hibernate框架中,使用JDBC语法

/*** 调用存储过程* * @param PRONAME* @return*/public CallableStatement citePro(final String PRONAME){Session session = getCurrentSession();CallableStatement pro = session.doReturningWork(new ReturningWork<C

关于使用cspreadsheet读写EXCEL表格数据的问题

前几天项目有读写EXCEL表格的需求,我就找了大概有几种,大致分为:COM方法、ODBC方法、OLE方法、纯底层格式分析方法。由于COM方法要求必须安装有OFFICE的EXCEL组件,纯底层格式分析方法又很多功能需要自行去完善,所有最终选择了数据库的方法,用数据库的方法去存取xls格式的数据。网上有一个高手写的CSpreedSheet,看了一下提供的接口,感觉挺好用的。在使用的过程中发现几个