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

相关文章

JavaWeb 学习笔记 spring+jdbc整合开发初步

JdbcTemplate类是Spring的核心类之一,可以在org.springframework.jdbc.core中找到它。JdbcTemplate类在内部已经处理数据库的建立和释放,可以避免一些常见的错误。JdbcTemplate类可直接通过数据源的应用实例化,然后在服务中使用,也可在xml配置中作为JavaBean应用给服务使用直接上一个实例步骤1.xml配置 <?xml version

大型网站架构演化(五)——数据库读写分离

网站在使用缓存后,使绝大部分数据读操作访问都可以不通过数据库就能完成,但是仍有一部分读操作(缓存访问不命中、缓存过期)和全部的写操作需要访问数据库,在网站的用户达到一定规模后,数据库因为负载压力过大而成为网站的瓶颈。      目前豆粉的主流数据库都提供主从热备功能,通过配置两台数据库主从关系,可以将一台数据库服务器的数据更新同步到另一台服务器上。网站利用数据库的这一功能,

大型网站架构演化(二)——应用服务和数据服务分离

随着网站业务的发展,一台服务器逐渐不能满足需求:越来越多的用户访问导致性能越来越差,越来越多的数据导致存储空间不足。这时就需要将应用和数据分离。应用和数据分离后整个网站使用三台服务器:应用服务器、文件服务器和数据库服务器,如图。              这三台服务器对硬件资源的要求各不相同: 应用服务器需要处理大量的业务逻辑,因此需要更快更强大的CPU;

Sharding(切片)技术(解决数据库分库一致性问题)

Sharding(切片) 不是一门新技术,而是一个相对简朴的软件理念,就是当我们的数据库单机无法承受高强度的i/o时,我们就考虑利用 sharding 来把这种读写压力分散到各个主机上去。 所以Sharding 不是一个某个特定数据库软件附属的功能,而是在具体技术细节之上的抽象处理,是Horizontal Partitioning 水平扩展(或横向扩展)的解决方案,其主要目的是为突破单节点数

【续2】linux C语言 文件描述符 读写地址分析

记录时间:2014-10-24 10:35 记录原因:一直对文件指针读写存在疑惑,导致经常性的操作文件时,结果不理想。原来一直是对文件被打开后,对文件流指针的读写位置没有弄清楚。 文件在打开后,任何一个对文件的操作都会改变文件流指针的位置,所以在对文件进行操作时,应从如下两点考虑: 1、文件是不是第一次打开:可以确认文件指针的确却位置; 2、检测文件打开方式,特殊注

linux C语言 文件描述符 读写地址分析

1、fwrite 和 fread对文件操作之后,文件位置指针已经移动到被操作的位置; 2、如果不是在fread或fwrite操作后的位置读、写文件内容,那么必须重新定位文件指针位置,此时可以使用 rewind、fseek函数; 3、rewind(FILE *stream):将文件指针直接移动到文件起始位置; 4、fseek(FILE *stream, long offset

【若依前后端分离】前端vue页面查看服务器本地的PDF

后端实现: 使用FileSystemResource包装文件,以便Spring MVC可以处理该资源 创建HttpHeaders对象以设置响应头 设置Content-Disposition头,使得浏览器以内联方式显示PDF(即在浏览器中直接打开) 设置Content-Type为application/pdf,指示响应体是一个PDF文件 构建并返回带有指定头信息和PDF资源的ResponseE

JDBC连接数据库 prepareStatement

import java.sql.Connection;import java.sql.DriverManager;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.SQLException;import team.JDBCTest;public class DBCStudent {// 定

关于C#读写XML的公用类

XmlHelper有很多种写法,以泛型的方式保存和读取xml,可以做到像下面这么简化又实用: 调用处 var sysParam = XmlHelper.LoadFromXML<TSysParam>(ApplicationDir.SystemParamFile);  //无参数文件时,初始化系统参数到XML文件  XmlHelper.SaveAsXML(ApplicationDir.System

c++:C++用fstream读写文件

fstream介绍 (1)fstream是C++标准库中面向对象库的一个,用于操作流式文件 (2)fstream本质上是一个class,提供file操作的一众方法 可以直接查看 man --versionman 2.10.2 在线查看: https://cplusplus.com/reference/#google_vignette https://zh.cppreference.