MySQL 之分库分表技术ShardingJDBC

SpringBoot 知识体系详解 本文是SpringBoot知识体系的系统梳理,涵盖从入门到进阶的全面内容。文章分为多个章节,主要包括:基础入门(HelloWorld、日志配置、分层设计等)、接口开发(封装规范、参数校验、异常处理等)、数据库集成(MySQL、PostgreSQL、分库分表方案)、NoSQL集成(Redis、MongoDB等)、定时任务、安全认证、文件操作、消息队列、应用部署(Docker等)、系统监控(Actuator、ELK等)以及底层原理(自动装配、Starter机制等)。作者计划在5月完成大部分内容,旨在构建完整的S 阅读详情

ShardingJDBC简介

Sharding-JDBC是当当网研发的开源分布式数据库中间件,从 3.0 开始Sharding-JDBC被包含在 Sharding-Sphere 中,之后该项目进入Apache孵化器,4.0版本之后的版本为Apache版本。
ShardingSphere官方文档地址
在这里插入图片描述

分库分表概念

- 垂直分表
将一个表按照字段分成多表,每个表存储其中一部分字段,热门字段、冷门字段分开放在不同表中。
- 垂直分库
通过将表按业务分类,然后分布在不同数据库,并且可以将这些数据库部署在不同服务器上,从而达到多个服务器共同分摊压力的效果,但是依然没有解决单表数据量过大的问题。
- 水平分表
是在同一个数据库内,把同一个表的数据按一定规则拆到多个表中,解决了单一表数据量过大的问题,分出来的小表中只包含一部分数据,从而使得单个表的数据量 变小,提高检索性能。
- 水平分库
把同一个表的数据按一定规则拆到不同的数据库中,每个库可以放在不同的服务器上。

ShardingJDBC概念

- 逻辑表
水平拆分的数据表的总称。例:订单数据表根据主键尾数拆分为10张表,分别是 t_order_0 、 t_order_1 到 t_order_9 ,他们的逻辑表名为 t_order 。
- 真实表
在分片的数据库中真实存在的物理表。即上个示例中的 t_order_0 到 t_order_9 。
- 数据节点
数据分片的最小物理单元。由数据源名称和数据表组成,例: ds_0.t_order_0 。
- 绑定表
指分片规则一致的主表和子表。例如: t_order 表和 t_order_item 表,均按照 order_id 分片,绑定表之间的分区键完全相同,则此两张表互为绑定表关系。绑定表之间的多表关联查询不会出现笛卡尔积关联,关联查询效率将大大提升。举例说明,如果SQL为:SELECT i.* FROM t_order o JOIN t_order_item i ON o.order_id=i.order_id WHERE o.order_id in (10, 11);
在不配置绑定表关系时,假设分片键为 order_id ,那么路由后的SQL 应该为4条,它们呈现为笛卡尔积:
在这里插入图片描述
在配置绑定表关系后,路由的SQL应该为2条:
在这里插入图片描述
- 广播表
指所有的分片数据源中都存在的表,表结构和表中的数据在每个数据库中均完全一致。适用于数据量不大且需要 海量数据的表进行关联查询的场景,例如:字典表。
- 分片键
用于分片的数据库字段,是将数据库(表)水平拆分的关键字段。例:将订单表中的订单主键的尾数取模分片,则订单主键为分片字段。 SQL中如果无分片字段,将执行全路由,性能较差。 除了对单分片字段的支持,Sharding- Jdbc也支持根据多个字段进行分片。
- 分片算法
通过分片算法将数据分片,支持通过 = 、 BETWEEN 和 IN 分片。分片算法需要应用方开发者自行实现,可实现的灵活度非常高。包括:精确分片算法 、范围分片算法 ,复合分片算法 等。例如:where order_id = ? 将采用精确分 片算法,where order_id in (?,?,?)将采用精确分片算法,where order_id BETWEEN ? and ? 将采用范围分片算 法,复合分片算法用于分片键有多个复杂情况。
- 分片策略
包含分片键和分片算法,由于分片算法的独立性,将其独立抽离。真正可用于分片操作的是分片键 + 分片算法,也就是分片策略。内置的分片策略大致可分为尾数取模、哈希、范围、标签、时间等。由用户方配置的分片策略则更 加灵活,常用的使用行表达式配置分片策略,它采用Groovy表达式表示,如: t_user_$->{u_id % 8} 表示t_user 表根据u_id模8,而分成8张表,表名称为 t_user_0 到 t_user_7 。
- 自增主键生成策略
通过在客户端生成自增主键替换以数据库原生自增主键的方式,做到分布式主键无重复。

ShardingJDBC分表快速入门

需求说明

使用ShardingJDBC完成对订单表的水平分表。 在order_db数据库中创建两张表,t_order_1和t_order_2,这两张表是订单表拆分后的表,通过ShardingJdbc向订单表插入数据, 按照一定的分片规则,主键为偶数的进入t_order_1,另一部分数据进入t_order_2,通过ShardingJdbc 查询数据,根据 SQL语句的内容从t_order_1或t_order_2查询数据。

环境说明

  • 数据库:MySQL5.7
  • JDK:JDK8
  • 应用框架:SpringBoot 2.1.5,Mybatis3.5.0
  • ShardingJDBC:sharding-jdbc-spring-boot-starter-4.0.0

创建数据库和表

创建订单库order_db:

CREATE DATABASE `order_db` CHARACTER SET 'utf8' COLLATE 'utf8_general_ci';

在order_db中创建t_order_1、t_order_2表:

