ShardingJDBC数据库中间件学习笔记

2023-11-17

简介

官网地址:https://shardingsphere.apache.org/index_zh.html

在这里插入图片描述

Apache ShardingSphere 产品定位为 Database Plus,旨在构建多模数据库上层的标准和生态。 它关注如何充分合理地利用数据库的计算和存储能力,而并非实现一个全新的数据库。ShardingSphere 站在数据库的上层视角,关注他们之间的协作多于数据库自身。

连接增量可插拔是 Apache ShardingSphere 的核心概念。

  • 连接:通过对数据库协议、SQL 方言以及数据库存储的灵活适配,快速的连接应用与多模式的异构数据库;
  • 增量:获取数据库的访问流量,并提供流量重定向(数据分片、读写分离、影子库)、流量变形(数据加密、数据脱敏)、流量鉴权(安全、审计、权限)、流量治理(熔断、限流)以及流量分析(服务质量分析、可观察性)等透明化增量功能;
  • 可插拔:项目采用微内核 + 三层可插拔模型,使内核、功能组件以及生态对接完全能够灵活的方式进行插拔式扩展,开发者能够像使用积木一样定制属于自己的独特系统。
    在这里插入图片描述

ShardingSphere-JDBC

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

  • 适用于任何基于 JDBC 的 ORM 框架,如:JPA, Hibernate, Mybatis, Spring JDBC Template 或直接使用 JDBC;
  • 支持任何第三方的数据库连接池,如:DBCP, C3P0, BoneCP, HikariCP 等;
  • 支持任意实现 JDBC 规范的数据库,目前支持 MySQL,PostgreSQL,Oracle,SQLServer 以及任何可使用 JDBC 访问的数据库。
  • 在这里插入图片描述

ShardingSphere-Proxy

定位为透明化的数据库代理端,提供封装了数据库二进制协议的服务端版本,用于完成对异构语言的支持。 目前提供 MySQL 和 PostgreSQL(兼容 openGauss 等基于 PostgreSQL 的数据库)版本,它可以使用任何兼容 MySQL/PostgreSQL 协议的访问客户端(如:MySQL Command Client, MySQL Workbench, Navicat 等)操作数据,对 DBA 更加友好。

  • 向应用程序完全透明,可直接当做 MySQL/PostgreSQL 使用;
  • 适用于任何兼容 MySQL/PostgreSQL 协议的的客户端。
  • 在这里插入图片描述

hardingSphere-Sidecar(TODO)

定位为 Kubernetes 的云原生数据库代理,以 Sidecar 的形式代理所有对数据库的访问。 通过无中心、零侵入的方案提供与数据库交互的啮合层,即 Database Mesh,又可称数据库网格。

Database Mesh 的关注重点在于如何将分布式的数据访问应用与数据库有机串联起来,它更加关注的是交互,是将杂乱无章的应用与数据库之间的交互进行有效地梳理。 使用 Database Mesh,访问数据库的应用和数据库终将形成一个巨大的网格体系,应用和数据库只需在网格体系中对号入座即可,它们都是被啮合层所治理的对象。

在这里插入图片描述

ShardingSphere-JDBC ShardingSphere-Proxy ShardingSphere-Sidecar
数据库 任意 MySQL/PostgreSQL MySQL/PostgreSQL
连接消耗数
异构语言 仅 Java 任意
性能 损耗低 损耗略高
无中心化
静态入口

hardingSphere功能清单

  • 功能列表:1.数据库分片 2.分库分表 3.读写分离 4.分片策略定制化 5.无中心化分布式主键
  • 分布式事务: 1.标准化事务接口 2.XA强一致事务 3.柔性事务 4.数据库治理
  • 分布式治理: 1.弹性伸缩 2.可视化链路追踪 3.数据加密

ShardingSphere数据分片内核剖析

ShardingSphere的3个产品的数据分片主要流程是完全一致的。核心由SQL解析=>执行器优化=>SQL路由=>SQL改写=> SQL执行=>结果归并的流程组成。
在这里插入图片描述

ShardingJDBC准备

Mysql完成主从复制

liunx准备mysql数据库

概述

主从复制(也称AB复制)允许将来自一个MySQL数据库服务器(主服务器)的数据复制到一个或多个MySQL数据库服务器(从服务器)。

复制是异步的从站不需要永久连接以接收来自主站的更新。

根据配置,您可以复制数据库中的所有数据库,所选数据库甚至选定的表。

主从复制优点

  • 横向扩展解决方案–在多个从站之间分配负载以提高性能。在此环境中,所有写入和更新都必须在主服务器上进行。但是,读取可以在一个或多个从设备上进行。该模型可以提高写入性能(因为主设备专用于更新),同时显着提高了越来越多的从设备的读取速度。
  • 数据安全性·因为数据被复制到从站,并且从站可以暂停复制过程,所以可以在从站上运行备份服务而不会破坏相应的主数据。
  • 分析–可以在主服务器上创建实时数据,而信息分析可以在从服务器上进行,而不会影响主服务器的性能。远程数据分发–您可以使用复制为远程站点创建数据的本地副本,而无需永久访问主服务器。

