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

相关文章

SpringBoot实现数据库读写分离的3种方法小结

《SpringBoot实现数据库读写分离的3种方法小结》为了提高系统的读写性能和可用性,读写分离是一种经典的数据库架构模式,在SpringBoot应用中,有多种方式可以实现数据库读写分离,本文将介绍三... 目录一、数据库读写分离概述二、方案一:基于AbstractRoutingDataSource实现动态

springboot security之前后端分离配置方式

《springbootsecurity之前后端分离配置方式》:本文主要介绍springbootsecurity之前后端分离配置方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的... 目录前言自定义配置认证失败自定义处理登录相关接口匿名访问前置文章总结前言spring boot secu

MySQL大表数据的分区与分库分表的实现

《MySQL大表数据的分区与分库分表的实现》数据库的分区和分库分表是两种常用的技术方案,本文主要介绍了MySQL大表数据的分区与分库分表的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有... 目录1. mysql大表数据的分区1.1 什么是分区?1.2 分区的类型1.3 分区的优点1.4 分

Redis中高并发读写性能的深度解析与优化

《Redis中高并发读写性能的深度解析与优化》Redis作为一款高性能的内存数据库,广泛应用于缓存、消息队列、实时统计等场景,本文将深入探讨Redis的读写并发能力,感兴趣的小伙伴可以了解下... 目录引言一、Redis 并发能力概述1.1 Redis 的读写性能1.2 影响 Redis 并发能力的因素二、

springboot将lib和jar分离的操作方法

《springboot将lib和jar分离的操作方法》本文介绍了如何通过优化pom.xml配置来减小SpringBoot项目的jar包大小,主要通过使用spring-boot-maven-plugin... 遇到一个问题,就是每次maven package或者maven install后target中的ja

配置springboot项目动静分离打包分离lib方式

《配置springboot项目动静分离打包分离lib方式》本文介绍了如何将SpringBoot工程中的静态资源和配置文件分离出来,以减少jar包大小,方便修改配置文件,通过在jar包同级目录创建co... 目录前言1、分离配置文件原理2、pom文件配置3、使用package命令打包4、总结前言默认情况下,

MySQL分表自动化创建的实现方案

《MySQL分表自动化创建的实现方案》在数据库应用场景中,随着数据量的不断增长,单表存储数据可能会面临性能瓶颈,例如查询、插入、更新等操作的效率会逐渐降低,分表是一种有效的优化策略,它将数据分散存储在... 目录一、项目目的二、实现过程(一)mysql 事件调度器结合存储过程方式1. 开启事件调度器2. 创

Python实现高效地读写大型文件

《Python实现高效地读写大型文件》Python如何读写的是大型文件,有没有什么方法来提高效率呢,这篇文章就来和大家聊聊如何在Python中高效地读写大型文件,需要的可以了解下... 目录一、逐行读取大型文件二、分块读取大型文件三、使用 mmap 模块进行内存映射文件操作(适用于大文件)四、使用 pand

C# 读写ini文件操作实现

《C#读写ini文件操作实现》本文主要介绍了C#读写ini文件操作实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录一、INI文件结构二、读取INI文件中的数据在C#应用程序中,常将INI文件作为配置文件,用于存储应用程序的

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

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