DROP TABLE IF EXISTS `t_order_1`;
CREATE TABLE `t_order_1` (
  `order_id` bigint(20) NOT NULL COMMENT '订单id',
  `price` decimal(10,2) NOT NULL COMMENT '订单价格',
  `user_id` bigint(20) NOT NULL COMMENT '下单用户id',
  `status` varchar(50) NOT NULL COMMENT '订单状态',
  PRIMARY KEY (`order_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;

DROP TABLE IF EXISTS `t_order_2`;
CREATE TABLE `t_order_2` (
  `order_id` bigint(20) NOT NULL COMMENT '订单id',
  `price` decimal(10,2) NOT NULL COMMENT '订单价格',
  `user_id` bigint(20) NOT NULL COMMENT '下单用户id',
  `status` varchar(50) NOT NULL COMMENT '订单状态',
  PRIMARY KEY (`order_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;

引入maven依赖

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.1.5.RELEASE</version>        
</parent>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.46</version>
    <scope>runtime</scope>
</dependency>
<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>2.0.0</version>
</dependency>
<dependency>
    <groupId>org.apache.shardingsphere</groupId>
    <artifactId>sharding-jdbc-spring-boot-starter</artifactId>
    <version>4.0.0</version>
</dependency>
<dependency>
    <groupId>org.apache.shardingsphere</groupId>
    <artifactId>sharding-jdbc-spring-namespace</artifactId>
    <version>4.0.0</version>
</dependency>

分片规则配置

分片规则配置是ShardingJDBC进行对分库分表操作的重要依据,配置内容包括:数据源、主键生成策略、分片策略等。
在application.properties中配置:

# 打印sql
spring.shardingsphere.props.sql.show=true
spring.main.allow-bean-definition-overriding=true

# 定义数据源
spring.shardingsphere.datasource.names=m1

spring.shardingsphere.datasource.m1.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.m1.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.m1.jdbc-url=jdbc:mysql://localhost:3306/order_db?characterEncoding=utf-8&serverTimezone=UTC&useSSL=false
spring.shardingsphere.datasource.m1.username=root
spring.shardingsphere.datasource.m1.password=123456

# 逻辑表名:t_order
# 指定t_order表的数据分布情况,配置数据节点
spring.shardingsphere.sharding.tables.t_order.actual-data-nodes=m1.t_order_$->{1..2}

# 指定t_order表的主键字段和生成策略
spring.shardingsphere.sharding.tables.t_order.key-generator.column=order_id
spring.shardingsphere.sharding.tables.t_order.key-generator.type=SNOWFLAKE

# 指定t_order表的分片策略,分片策略包括分片键和分片算法
spring.shardingsphere.sharding.tables.t_order.table-strategy.inline.sharding-column=order_id
spring.shardingsphere.sharding.tables.t_order.table-strategy.inline.algorithm-expression=t_order_$->{order_id % 2 + 1}
  • 首先定义数据源m1,并对m1进行实际的参数配置
  • 指定t_order表的数据分布情况,他分布在m1.t_order_1,m1.t_order_2
  • 指定t_order表的主键生成策略为SNOWFLAKE,SNOWFLAKE是一种分布式自增算法,保证id全局唯一
  • 定义t_order分片策略,order_id为偶数的数据落在t_order_1,为奇数的落在t_order_2,分表策略的表达式为 t_order_$->{order_id % 2 + 1}

编码

数据操作

import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.springframework.stereotype.Component;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;

@Mapper
@Component
public interface OrderDao {
    @Insert("insert into t_order(price,user_id,status)values(#{price},#{userId},#{status})")
    int insertOrder(@Param("price") BigDecimal price, @Param("userId") Long userId, @Param("status") String status);

    @Select("<script>" +
            "select" +
            " * " +
            " from t_order t " +
            " where t.order_id in " +
            " <foreach collection='orderIds' open='(' separator=',' close=')' item='id'>" +
            " #{id} " +
            " </foreach>" +
            "</script>")
    List<Map> selectOrderbyIds(@Param("orderIds") List<Long> orderIds);
}

单元测试

@RunWith(SpringRunner.class)
@SpringBootTest(classes = {ShardingJdbcDemoApplication.class})
public class ShardingJdbcTest {
    @Resource
    OrderDao orderDao;
    @Test
    public void testInsertOrder(){
        for(int i=1;i<20;i++){
            orderDao.insertOrder(new BigDecimal(i),1L,"SUCCESS");
        }
    }
    @Test
    public void testSelectOrderbyIds(){
        List<Long> ids = new ArrayList<>();
        ids.add(436669720939200512L);
        ids.add(436669722465927169L);
        List<Map> maps = orderDao.selectOrderbyIds(ids);
        System.out.println(maps);
    }
}

在这里插入图片描述

流程分析

ShardingJDBC在拿到用户要执行的sql之后流程分析:

  • 解析sql,获取片键值,在本例中是order_id
  • Sharding-JDBC通过规则配置 t_order_$->{order_id % 2 + 1},知道了当order_id为偶数时,应该往 t_order_1表插数据,为奇数时,往t_order_2插数据
  • 于是Sharding-JDBC根据order_id的值改写sql语句,改写后的SQL语句是真实所要执行的SQL语句
  • 执行改写后的真实sql语句
  • 将所有真正执行sql的结果进行汇总合并,返回

ShardingJDBC分库分表快速入门

环境说明

  • 数据库:MySQL5.7
  • JDK:JDK8
  • 应用框架:SpringBoot 2.1.5,Mybatis-Plus
  • ShardingJDBC:sharding-jdbc-spring-boot-starter-4.0.0-RC1

导入依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.46</version>
    <scope>runtime</scope>
</dependency>
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.1.1</version>
</dependency>
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.8</version>
</dependency>
<dependency>
    <groupId>org.apache.shardingsphere</groupId>
    <artifactId>sharding-jdbc-spring-boot-starter</artifactId>
    <version>4.0.0-RC1</version>
</dependency>
<dependency>
    <groupId>org.apache.shardingsphere</groupId>
    <artifactId>sharding-jdbc-spring-namespace</artifactId>
    <version>4.0.0-RC1</version>
</dependency>

创建数据库和表

ds0
  ├── user_0
  └── user_1
ds1
  ├── user_0
  └── user_1

SQL脚本:
ds0

CREATE DATABASE IF NOT EXISTS `ds0`;
USE `ds0`;
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for user_0
-- ----------------------------
DROP TABLE IF EXISTS `user_0`;
CREATE TABLE `user_0` (
  `id` bigint(50) NOT NULL,
  `name` varchar(255) DEFAULT NULL,
  `age` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- ----------------------------
-- Table structure for user_1
-- ----------------------------
DROP TABLE IF EXISTS `user_1`;
CREATE TABLE `user_1` (
  `id` bigint(50) NOT NULL,
  `name` varchar(255) DEFAULT NULL,
  `age` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

ds1

CREATE DATABASE IF NOT EXISTS `ds1`;
USE `ds1`;
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for user_0
-- ----------------------------
DROP TABLE IF EXISTS `user_0`;
CREATE TABLE `user_0` (
  `id` bigint(50) NOT NULL,
  `name` varchar(255) DEFAULT NULL,
  `age` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- ----------------------------
-- Table structure for user_1
-- ----------------------------
DROP TABLE IF EXISTS `user_1`;
CREATE TABLE `user_1` (
  `id` bigint(50) NOT NULL,
  `name` varchar(255) DEFAULT NULL,
  `age` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

分片规则配置

分库分表的分片规则配置,配置内容包括:数据源、主键生成策略、分片策略等。

# 数据源 ds0,ds1
spring.shardingsphere.datasource.names=ds0,ds1

# 第一个数据库
spring.shardingsphere.datasource.ds0.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.ds0.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.ds0.jdbc-url=jdbc:mysql://localhost:3306/ds0?characterEncoding=utf-8&serverTimezone=UTC&useSSL=false
spring.shardingsphere.datasource.ds0.username=root
spring.shardingsphere.datasource.ds0.password=123456

# 第二个数据库
spring.shardingsphere.datasource.ds1.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.ds1.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.ds1.jdbc-url=jdbc:mysql://localhost:3306/ds1?characterEncoding=utf-8&serverTimezone=UTC&useSSL=false
spring.shardingsphere.datasource.ds1.username=root
spring.shardingsphere.datasource.ds1.password=123456

# 水平拆分的数据库(表) 配置分库 + 分表策略 行表达式分片策略
# 分库策略列名称
spring.shardingsphere.sharding.default-database-strategy.inline.sharding-column=id
# 分库策略算法表达式
spring.shardingsphere.sharding.default-database-strategy.inline.algorithm-expression=ds$->{id % 2}

# 分库分表节点,其中user为逻辑表
spring.shardingsphere.sharding.tables.user.actual-data-nodes=ds$->{0..1}.user_$->{0..1}
# 分表策略列名称
spring.shardingsphere.sharding.tables.user.table-strategy.inline.sharding-column=id
# 分表策略算法表达式
spring.shardingsphere.sharding.tables.user.table-strategy.inline.algorithm-expression=user_$->{id % 2}

# 主键生成策略
spring.shardingsphere.sharding.tables.user.key-generator.column=id
spring.shardingsphere.sharding.tables.user.key-generator.type=SNOWFLAKE

# 打印执行的数据库以及语句
spring.shardingsphere.props.sql.show=true
spring.main.allow-bean-definition-overriding=true

配置说明:

  • 逻辑表 user
    水平拆分的数据库(表)的相同逻辑和数据结构表的总称。例:用户数据根据主键尾数拆分为2张表,分别是user_0到user_1,他们的逻辑表名为user_。
  • 真实表
    在分片的数据库中真实存在的物理表。即上个示例中的user_0到user_1。
  • 分片算法:
    Hint分片算法
    对应HintShardingAlgorithm,用于处理使用Hint行分片的场景。需要配合HintShardingStrategy使用。
  • 分片策略:
    行表达式分片策略
    对应InlineShardingStrategy。使用Groovy的表达式,提供对SQL语句中的=和IN的分片操作支持,只支持单分片键。对于简单的分片算法,可以通过简单的配置使用,从而避免繁琐的Java代码开发,如: user$->{id % 2} 表示user表根据id模2,而分成2张表,表名称为user_0到user_1。

编码

实体类:

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;

@Data
@EqualsAndHashCode(callSuper = true)
@Accessors(chain = true)
@TableName("user")
public class User extends Model<User> {
    @TableId(type= IdType.AUTO)
    private Long id;
    private String name;
    private Integer age;
}

Mapper层:

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.entity.User;

public interface UserMapper extends BaseMapper<User> {
}

Service层:

// 接口
import com.baomidou.mybatisplus.extension.service.IService;
import com.example.entity.User;
import java.util.List;

public interface UserService extends IService<User> {
    @Override
    boolean save(User entity);
    List<User> getUserList();
}

// 实现类
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.entity.User;
import com.example.mapper.UserMapper;
import com.example.service.UserService;
import org.springframework.stereotype.Service;
import java.util.List;

@Service("userService")
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Override
    public boolean save(User user) {
        return super.save(user);
    }

    @Override
    public List<User> getUserList() {
        return baseMapper.selectList(Wrappers.lambdaQuery());
    }
}

Controller层:

import com.example.entity.User;
import com.example.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;

@RestController
public class UserController {

    @Autowired
    private UserService userService;

    @GetMapping("/select")
    public List<User> select(){
        return userService.getUserList();
    }

    @GetMapping("/insert")
    public Boolean insert(User user) {
        return userService.save(user);
    }
}

测试

http://localhost:8080/insert?name=James&age=12
http://localhost:8080/insert?name=James&age=13
http://localhost:8080/insert?name=James&age=14
http://localhost:8080/insert?name=James&age=15

http://127.0.0.1:8080/select

执行自定义SQL

在application.properties添加配置:

mybatis-plus.mapper-locations=classpath:/mapper/**.xml

在启动类上添加注解:

@MapperScan("com.example.mapper")

创建UserMapper.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.example.mapper.UserMapper">
    <select id="selectUserForAge" resultType="com.example.entity.User" parameterType="java.lang.Integer">
        select * from user where age = #{age};
    </select>
</mapper>

UserMapper.java

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.entity.User;
import org.apache.ibatis.annotations.Param;
import java.util.List;

public interface UserMapper extends BaseMapper<User> {
    List<User> selectUserForAge(@Param("age") Integer age);
}

扩展代码

public static DataSource dataSource(String dbName) {
    HikariDataSource dataSource = new HikariDataSource();
    dataSource.setDriverClassName("com.mysql.jdbc.Driver");
    dataSource.setJdbcUrl(String.format("jdbc:mysql://127.0.0.1:3306/%s", dbName));
    dataSource.setPoolName("db:" + dbName + System.currentTimeMillis());
    dataSource.setUsername("root");
    dataSource.setPassword("123456");
    return dataSource;
}

DataSource dataSource = dataSource("ds0");
try (Connection conn = dataSource.getConnection();
     Statement statement = conn.createStatement()) {
    ResultSet resultSet = statement.executeQuery("SELECT `e_sys_sequence.nextval`('userId')");
    if (resultSet.next()){
        long aLong = resultSet.getLong(1);
    }
} catch (Exception e) {

}

ShardingJDBC分库分表(支持连接查询)

导入依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.46</version>
    <scope>runtime</scope>
</dependency>
<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>2.0.0</version>
</dependency>
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.8</version>
</dependency>
<dependency>
    <groupId>org.apache.shardingsphere</groupId>
    <artifactId>sharding-jdbc-spring-boot-starter</artifactId>
    <version>4.0.0-RC1</version>
</dependency>
<dependency>
    <groupId>org.apache.shardingsphere</groupId>
    <artifactId>sharding-jdbc-spring-namespace</artifactId>
    <version>4.0.0-RC1</version>
</dependency>

创建数据库和表

ds0
  ├── t_order0
  └── t_order1
  └── t_order_item0
  └── t_order_item1
  └── t_config
ds1
  ├── user_0
  └── user_1
  └── t_order_item0
  └── t_order_item1
CREATE TABLE `t_order0` (
  `order_id` bigint(20) NOT NULL AUTO_INCREMENT,
  `user_id` bigint(20) NOT NULL,
  `name` varchar(100) DEFAULT NULL,
  PRIMARY KEY (`order_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `t_order1` (
  `order_id` bigint(20) NOT NULL AUTO_INCREMENT,
  `user_id` bigint(20) NOT NULL,
  `name` varchar(100) DEFAULT NULL,
  PRIMARY KEY (`order_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `t_order_item0` (
  `order_id` bigint(20) NOT NULL,
  `item` varchar(100) DEFAULT NULL,
  `user_id` bigint(20) NOT NULL,
  PRIMARY KEY (`order_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `t_order_item1` (
  `order_id` bigint(20) NOT NULL,
  `item` varchar(100) DEFAULT NULL,
  `user_id` bigint(20) NOT NULL,
  PRIMARY KEY (`order_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE `t_config` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` bigint(20) DEFAULT NULL,
  `config` varchar(100) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

配置

# 这里要注册所有的数据源
spring.shardingsphere.datasource.names=ds0,ds1

# 这是数据源0的配置
spring.shardingsphere.datasource.ds0.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.ds0.jdbc-url=jdbc:mysql://localhost:3306/ds0?serverTimezone=UTC&useSSL=false
spring.shardingsphere.datasource.ds0.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.ds0.username=root
spring.shardingsphere.datasource.ds0.password=123456

# 这是数据源1的配置
spring.shardingsphere.datasource.ds1.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.ds1.jdbc-url=jdbc:mysql://localhost:3306/ds1?serverTimezone=UTC&useSSL=false
spring.shardingsphere.datasource.ds1.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.ds1.username=root
spring.shardingsphere.datasource.ds1.password=123456

# 分库策略
spring.shardingsphere.sharding.default-database-strategy.inline.sharding-column=order_id
spring.shardingsphere.sharding.default-database-strategy.inline.algorithm-expression=ds$->{order_id % 2}

# 分表策略
spring.shardingsphere.sharding.tables.t_order.actual-data-nodes=ds$->{0..1}.t_order$->{0..1}
spring.shardingsphere.sharding.tables.t_order.table-strategy.inline.sharding-column=order_id
spring.shardingsphere.sharding.tables.t_order.table-strategy.inline.algorithm-expression=t_order$->{order_id % 2}
spring.shardingsphere.sharding.tables.t_order.key-generator.column=order_id
spring.shardingsphere.sharding.tables.t_order.key-generator.type=SNOWFLAKE

spring.shardingsphere.sharding.tables.t_order_item.actual-data-nodes=ds$->{0..1}.t_order_item$->{0..1}
spring.shardingsphere.sharding.tables.t_order_item.table-strategy.inline.sharding-column=order_id
spring.shardingsphere.sharding.tables.t_order_item.table-strategy.inline.algorithm-expression=t_order_item$->{order_id % 2}

spring.shardingsphere.sharding.binding-tables=t_order, t_order_item

# 广播表, 其主节点是ds0
spring.shardingsphere.sharding.broadcast-tables=t_config
spring.shardingsphere.sharding.tables.t_config.actual-data-nodes=ds$->{0}.t_config

# 打印执行的数据库以及语句
spring.shardingsphere.props.sql.show=true
spring.main.allow-bean-definition-overriding=true

mybatis.mapper-locations=classpath:mapper/*Dao.xml
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@MapperScan("com.example.dao")
@SpringBootApplication
public class ShardingJdbcDemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(ShardingJdbcDemoApplication.class, args);
    }

}

编码

实体类:

public class Order { 
    private Long orderId;
    private Long userId;
    private String name;
}
public class OrderItem {
    private Long orderId;
    private String item;
    private Long userId;
}
public class TConfig {
    private Integer id;
    private Long userId;
    private String config;    
}

Dao类:

public interface OrderDao {
    Order queryById(Long orderId);
    int insert(Order order);
}
public interface OrderItemDao {
    OrderItem queryById(Long orderId);
    int insert(OrderItem orderItem);
    //为了测试绑定表
    @Select(value = "select * from t_order t1 inner join t_order_item t2 on t1.order_id = t2.order_id where t1.order_id=#{orderId}")
    Optional<OrderItem> getOrderItemByOrderId(@Param("orderId") Long orderId);
}
public interface ConfigDao {
    TConfig queryById(Integer id);
    int insert(TConfig tConfig);
}

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.example.dao.OrderDao">
    <resultMap type="com.example.entity.Order" id="TOrder0Map">
        <result property="orderId" column="order_id" jdbcType="INTEGER"/>
        <result property="userId" column="user_id" jdbcType="INTEGER"/>
        <result property="name" column="name" jdbcType="VARCHAR"/>
    </resultMap>
    <!--查询单个-->
    <select id="queryById" resultMap="TOrder0Map">
        select
          order_id, user_id, name
        from t_order
        where order_id = #{orderId}
    </select>
    <!--新增所有列-->
    <insert id="insert" keyProperty="orderId" useGeneratedKeys="true">
        insert into t_order(user_id, name)
        values (#{userId}, #{name})
    </insert>
</mapper>

<?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.example.dao.OrderItemDao">
    <resultMap type="com.example.entity.OrderItem" id="TOrderItem0Map">
        <result property="orderId" column="order_id" jdbcType="INTEGER"/>
        <result property="item" column="item" jdbcType="VARCHAR"/>
        <result property="userId" column="user_id" jdbcType="INTEGER"/>
    </resultMap>
    <!--查询单个-->
    <select id="queryById" resultMap="TOrderItem0Map">
        select
          order_id, item, user_id
        from t_order_item
        where order_id = #{orderId}
    </select>
    <!--新增所有列-->
    <insert id="insert">
        insert into t_order_item(order_id, item, user_id)
        values (#{orderId}, #{item}, #{userId})
    </insert>
</mapper>

<?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.example.dao.ConfigDao">
    <resultMap type="com.example.entity.TConfig" id="TConfigMap">
        <result property="id" column="id" jdbcType="INTEGER"/>
        <result property="userId" column="user_id" jdbcType="INTEGER"/>
        <result property="config" column="config" jdbcType="VARCHAR"/>
    </resultMap>
    <!--查询单个-->
    <select id="queryById" resultMap="TConfigMap">
        select
          id, user_id, config
        from t_config
        where id = #{id}
    </select>
    <!--新增所有列-->
    <insert id="insert" keyProperty="id" useGeneratedKeys="true">
        insert into t_config(user_id, config)
        values (#{userId}, #{config})
    </insert>
</mapper>

测试

@RunWith(SpringRunner.class)
@SpringBootTest(classes = {ShardingJdbcDemoApplication.class})
public class ShardingJdbcTest {
    @Resource
    OrderDao orderDao;
    @Resource
    OrderItemDao orderItemDao;
    @Test
    public void saveOrder(){
        for (int i=0; i<5; i++){
            Order order = new Order();
            order.setName("James");
            order.setUserId(i + 0L);
            orderDao.insert(order);
        }
    }
    @Test
    public void saveOrderItem(){
        OrderItem orderItem = new OrderItem();
        orderItem.setItem("Item1");
        orderItem.setOrderId(435929970817105921L);
        orderItem.setUserId(1001L);
        orderItemDao.insert(orderItem);
    }
    @Test
    public void saveOrderItemJoin(){
        Optional<OrderItem> optional = orderItemDao.getOrderItemByOrderId(435929970817105921L);
        System.out.println(optional);
    }
}

ShardingJDBC读写分离快速入门

在这里插入图片描述

创建数据库和表

CREATE DATABASE `user_db` CHARACTER SET 'utf8' COLLATE 'utf8_general_ci';

DROP TABLE IF EXISTS `t_user`;
CREATE TABLE `t_user` (
  `user_id` bigint(20) NOT NULL COMMENT '用户id',
  `fullname` varchar(255) NOT NULL COMMENT '用户姓名',
  `user_type` char(1) DEFAULT NULL COMMENT '用户类型',
  PRIMARY KEY (`user_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;

读写规则配置

# 打印sql
spring.shardingsphere.props.sql.show=true
spring.main.allow-bean-definition-overriding=true

# 定义数据源
spring.shardingsphere.datasource.names=m1,s1

spring.shardingsphere.datasource.m1.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.m1.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.m1.jdbc-url=jdbc:mysql://localhost:3380/user_db?characterEncoding=utf-8&serverTimezone=UTC&useSSL=false
spring.shardingsphere.datasource.m1.username=root
spring.shardingsphere.datasource.m1.password=123456

spring.shardingsphere.datasource.s1.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.s1.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.s1.jdbc-url=jdbc:mysql://localhost:3381/user_db?characterEncoding=utf-8&serverTimezone=UTC&useSSL=false
spring.shardingsphere.datasource.s1.username=root
spring.shardingsphere.datasource.s1.password=123456

# 主库从库逻辑数据源定义 ds0为user_db
spring.shardingsphere.sharding.master-slave-rules.ds0.master-data-source-name=m1
spring.shardingsphere.sharding.master-slave-rules.ds0.slave-data-source-names=s1

# t_user分表策略,固定分配至ds0的t_user真实表,ds0对应了m1和s1
spring.shardingsphere.sharding.tables.t_user.actual-data-nodes=ds0.t_user

编码

数据操作

import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Map;

@Mapper
@Component
public interface UserDao {
    @Insert("insert into t_user(user_id, fullname) value(#{userId},#{fullname})")
    int insertUser(@Param("userId") Long userId, @Param("fullname") String fullname);
    @Select({"<script>",
            " select",
            " * ",
            " from t_user t ",
            " where t.user_id in",
            "<foreach collection='userIds' item='id' open='(' separator=',' close=')'>",
            "#{id}",
            "</foreach>",
            "</script>"
    })
    List<Map> selectUserbyIds(@Param("userIds") List<Long> userIds);
}

单元测试

@RunWith(SpringRunner.class)
@SpringBootTest(classes = {ShardingJdbcDemoApplication.class})
public class ShardingJdbcTest {
    @Resource
    private UserDao userDao;
    @Test
    public void insertUser(){
        for(long i=0; i<5; i++){
            userDao.insertUser(i, "James" + i);
        }
    }
    @Test
    public void selectUserbyIds(){
        List<Long> userIds = new ArrayList<>();
        userIds.add(0L);
        userIds.add(1L);
        userIds.add(2L);
        userDao.selectUserbyIds(userIds);
    }
}

综合案例

创建数据库和表

创建store_db、product_db_1、product_db_2数据库:

CREATE DATABASE `store_db` CHARACTER SET 'utf8' COLLATE 'utf8_general_ci';
CREATE DATABASE `product_db_1` CHARACTER SET 'utf8' COLLATE 'utf8_general_ci';
CREATE DATABASE `product_db_2` CHARACTER SET 'utf8' COLLATE 'utf8_general_ci';

在store_db数据库中执行下面的脚本:

CREATE TABLE `store_info` (
  `id` bigint(20) NOT NULL COMMENT 'id',
  `store_name` varchar(100) DEFAULT NULL COMMENT '店铺名称',
  `reputation` int(11) DEFAULT NULL COMMENT '信誉等级',
  `region_code` varchar(50) DEFAULT NULL COMMENT '店铺所在地',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;
INSERT INTO `store_info` VALUES ('1', 'XX零食店', '4', '110100');
INSERT INTO `store_info` VALUES ('2', 'XX饮品店', '3', '410100');

分别在store_db、product_db_1、product_db_2数据库中执行下面的脚本:

DROP TABLE IF EXISTS `region`;
CREATE TABLE `region` (
  `id` bigint(20) NOT NULL COMMENT 'id',
  `region_code` varchar(50) DEFAULT NULL COMMENT '地理区域编码',
  `region_name` varchar(100) DEFAULT NULL COMMENT '地理区域名称',
  `level` tinyint(1) DEFAULT NULL COMMENT '地理区域级别(省、市、县)',
  `parent_region_code` varchar(50) DEFAULT NULL COMMENT '上级地理区域编码',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;
INSERT INTO `region` VALUES ('1', '110000', '北京', '0', null);
INSERT INTO `region` VALUES ('2', '410000', '河南省', '0', null);
INSERT INTO `region` VALUES ('3', '110100', '北京市', '1', '110000');
INSERT INTO `region` VALUES ('4', '410100', '郑州市', '1', '410000');

分别在product_db_1、product_db_2数据库中执行下面的脚本:

DROP TABLE IF EXISTS `product_info_1`;
CREATE TABLE `product_info_1` (
  `product_info_id` bigint(20) NOT NULL COMMENT 'id',
  `store_info_id` bigint(20) DEFAULT NULL COMMENT '所属店铺id',
  `product_name` varchar(100) DEFAULT NULL COMMENT '商品名称',
  `spec` varchar(50) DEFAULT NULL COMMENT '规 格',
  `region_code` varchar(50) DEFAULT NULL COMMENT '产地',
  `price` decimal(10,0) DEFAULT NULL COMMENT '商品价格',
  `image_url` varchar(100) DEFAULT NULL COMMENT '商品图片',
  PRIMARY KEY (`product_info_id`) USING BTREE,
  KEY `FK_Reference_1` (`store_info_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;

DROP TABLE IF EXISTS `product_info_2`;
CREATE TABLE `product_info_2` (
  `product_info_id` bigint(20) NOT NULL COMMENT 'id',
  `store_info_id` bigint(20) DEFAULT NULL COMMENT '所属店铺id',
  `product_name` varchar(100) DEFAULT NULL COMMENT '商品名称',
  `spec` varchar(50) DEFAULT NULL COMMENT '规 格',
  `region_code` varchar(50) DEFAULT NULL COMMENT '产地',
  `price` decimal(10,0) DEFAULT NULL COMMENT '商品价格',
  `image_url` varchar(100) DEFAULT NULL COMMENT '商品图片',
  PRIMARY KEY (`product_info_id`) USING BTREE,
  KEY `FK_Reference_1` (`store_info_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;

DROP TABLE IF EXISTS `product_descript_1`;
CREATE TABLE `product_descript_1` (
  `id` bigint(20) NOT NULL COMMENT 'id',
  `product_info_id` bigint(20) DEFAULT NULL COMMENT '所属商品id',
  `descript` longtext COMMENT '商品描述',
  `store_info_id` bigint(20) DEFAULT NULL COMMENT '所属店铺id',
  PRIMARY KEY (`id`) USING BTREE,
  KEY `FK_Reference_2` (`product_info_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;

DROP TABLE IF EXISTS `product_descript_2`;
CREATE TABLE `product_descript_2` (
  `id` bigint(20) NOT NULL COMMENT 'id',
  `product_info_id` bigint(20) DEFAULT NULL COMMENT '所属商品id',
  `descript` longtext COMMENT '商品描述',
  `store_info_id` bigint(20) DEFAULT NULL COMMENT '所属店铺id',
  PRIMARY KEY (`id`) USING BTREE,
  KEY `FK_Reference_2` (`product_info_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;

分片配置

既然是分库分表,那么就需要定义多个真实数据源,每一个数据库链接信息就是一个数据源定义,如:

spring.shardingsphere.datasource.m0.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.m0.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.m0.jdbc-url=jdbc:mysql://localhost:3380/store_db?characterEncoding=utf-8&serverTimezone=UTC&useSSL=false
spring.shardingsphere.datasource.m0.username=root
spring.shardingsphere.datasource.m0.password=123456

m0,就是这个真实数据源的名称,然后需要告诉Sharding-JDBC,咱们有哪些真实数据源,如:

spring.shardingsphere.datasource.names=m0,m1,m2,s0,s1,s2

如果需要配置读写分离,还需要告诉Sharding-JDBC,这么多真实数据源,那几个是一套读写分离?也就是定义主从逻辑数据源:

spring.shardingsphere.sharding.master-slave-rules.ds0.master-data-source-name=m0
spring.shardingsphere.sharding.master-slave-rules.ds0.slave-data-source-names=s0

若我们已经对m0和s0做了mysql主从同步,那我们需要告诉Sharding-JDBC,m0、s0为一组主从同步数据源,其中m0为主,s0为从,并且定义名称为ds0,这个ds0就是主从逻辑数据源。

最终Sharding-JDBC配置如下:

在这里插入代码片

参考

JAVA 关于分库分表的学习和DEMO
sharding-jdbc结合mybatis实现分库分表功能
分库分表主键问题 - Sharding-Jdbc
sharding-jdbc分库分表
SpringBoot使用Sharding-JDBC分库分表
Sharding-JDBC 系列 01 - 分库分表
详解Spring Boot中整合Sharding-JDBC读写分离示例
Sharding-JDBC:查询量大如何优化?
利用ShardingSphere-JDBC实现分库分表

ShardingJDBC分库分表实战 ShardingSphere分库分表的核心概念 虚拟库: ShardingSphere的核心就是提供一个具备分库分表功能的虚拟库,他是一个ShardingSphereDatasource实例。应用程序只需要像操作单数据源一样访问这个ShardingSphereDatasource即可。示例中,MyBatis框架并没有特殊指定DataSource,就是使用的ShardingSphere的DataSource数据源。 真实库: 实际保存数据的数据库。这些数据库都被包含在ShardingSphereDatasou 阅读详情

相关推荐

MySQL第十二讲:ShardingJDBC详解

互联网业务兴起之后,海量用户加上海量数据的特点,单个数据库服务器已经难以满足业务需要,必须考虑数据库集群的方式来提升性能。高性能数据库集群的`第一种方式是“读写分离”`,`第二种方式是“数据库分片”`。

Jet_qi的博客 1028

分库分表之Sharding-JDBC

目录 1、Sharding-JDBC概述 2、架构回顾 3、SpringBoot集成Sharding-JDBC 3.1 准备工作 3.2 配置MySQL主从复制 3.3 引入依赖坐标 3.4 application.properties配置 3.5 启动类,pojo service,dao,test 3.6 一些需要补充的概念 4、Sharding-JDBC原理 5、分库分表带来的问题 5.1 垂直分库带来的问题和解决思路 5.2 水平分库带来的问题和解决思路 5.3 我们.

长沙老码农 6998

QTabWidget动态标签页管理:从代码创建到UI设计的实战指南

本文深入探讨了QTabWidget动态标签页管理的实战技巧,涵盖从纯代码创建到UI设计器布局的两种核心方法。详细讲解了如何动态添加、插入、关闭标签页,并管理其内容与生命周期。文章还提供了标签页精细化控制、界面优化(如设置图标、样式表)以及构建简易多文档编辑器的进阶实战案例,帮助开发者灵活应对数据监控、多文档编辑等复杂界面需求。

omega的博客 866

MySQL_11_ShardingJDBC实现分库分表

文章目录一、前言二、关系型数据库层面的高并发优化2.1 MYSQL海量数据带来的性能问题2.2 分片策略2.3 分布式ID2.3.1 定义全局表2.3.2 UUID2.3.3 雪花算法2.3 常见分库分表策略2.4 分库分表实战2.5 分库分表带来的问题三、Sharding-JDBC分库分表(uuid 雪花算法 SPI机制)四、ShardingSphere读写分离和分布式事务(理论+实战)4.1 读写分离4.2 分布式事务2.2 详解分库分表2.3 常见分库分表策略2.4 分库分表实战2.5 分库分表带来的

毛毛的专栏 2814

CrackerXI+脱壳实战:解决iOS应用逆向中的加密文件问题

本文详细介绍了如何使用CrackerXI+工具对iOS应用进行脱壳,解决App Store应用因FairPlay DRM加密而无法进行静态分析的难题。通过图形化界面一键操作,CrackerXI+能高效获取解密后的可执行文件,为逆向工程奠定基础。文章涵盖工具选型、实战步骤及常见问题排查,是iOS逆向入门与进阶的实用指南。

seed的博客 258

保姆级教程:用CST 2023一步步复现一个1-8GHz Vivaldi天线(含参数优化与结果分析)

本文提供了一份详细的CST 2023教程,指导读者如何从零开始设计并优化1-8GHz Vivaldi天线。内容涵盖工程设置、参数化建模、仿真加速技巧以及性能优化策略,特别适合需要实现宽带天线设计的工程师和研究人员。通过实战案例,帮助用户掌握Vivaldi天线的核心设计要点和CST高级功能应用。

weixin_30800987的博客 618

MySQL从入门到精通【实践篇】之使用Sharding-JDBC 分库分表详解

Sharding-JDBC 是一款开源的分布式数据库中间件,主要目标是充分利用数据库的水平扩展能力,尽可能地避免改变已有的应用程序代码,简化分布式系统的开发难度。本文主要是使用sharding-jdbc 实现分库分表 以及各种分库分表策略实战验证。在学习本文之前建议 先看下我之前写的两篇文章《MySQL从入门到精通【进阶篇】MySQL分库分表详解》《MySQL从入门到精通【进阶篇】MySQL的读写分离详解》分库分表是一种常见的数据库扩展策略,它通过将数据分散到多个数据库或表中,来提高系统的性能和可扩展性。

日拱一卒无有尽,功不唐捐终入海 1129

基于STC8A8K64S4A12的掉电唤醒定时器应用,极大降低产品功耗

通过合理的配置和编程,我们可以充分发挥单片机的功能,实现能效优化和电池寿命延长的目标。其中,掉电唤醒定时器是其一项重要功能,可以在系统处于睡眠状态时通过定时器的计时功能进行唤醒,从而实现对系统功耗的有效控制。使用STC8A8K64S4A12的掉电唤醒定时器功能,我们可以在不影响系统正常工作的情况下,大大降低产品的功耗。通过以上的代码,我们实现了一个简单的掉电唤醒定时器功能。当系统进入睡眠模式后,定时器开始计时,到达预设的唤醒时间后,定时器中断被触发,系统从睡眠模式唤醒,执行相应的操作。

CodeSageX的博客 1090

Sharding-jdbc分库分表

引入 不断增长的业务数据会对MySQL数据库的存储和访问造成极大的性能影响,由于单台服务器的资源(CPU、磁盘、内存等)总是有限的,所以单台数据库所能承载的数据量、数据处理能力都将遭遇瓶颈。不论是获取连接还是插入或查询都会有极大的性能问题。 MySQL大数据量造成的性能瓶颈解决方案: 从SQL入手 加入索引 -> 缓存 -> 主从复制/读写分离 使用缓存,减少对数据库的同步访问 减少MySQL使用,可以使用HBase、polarDB、TiDB等分布式存储,ES查询 分库分表 拓展

Lyzxii 6276

Qt5.15.7编译报错问题汇总:python2安装环境导致的问题

导致编译生成的:RegExpJitTables.h文件大小为0。RegExpJitTables.h 能生成且大小不为0KB。可以看到,正确的python路径,执行编译路径后。再执行 configure XXX…尝试直接改,将其改为正确的路径。

MusicScore的博客 1439

基于YOLOv10的PCB电子元件智能识别系统设计与实现

数据预处理模块:负责对原始PCB图像进行标注、增强和格式转换模型训练模块:基于YOLOv10架构进行模型训练和优化推理检测模块:加载训练好的模型进行实时检测用户界面模块:提供友好的交互界面,方便用户操作和结果可视化YOLO(You Only Look Once)系列算法自2016年提出以来,经历了多次迭代更新。YOLOv1-v3:奠定了YOLO系列的基础架构YOLOv4-v7:引入大量优化技巧和网络结构改进YOLOv8-v9:进一步优化模型结构和训练策略YOLOv10。

YOLO 156

MySQL-分库分表(Mycat)

本文系统介绍了MyCat数据库中间件的分库分表技术。主要内容包括:1)垂直拆分和水平拆分的原理与实现方式;2)MyCat的核心配置文件schema.xml、rule.xml , server.xml的详细配置方法;3)多种分片规则(范围分片、取模分片、一致性哈希等)的具体应用;4)MyCat的SQL解析与结果合并机制。文章通过具体配置示例,展示了如何利用MyCat实现数据分片、路由查询等功能,解决单数据库性能瓶颈问题,为大数据量场景下的数据库架构设计提供了实用指导方案。

weixin_74354824的博客 2275

RK平台PCIE-Ethernet扩展:Intel I210移植与性能飞升之路

本文详细介绍了Intel I210千兆以太网控制器在瑞芯微RK平台的移植与优化过程。通过硬件适配、内核配置、驱动开发及性能调优四个关键环节,实现了RK平台的网络性能提升。硬件方面,重点说明了PCIE接口的规范连接与供电检查;软件方面,系统阐述了内核配置、设备树修改和驱动编译流程。在性能优化环节,详细介绍了中断优化、缓冲区设置和TCP/IP协议栈调优策略,并采用Iperf和Netperf工具进行量化测试验证。测试结果显示,优化后的网络吞吐量提升20%以上,延迟降低40%,为工业控制、智能安防等场景提供了可靠的

远程部署调试 运行安装 项目调试 二次开发 项目技术新 持续迭代 部分源码免费分享 351

MySQL分库分表

先垂直后水平:优先解耦复杂业务,再处理数据规模问题。最小化改动:尽量保持原有SQL语法兼容性,降低迁移成本。渐进式演进:从单机→主从复制→垂直拆分→水平拆分逐步迭代,避免过度设计。通过合理的分片策略与工具选型,可在保证系统稳定性的前提下实现高性能扩展。

weixin_50808694的博客 979

51单片机 DHT11温湿度传感器LCD显示+串口打印+Proteus仿真

DHT11+LCD1602+串口输出+Proteus仿真

perseverance51博客 7198

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

MySQL日志、主从复制和分库分表

二进制日志(BINLOG)记录了所有的 DDL(数据定义语言)语句和 DML(数据操纵语言)语句,但 不包括数据查询(SELECT、SHOW)语句。作用:①. 灾难时的数据恢复;②. MySQL的主从复制。在MySQL8版本中,默认二进制日志是开启着 的,涉及到的参数如下:log_bin_basename:当前数据库服务器的binlog日志的基础名称(前缀),具体的binlog文 件名需要再该basename的基础上加上编号(编号从000001开始)。

m0_74818265的博客 1093

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

【MySQL学习|黑马笔记|Day9】日志(错误日志、二进制日志、查询日志、慢查询日志),主从复制(原理、主库配置、从库配置),分库分表的拆分方式

MySQL运维日志与主从复制摘要 MySQL日志系统包含错误日志(默认开启)、二进制日志(记录DDL/DML)、查询日志(记录所有操作)和慢查询日志(记录执行慢的SQL)。二进制日志是主从复制的核心,可通过mysqlbinlog工具查看。 主从复制通过主库二进制日志传输到从库中继日志实现数据同步,配置步骤包括: 主库配置server-id、创建复制账号、查看日志坐标 从库配置不同server-id为只读模式 在从库使用CHANGE REPLICATION SOURCE命令指向主库 主从复制能提高可用性、实现

2401_87144364的博客 642

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

【MySQL】分库分表 —— 介绍 —— 拆分策略

分库分表的形式,主要是两种:垂直拆分和水平拆分。

qq_39921135的博客 589

mysql3-进阶

来自视频学习:黑马程序员 MySQL数据库入门到精通,从mysql安装到mysql高级、mysql优化全囊括_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1Kr4y1i7ru?p=153&spm_id_from=pageDriver 三、进阶 1、日志: a、错误日志:是mysql中最重要的日志之一,它记录了当mysqld启动和停止时,以及服务器在运行过程中发生任何严重错误时的相关信息。当数据库出现任何故障导致无法正常使用时,建议首先查看此日志

qq_36590288的博客 959

MySQL-运维

错误日志是MysQL中最重要的日志之一,它记录了当mysqld启动和停止时,以及服务器在运行过程中发生任何时的相关信息。当数据库出现任何故障导致无法正常使用时,建议首先查看此日志。该日志是默认开启的,默认存放目录/var/log/,默认的日志文件名为mysqld.log。

weixin_51262054的博客 241

MySQL的分库分表

分库分表的中心思想就是将数据分散存储,使得单一数据库/表的数据量变小来缓解单一数据库的性能问题,从而达到提升数据库性能的目的;1.IO瓶颈:热点数据太多,数据库缓存不足,产生大量磁盘IO,效率降低,请求数据太多,带宽不够,网络IO瓶颈;每个库的数据也不一样;(1)水平分库:以字段为依据,按照一定策略,将一个库的数据拆分到多个库中;特点:每个库的表结构都一样,每个库的数据都不一样;(2)水平分表:以字段为依据,按照一定策略,将一个表的数据拆分到多个表中;特点:每个库的表结构都一样,每个库的数据都不一样;

m0_59745705的博客 381

智能客服数据库架构设计:从优快云案例看高并发场景下的技术选型与优化

用户咨询一上来,那就是海量的实时消息写入,每个会话的状态还得时刻保持,不能出一点差错。高峰期每秒上万条消息砸过来,传统的单库单表架构瞬间就扛不住了,慢查询、连接池打满、甚至直接宕机,用户体验直接跌到谷底。今天,我就结合在类似高并发场景下的实践,聊聊我们是怎么一步步把数据库架构“撑”起来的。我们为了可用性和性能,在很多地方选择了最终一致性,比如会话状态先更新Redis,再异步同步到MySQL做持久化。这在绝大多数情况下没问题,但如果Redis集群出现脑裂或持久化失败,就可能出现状态丢失的极端情况。

2600_94959984的博客 299

看完这个故事,你就知道程序员为什么选公司就要去上升期的

看完这个故事,你就知道程序员为什么选公司就要去上升期的 https://www.toutiao.com/i6948390604984402462/?tt_from=weixin&utm_campaign=client_share&wxshare_count=1&timestamp=1617943363&app=news_article&utm_source=weixin&utm_medium=toutiao_ios&use_new_style=1&a

荒野求生的博客 282

必看,个人整理的系统化Java后端最全知识点

你可能有所感悟。零散的资料读了很多,但是很难有提升。到处是干货,但是并没什么用,简单来说就是缺乏系统化。另外,噪音太多,雷同的框架一大把,我不至于全都要去学了吧。这里,我大体根据基础、Java基础、Java进阶给分了下类,挑的也都是最常用最重要的工具。......

m0_72885838的博客 200
上一篇: Redis 之Jedis客户端
下一篇: MySQL 之自己实现sequence
yyangqqian
博客等级 码龄15年 406粉丝 406原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值