主从复制原理

前提是作为主服务器角色的数据库服务器必须开启二进制曰志

主服务器上面的任何修改都会通过自己的I/0 tread(I/O线程)保存在二进制日志 Binary log里面。

  • 从服务器上面也启动一个I/0 thread,通过配置好的用户名和密码,连接到主服务器上面请求读取二进制日志,然后把读取到的二进制日志写到本地的一个Realy log(中继日志)里面。
  • 从服务器上面同时开启一个SQL thread定时检查Realy log(这个文件也是二进制的),如果发现有更新立即把更新的内容在本机的数据库上面执行一遍。
    每个从服务器都会收到主服务器二进制日志的全部内容的副本。
  • 从服务醋设备负责决定应该执行二进制日志中的哪些语句。
    除非另行指定,否则主从二进制日志中的所有事件都在从站上执行。如果需要。您可以将从服务器配置为仅处理一些特定数据库或表的事件。

基于Docker完成主从复制

原文链接:https://www.cnblogs.com/songwenjie/p/9371422.html

为什么基于Docker搭建?

  • 资源有限
  • 虚拟机搭建对机器配置有要求,并且安装mysql步骤繁琐
  • 一台机器上可以运行多个Docker容器
  • Docker容器之间相互独立,有独立ip,互不冲突
  • Docker使用步骤简便,启动容器在秒级别

利用Docker搭建主从服务器

首先拉取docker镜像,我们这里使用5.7版本的mysql:

docker pull mysql:5.7

然后使用此镜像启动容器,这里需要分别启动主从两个容器

Master(主):

docker run -p 3339:3306 --name mymysql -e MYSQL_ROOT_PASSWORD=123456 -d mysql:5.7

Slave(从):

docker run -p 3340:3306 --name mymysql -e MYSQL_ROOT_PASSWORD=123456 -d mysql:5.7

Master对外映射的端口是3339,Slave对外映射的端口是3340。因为docker容器是相互独立的,每个容器有其独立的ip,所以不同容器使用相同的端口并不会冲突。这里我们应该尽量使用mysql默认的3306端口,否则可能会出现无法通过ip连接docker容器内mysql的问题。

使用docker ps命令查看正在运行的容器

[root@iz2vcbxtcjxxdepmmofk3hz mysql3307]# docker ps
CONTAINER ID   IMAGE                 COMMAND                  CREATED          STATUS          PORTS                               NAMES
66392fd83cf1   mysql:5.7             "docker-entrypoint.s…"   51 minutes ago   Up 20 minutes   33060/tcp, 0.0.0.0:3308->3306/tcp   mysql-slave
f5b9761e3dee   mysql:5.7             "docker-entrypoint.s…"   51 minutes ago   Up 35 minutes   33060/tcp, 0.0.0.0:3307->3306/tcp   mysql-master
配置Master(主)

通过docker exec -it 627a2368c865 /bin/bash命令进入到Master容器内部,也可以通过docker exec -it mysql-master /bin/bash命令进入。627a2368c865是容器的id,而mysql-master是容器的名称。

cd /etc/mysql切换到/etc/mysql目录下,然后vi my.cnf对my.cnf进行编辑。此时会报出bash: vi: command not found,需要我们在docker容器内部自行安装vim。使用apt-get install vim命令安装vim

会出现如下问题:

Reading package lists... Done
Building dependency tree       
Reading state information... Done
E: Unable to locate package vim

执行apt-get update,然后再次执行apt-get install vim即可成功安装vim。然后我们就可以使用vim编辑my.cnf,在my.cnf中添加如下配置:

[mysqld]
## 同一局域网内注意要唯一
server-id=100  
## 开启二进制日志功能,可以随便取(关键)
log-bin=mysql-bin

配置完成之后,需要重启mysql服务使配置生效。使用service mysql restart完成重启。重启mysql服务时会使得docker容器停止,我们还需要docker start mysql-master启动容器。

下一步在Master数据库创建数据同步用户,授予用户 slave REPLICATION SLAVE权限和REPLICATION CLIENT权限,用于在主从库之间同步数据。

CREATE USER 'slave'@'%' IDENTIFIED BY '123456';

GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'slave'@'%';
配置Slave(从)

和配置Master(主)一样,在Slave配置文件my.cnf中添加如下配置:

[mysqld]
## 设置server_id,注意要唯一
server-id=101  
## 开启二进制日志功能,以备Slave作为其它Slave的Master时使用
log-bin=mysql-slave-bin   
## relay_log配置中继日志
relay_log=edu-mysql-relay-bin  

配置完成后也需要重启mysql服务和docker容器,操作和配置Master(主)一致。

链接Master(主)和Slave(从)

在Master进入mysql,执行show master status;
在这里插入图片描述
File和Position字段的值后面将会用到,在后面的操作完成之前,需要保证Master库不能做任何操作,否则将会引起状态变化,File和Position字段的值变化。

在Slave 中进入 mysql,执行

change master to master_host='172.17.0.3', master_user='slave', master_password='123456', master_port=3306, master_log_file='mysql-bin.000001', master_log_pos= 3298, master_connect_retry=30;

命令说明:

master_host : Master的地址,指的是容器的独立ip,可以通过docker inspect --format='{{.NetworkSettings.IPAddress}}' 容器名称|容器id 查询容器的ip

master_port: Master的端口号,指的是容器的端口号

master_user: 用于数据同步的用户

master_password: 用于同步的用户的密码

master_log_file: 指定 Slave 从哪个日志文件开始复制数据,即上文中提到的 File 字段的值

master_log_pos: 从哪个 Position 开始读,即上文中提到的 Position 字段的值

master_connect_retry: 如果连接失败,重试的时间间隔,单位是秒,默认是60秒

在Slave 中的mysql终端执行show slave status \G;用于查看主从同步状态。

正常情况下,SlaveIORunning 和 SlaveSQLRunning 都是No,因为我们还没有开启主从复制过程。使用start slave开启主从复制过程,然后再次查询主从同步状态show slave status \G;

SlaveIORunning 和 SlaveSQLRunning 都是Yes,说明主从复制已经开启。此时可以测试数据同步是否成功。

读写分离

项目测试

新建项目导入依赖

       <!--web-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!--数据库-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.3.2</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.10</version>
        </dependency>

        <!--sharding-jdbc-->
        <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-core-common</artifactId>
            <version>4.0.0-RC1</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

yaml配置

server:
  port: 8085

spring:
  main:
    allow-bean-definition-overriding: true
  shardingsphere:
    # 参数配置 显示SQl
    props:
      sql:
        show: true
    # 配置数据源
    datasource:
      # 给每个数据源取别名
      names: ds1,ds2
      # 给master-ds1每个数据源配置数据库连接信息
      ds1: # master
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://localhost:3307/test?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&useSSL=false&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
        username: root
        password: 123456
        maxPoolSize: 100
        minPoolSize: 5
      ds2: # slave
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://localhost:3308/test?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&useSSL=false&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
        username: root
        password: 123456
        maxPoolSize: 100
        minPoolSize: 5
    #    配置默认数据源
    sharding:
      # 默认数据源 主要用于写 注意一定要配置读写分离 如果不配做 那么就会把全部节点都当成slave
      default-data-source-name: ds1
    # 配置读写分离
    masterslave:
      name: ms # 名称 任意取
      master-data-source-name: ds1 # 主库
      slave-data-source-names: ds2 # 从库 多个逗号分割
      # 从节点负载均衡策略 默认轮询 随机 RANDOM
      load-balance-algorithm-type: round_robin

# mybatis 配置
mybatis:
  mapper-locations: classpath*:mapper/*.xml
  type-aliases-package: com.tuxc.entity

数据库表

DROP TABLE IF EXISTS `master_slave`;
CREATE TABLE `master_slave`  (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;

测试代码编写

@Data
public class TestEntity {
  // 主键
  private Integer id;
  // 姓名
  private String name;
}
@Repository
@Mapper
public interface TestMapper {

  @Select("select * from master_slave")
  List<TestEntity> selectByAll();

  @Insert("insert into master_slave (name) VALUES (#{name})")
  void insert(TestEntity testEntity);
}

测试运行

@RestController
@RequestMapping("/test/user")
public class TestController {

  @Autowired
  private TestMapper testMapper;

  @GetMapping
  public String insert(){
    TestEntity test = new TestEntity();
    test.setName("ndsjjdaa");
    testMapper.insert(test);
    return "success";
  }

  @GetMapping("findByAll")
  public List<TestEntity> findByAll(){
    return testMapper.selectByAll();
  }
  
}

在这里插入图片描述
由此实现了读写分离

分库分表

为什么要分库分表

一般的机器(4核16G),单库的MySQL并发(QPS+TPS)超过了2k,系统基本就完蛋了。最好是并发量控制在1k左右。这里就引出一个问题,为什么要分库分表?

分库分表目的:解决高并发,和数据量大的问题。

1、高并发情况下,会造成IO读写频繁,自然就会造成读写缓慢,甚至是宕机。一般单库不要超过2k并发,NB的机器除外。
2、数据量大的问题。主要由于底层索引实现导致,MySQL的索引实现为B+TREE,数据量其他,会导致索引树十分庞大,造成查询缓慢。

第二,innodb的最大存储限制64TB。
要解决上述问题。最常见做法,就是分库分表。
分库分表的目的,是将一个表拆成N个表,就是让每个表的数据量控制在一定范围内,保证SQL的性能。一个表数据建议不要超过500W。

概念

又分为垂直拆分和水平拆分。

水平拆分: 统一个表的数据拆到不同的库不同的表中。可以根据时间、地区、或某个业务键维度,也可以通过hash进行拆分,最后通过路由访问到具体的数据。拆分后的每个表结构保持一致。

垂直拆分: 就是把一个有很多字段的表给拆分成多个表,或者是多个库上去。每个库表的结构都不一样,每个库表都包含部分字段。一般来说,可以根据业务维度进行拆分,如订单表可以拆分为订单、订单支持、订单地址、订单商品、订单扩展等表;也可以,根据数据冷热程度拆分,20%的热点字段拆到一个表,80%的冷字段拆到另外一个表。

在这里插入图片描述

不停机分库分表数据迁移

一般数据库的拆分也是有一个过程的,一开始是单表,后面慢慢拆成多表。那么我们就看下如何平滑的从MySQL单表过度到MySQL的分库分表架构。

  1. 利用mysql+canal做增量数据同步,利用分库分表中间件,将数据路由到对应的新表中。
  2. 利用分库分表中间件,全量数据导入到对应的新表中。
  3. 通过单表数据和分库分表数据两两比较,更新不匹配的数据到新表中。
  4. 数据稳定后,将单表的配置切换到分库分表配置上。
    在这里插入图片描述

分库分表的方式

逻辑表

逻辑表是指:水平拆分的数据库或者数据表的相同路基和数据结构表的总称。比如用户数据根据用户id%2拆分为2个表,分别是:ksi_user0和ksd_user1。他们的逻辑表名是: ksd_user。
在shardingjdbc中的定义方式如下:

spring:
  shardingsphere:
    sharding:
      tables:
        # 逻辑表名称
        master-savle:

分库分表数据节点- actual-data-nodes

spring:
  shardingsphere:
    sharding:
      tables:
        # 逻辑表名称
        master-savle: # 有多少库和表则定义多少 否则会报错
          # 数据节点:多数据源$->{0..N} 逻辑表名$ ->{0..N} 相同表
          actual-data-nodes: ds$->{0..2}.master-savle$->{0..1}
          # 数据节点;多数据源$->{0..N} 逻辑表名$ ->{0..N} 不同表
          actual-data-nodes: ds0.master-savle$->{0..1}, ds1.master-savle$->{2..4}
          # 指定单数据源的配置方式
          actual-data-nodes: ds0.master-savle$->{0..4}
          # 全部手动指定
          actual-data-nodes: ds0.master-savle1, ds0.master-savle2, ds0.master-savle3

数据分片是最小单元。由数据源名称和数据表组成,比如: ds0.ksd_user0

在这里插入图片描述

分库分表5种分片策略

在这里插入图片描述

数据源分片分为两种:

  • 数据源分片
  • 表分片

这两个是不同维度的分片规则,但是它们额能用的分片策略和规则是一样的。它们由两部分构成:

  • 分片键
  • 分片算法

第一种: none

对应NoneShardingStragey,不分片策略,SQL会被发给所有节点去执行,这个规则没有子项目可以配置。

第二种:inline行表达时分片策略{核心,必须要掌握)

对应InlineShardingStragey。使用Groovy的表达时,提供对SQL语句种的=和in的分片操作支持,只支持单分片键。对于简单的分片算法,可以通过简单的配置使用,从而避免繁琐的Java代码开放,如: ksd_user$(分片键(数据表字段) userid % 5)表示ksd_user表根据某字段(userid)模5.从而分为5张表,表名称为: ksd_user0到ksd_user4。如果库也是如此。

spring:
  shardingsphere:
    sharding:
      tables:
        # 逻辑表名称
        master-savle:
          # 数据节点:多数据源$->{0..N} 逻辑表名$ ->{0..N} 相同表
          actual-data-nodes: ds$->{0..2}.master-savle$->{0..1}
          # 数据源分片策略
          databaseStrategy:
            inline:
              shardingColumn: user_id
              algorithmlnlineExpression: ds$->{user_id%2}
          # 表分片策略
          tableStrategy:
            inline:
              shardingColumn: order_id
              algorithmlnlineExpression: master-savle$->{order_id%2}

第三种:根据实时间日期–按照标准规则分库分表

标准分片- Standard(了解)

  • 对应StrandardShardingStrategy.提供对SQL语句中的=,in和恶between and的分片操作支持。
  • StrandardShardingStrategy只支持但分片键。提供PreciseShardingAlgorithm和RangeShardingAlgorithm两个分片算法。
  • PreciseShardingAlgorithm是必选的呃,用于处理=和IN的分片
  • 和RangeShardingAlgbrithm是可选的,是用于处理Betwwen and分片,如果不配置和RangeShardingAlgorithm,SQL的Between AND将按照全库路由处理。
/**
 *  标准分片- Standard(了解)
 *  必须继承PreciseShardingAlgorithm
 * @author tuxuchen
 * @date 2021/11/25 11:41
 */
public class BirthdayAlgorithm implements PreciseShardingAlgorithm<Date> {

  // 有几个数据源 放几条数据
  List<Date> dateList = new ArrayList<>();

  {
    Calendar calendar1 = Calendar.getInstance();
    calendar1.set(2021, 1, 1, 0, 0, 0);
    Calendar calendar2 = Calendar.getInstance();
    calendar2.set(2022, 1, 1, 0, 0, 0);
    dateList.add(calendar1.getTime());
    dateList.add(calendar2.getTime());
  }

  /**
   *
   * @param collection 数据源集合 ds1 ds2
   * @param preciseShardingValue
   * @return
   */
  @Override
  public String doSharding(Collection<String> collection, PreciseShardingValue<Date> preciseShardingValue) {
    // 获得属性数据库的值
    Date date = preciseShardingValue.getValue();
    // 获取数据源的名称信息列表
    Iterator<String> iterator = collection.iterator();
    String target = null;
    for (Date s : dateList) {
      target = iterator.next();
      // 如果数据晚于指定的日期直接返回
      if (date.before(s)){
        break;
      }
    }
    return target; // 最后返回的是 ds1  ds2
  }
}
spring:
  shardingsphere:
    sharding:
      tables:
        # 逻辑表名称
        master-savle:
          # 数据节点:多数据源$->{0..N} 逻辑表名$ ->{0..N} 相同表
          actual-data-nodes: ds$->{0..2}.master-savle$->{0..1}
          # 数据源分片策略
          databaseStrategy:
            standard:
              shardingColumn: birthady # 字段名
              preciseAlgorithmClassName: com.tuxc.config.BirthdayAlgorithm
          # 表分片策略
          tableStrategy:
            inline:
              shardingColumn: order_id
              algorithmlnlineExpression: master-savle$->{order_id%2}

第四种: ShardingSphere -符合分片策略((了解)

  • 对应接口:HintShardingStrategy。通过Hint而非SQL解析的方式分片的策略。
  • 对于分片字段非SQL决定,而是由其他外置条件决定的场景,克使用SQL hint灵活的注入分片字段。例如:按照用户登录的时间,主键等进行分库,而数据库中并无此字段。SQL hint支持通过Java API和SQL注解两种方式使用。让后分库分表更加灵活。
    在这里插入图片描述

第五种:ShardingSphere - hint分片策略(了解)

  • 对应ComplexShardingStrategy。符合分片策略提供对SQL语句中的-,in和between and的分片操作支持。
  • ComplexShardingStrategy支持多分片键,由于多分片键之间的关系复杂,因此并未进行过多的封装,而是直接将分片键组合以及分片操作符透传至分片算法,完全由开发者自己实现,提供最大的灵活度。
    在这里插入图片描述

分布式主键配置

问题:如果主键是自增长的情况下,存放在不同数据库里的数据,很容易出现主键相同的情况

在这里插入图片描述

ShardingSphere提供灵活的配置分布式主键生成策略方式。在分片规则配置模块克配置每个表的主键生成策略。默认使用雪花算法。(snowflake)生成64bit的长整型数据。支持两种方式配置

  • SNOWFLAKE
  • UUID
spring:
  shardingsphere:
    sharding:
      tables:
        # 逻辑表名称
        master-savle:
          key-generator:
            #主键的列明 数据库类型 必须用 bigint类型
            column: id
            type: SHOWFLAKE # 注意要用大写

注意点:

  1. 数据库主键类型不要自增长,否则会插入不进去
  2. 使用SHOWFLAKE ,数据库列类型必须是bigint
  3. 配置主键策略使用大写

分布式事务管理

本地事务

在不开启任何分布式事务管理器的前提下,让每个数据节点各自管理自己的事务,它们之间没有协阅以及通信的能力,也并不互相知晓其他数据节点事务的成功与否。本地事务在性能方面无任何损耗,但在强一致性以及最终一致性方面则力不从心。

两阶段提交

XA协议最早的分布式事务模型是由X/Open国际联盟提出的X/Open Distributed Transaction Processing (DTP)模型,简称XA协议。
基于XA协议实现的分布式事务对业务侵入很小。它最大的优势就是对使用方通明,用户可以像使用本地事务一样使用基于XA协议的分布式事务。XA协议能够严格保障事务ACID特性。
严格保障事务ACID特性是一把双刃剑,事务执行在过程中需要将所需资源全部锁定,它更加适用于执行时间确定的短事务。对于长事务来说,整个事务进行期间对数据的独占,将导致对热点数据依赖的业务系统并发性能衰退明显。因此,在高并发的性能至上场景中,基于XA协议的分布式事务并不是最侄选择。

柔性事务

如果将实现了ACID的事务要素的事务称为刚性事务的话,那么基于BASE事务要素的事务则称为桑柔性事务。BASE是基本可用、柔性状态和最终―数性这三个要素的缩写。

  • 基本可用(Basically Available)保证分布式事务参与方不一定同时在线。
  • 柔性状态(Soft state)则允许系统状态更新有一定的延时,这个延时对客户来说不一定能够察觉。
  • 而最终一致性(Eventually consistent)通常是通过消息传递的方式保证系统的最终一致性。

在ACID事务中对隔离性的要求很高,在事务执行过程中,必须将所有的资源锁定。柔性事务的理念则是通过业务逻辑将互斥锁操作从资源层面上移至业务层面。通过放宽对强一致性要求,来换取系统吞吐量的提升。
基于ACID的强一致性事务和基于BASE的最终一致性事务都不是银弹,只有在最适合的场景中才能发挥它们的最大长处,可通过下表详细对比它们之间的区别,以帮助开发者进行技术选型,

使用SpringBoot starter

引入 Maven 依赖

<!-- 使用 XA 事务时,需要引入此模块 -->
<dependency>
    <groupId>org.apache.shardingsphere</groupId>
    <artifactId>shardingsphere-transaction-xa-core</artifactId>
    <version>${shardingsphere.version}</version>
</dependency>

<!-- 使用 BASE 事务时,需要引入此模块 -->
<dependency>
    <groupId>org.apache.shardingsphere</groupId>
    <artifactId>shardingsphere-transaction-base-seata-at</artifactId>
    <version>${shardingsphere.version}</version>
</dependency>

配置事务管理器

@Configuration
@EnableTransactionManagement
public class TransactionConfiguration {
    
    @Bean
    public PlatformTransactionManager txManager(final DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }
    
    @Bean
    public JdbcTemplate jdbcTemplate(final DataSource dataSource) {
        return new JdbcTemplate(dataSource);
    }
}

使用分布式事务

@Transactional
@ShardingSphereTransactionType(TransactionType.XA)  // 支持TransactionType.LOCAL, TransactionType.XA, TransactionType.BASE
public void insert() {
    jdbcTemplate.execute("INSERT INTO t_order (user_id, status) VALUES (?, ?)", (PreparedStatementCallback<Object>) ps -> {
        ps.setObject(1, i);
        ps.setObject(2, "init");
        ps.executeUpdate();
    });
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

ShardingJDBC数据库中间件学习笔记 的相关文章

  • 使用多个窗口通过 Eclipse 进行调试

    我通常运行双显示器设置 因此我为同一工作区打开两个 Eclipse 窗口 显示不同的文件 当我调试并命中断点时 Eclipse 会切换到 调试 透视图 但它还会在我的两个窗口中显示断点所在的文件 行 即使包含断点的文件在一个窗口中打开 但在
  • JTextPane 的样式是否具有类似控制台的格式?

    有没有办法使 JTextPane 中的文本看起来与控制台输出的文本相似 我的意思是 基本上 每个字符如何具有相同的宽度 以便 ASCII 艺术或间距缩进之类的东西可以正常工作 例如 目前 如果我输入 First 然后输入 5 个空格 然后在
  • 什么时候数据库被称为嵌入式数据库?

    术语 嵌入式数据库 与 数据库 具有不同的含义吗 我见过的嵌入式数据库有两种定义 嵌入式数据库就像专门为 嵌入式 空间 移动设备等 设计的数据库系统一样 这意味着它们在紧张的环境中 内存 CPU 方面 可以合理地执行 嵌入式数据库就像不需要
  • JavaFX TabPane 禁用按键切换选项卡

    我有一个Tab有一些内容 ScrollBar和别的 The ScrollBar has event handler for keys left and right 但如果我按下这些按钮Tabs被切换 因为TabPane还有一个密钥处理程序
  • 如果主键不为空,Spring data JPA不允许实体被持久化

    我有一个订阅者实体 它使用用户提供的电子邮件地址作为主键而不是自动生成的值 这意味着当调用JpaRepository的save方法时 主键值为not null 春季数据JPA文档 http docs spring io spring dat
  • 如何在 selenium webdriver 中将网络浏览器从 Firefox 更改为 Chrome/Opera/IE/Safari?

    如何将浏览器从 firefox 更改为在 selenium webdriver 中工作的 Chrome Opera IE 请指导步骤以及代码片段 如果您对上述任何浏览器有答案 请回复 我读了很多这方面的内容 但无法正确链接 首先 您需要将正
  • 仅在文件下载完成后设置 cookie。

    我有一个场景 我想告诉用户下载完成并提示关闭按钮 为此 我使用 jquery 插件来连续监视 cookie 以了解下载何时完成 我的问题是我想设置这个cookie fileDownload true and path 下载完成后立即进行 为
  • 如何统计List中某个元素出现的次数

    我有一个ArrayList Java的Collection类 如下 ArrayList
  • hibernate 如何确保二级缓存使用数据库中的最新数据进行更新

    我读到 使用 hibernate 的二级缓存 它可以通过减少数据 对象检索的数据库命中来提高应用程序性能 但是hibernate是如何保证二级缓存与数据库中的数据是最新的呢 例如 假设下面的类是实体并持久化到数据库中 Entity clas
  • 更改 Java 字符串中的日期格式

    I ve a String代表一个日期 String date s 2011 01 18 00 00 00 0 我想将其转换为Date并将其输出到YYYY MM DD format 2011 01 18 我怎样才能实现这个目标 好的 根据我
  • 本机查询 (JPA) 未重置并返回相同的旧结果

    我有一个本机 sql 查询如下 for init i 0 i lt 2 i String sql Select from accounts where id Query query em createNativeQuery sql Acco
  • [PersistenceUnit:<名称>]:无法构建EntityManagerFactory

    正如主题所述 我的问题是EntityManagerFactory无法建造 我正在使用 Maven Hibernate 我正在连接到 MySQL 数据库
  • 有人让动物嗅探器插件工作吗?

    maven animal sniffer 插件承诺告诉我我的代码是否有任何对 Java 1 6 或更高版本 API 的引用 这对于我们这些在 MacOSX Snow Leopard 只有官方 1 6 上开发但需要交付到 1 5 环境的人来说
  • Rmi 错误 IllegalArgumentException、MarshalException

    为所有人上课 package Task2 import java rmi RemoteException import java rmi server UnicastRemoteObject public class IdCl extend
  • FirebaseAuth.getInstance().signOut() 不注销

    我尝试从 firebase 注销用户 但在关闭应用程序并再次打开后 用户仍然处于连接状态 我尝试从 firebase 定期注销用户 但没有解决问题 我想知道是什么导致了这个问题 logout setOnClickListener new V
  • 为数组生成随机索引

    我知道对于普通整数来说这是这样 但是有索引这样的东西吗 Random dice new Random int n dice nextInt 6 System out println n 你是什 么意思 数组索引是普通数字 所以你可以轻松地做
  • ACTION_MEDIA_BUTTON 的广播接收器不起作用

    我正在为 Android 操作系统版本 4 0 3 ICS 编写 Android 应用程序 问题是我没有从 BroadcastReceiver 的 onReceive 方法中的 Log d 获得输出 这意味着我的应用程序没有正确处理广播 我
  • Selenium WebDriver (java) 可以与浏览器的检查工具元素选择器交互吗?

    通过使用 selenium 我可以访问位于检查选项卡中的浏览器元素选择器 在浏览器中按 Ctrl Shift C 吗 我想使用该选择器 指向 一个元素 并使其在浏览器中突出显示 例如 简单的事情如下 WebElement elem driv
  • a.equals(a) 什么时候返回 false?

    我想知道在哪些情况下java中的变量不能相等 使用equals 方法 自身 我这里说的不是对象而是变量本身 只要代码编译并在调用 equals 时返回 false 到目前为止 我发现的唯一情况是 public class A public
  • Spring Boot 应用程序崩溃

    请告诉我哪里有问题 我尝试启动我的第一个在 Spring Boot 上开发的应用程序 我已经在 SpringMVC 上有了简单的 Web 项目 现在我喜欢在 BOOT 上构建它 这是错误输出 org springframework bean

随机推荐

  • utf8格式源代码中的字符串,默认都会当作char来处理,除非用L""符号来修饰

    原先QString mystrr 现在都不认了 必须都要加上L才行 原先 m conn gt put HttpProxyAuthMethod Basic 现在 m conn gt put HttpProxyAuthMethod L Basi
  • Apache2.4 + PHP 5.5 源码编译安装

    系统 centos6 4 MySQL5 5 53已经编译安装完成 请见 http blog csdn net odongyuan1 article details 58602551 旧版本卸载 rpm qa grep httpd yum r
  • Numpy攻略系列:repeat函数

    Numpy中repeat函数使用 Numpy是Python强大的数学计算库 和Scipy一起构建起Python科学计算生态 在本节下面我们重点介绍下repeat函数的用法 我们在Python中import numpy help numpy
  • ChatGPT怎么突然变得这么强?华人博士万字长文深度拆解GPT-3.5能力起源

    文章目录 一 2020 版初代 GPT 3 与大规模预训练 二 从 2020 版 GPT 3 到 2022 版 ChatGPT 三 Code Davinci 002和 Text Davinci 002 在代码上训练 在指令上微调 四 tex
  • vue2 onresize实现浏览器窗口大小实时计算

    首发于我的博客 http zhengxiyun top mounted window onresize gt return gt this divHeight window innerHeight yourHeight beforeMoun
  • 华为OD机试 - 事件推送(Java)

    题目描述 同一个数轴X上有两个点的集合A A1 A2 Am 和B B1 B2 Bn Ai和Bj均为正整数 A B已经按照从小到大排好序 A B均不为空 给定一个距离R 正整数 列出同时满足如下条件的所有 Ai Bj 数对 Ai lt Bj
  • Shell函数和脚本参数

    1 在脚本中定义函数 functin name 直接的定义方式 语句块 function function name 使用关键字 function 定义的方式 语句块 函数命名规则 为了和变量区分 使用小写字母和下划线 以字母开头 不能使用
  • 如何免费体验腾讯云虚拟主机(云服务器)

    最近调Android程序 访问不到局域网内的服务器 是在没有办法了就搞了台腾讯云的虚拟主机 不得不说 比起那些香港的三线品牌虚拟主机体验好了许多 配置属于乞丐版 1GHz CPU 1GB RAM 50GB 系统盘 30GB数据盘 对于广大学
  • 李宏毅机器学习 hw1 boss baseline 解析

    hw1 代码 任务描述 任务很简单 就是一个回归问题 给你过去四天新冠肺炎感染人数的相关情况 让你预测最后一天的新冠感染人数 上图展示了特征的解析特征共有117维 首先是37维的关于州的one hot编码 然后是4维的特征表示是否有新冠相像
  • 山东理工大学第十五届ACM程序设计竞赛 R - Zyn的超能力

    Description Zyn 需要能量提高自己的超能力 有两种能量存在 超级能量和小能量 对于超级能量 Zyn 绝对不可以错过 而且努力的 Zyn 希望得到更多的小能量 但是 Zyn 每天最多可以获得 k 次能量 而且每个能量都会在第 x
  • DNF那个跨区服务器稳定,dnf2017年最新跨区表 dnf2017跨区大区汇总介绍

    小编今天为大家带来的就是dnf2017年的最新跨区表 还不清楚dnf2017年各大区跨区详情的小伙伴们抓紧时间跟上小编一起来看一下吧 DNF跨6有哪些区 地下城与勇士跨区列表2017 跨一 广东1区 广东2区 广东3区 广东4区 广东5区
  • Vue:配置.env.dev文件不生效的问题

    问题描述 Vue项目的 env dev文件配置如下 但是在启动项目之后 通过process env VUE APP SCISERVE获取到的变量值一直为undefined 开发环境配置 在配置文件中定义自定义变量时 一定要以 VUE APP
  • WI-FI定位算法原理与介绍

    所谓的定位 就是利用所有可以获取的信息 对用户所在的位置进行推算 得到最大可能的用户位置 定位可以分为很多种定位 基站定位 WI FI定位 GPS定位 甚至地磁定位 几种定位方式各有优缺点 定位方式 精度 M 速度 耗电量 适用范围 基站定
  • Scikit-Learn 机器学习笔记 -- 线性回归、逻辑回归、softmax回归

    Scikit Learn 机器学习笔记 线性回归 逻辑回归 softmax回归 参考文档 handson ml import numpy as np from matplotlib import pyplot as plt 创建线性回归数据
  • 河北计算机等级考试但不包含职称,河北省计算机等级考试但不包含职称的页面(河北省计算机等级考试时间)...

    最佳案可以的 职称计算机在考试时 往往解决方法不止一种 只要达到最终结果 把题操作对就行了 界通2015年全国职称计算机考试模拟题库软件祝您考试顺利 最佳案职称计算机考试和全国计算机等级考试不是一回事 职称计算机考试是用于评职称的 比如评高
  • Java基础:Callable

    Callable具有返回值 抛出异常 import java util concurrent Callable public class TestCallable implements Callable Override public Bo
  • mysql 数据库字段动态扩展

    主要有一下几种方案 1 动态添加属性字段 当数据库中需要增加一个字段的时候 直接在数据库中增加 并修改相应的代码 优点 操作简单 易懂 缺点 每增加一个字段都需要修改数据库表结构 修改代码 而且在一张大表进行操作的时候 还可能需要很长时间
  • windows下的torch=1.2.0环境配置

    神经网络学习小记录48 windows下的torch 1 2 0环境配置 学习前言 环境内容 Anaconda安装 下载Cudnn和CUDA 配置torch环境 安装VSCODE 学习前言 好多人问环境怎么配置 还是出个教程吧 环境内容 t
  • Vmware 虚拟机 网络设置

    弄了很久 每次重启虚拟机都会网络连接不上 于是 这次弄好了之后 决定记录一下 我的虚拟机 主要用于PHP swoole 需要装在linux 上面 不得不通过虚拟机安装 学习一下 一 关于虚拟机的设置 1 选择NAT 模式 2 设置NAT模式
  • ShardingJDBC数据库中间件学习笔记

    简介 官网地址 https shardingsphere apache org index zh html Apache ShardingSphere 产品定位为 Database Plus 旨在构建多模数据库上层的标准和生态 它关注如何充