专栏首页码猿技术专栏数据库中间件之Mycat

数据库中间件之Mycat

文章目录

1. Mycat入门

1.1. 安装

1.1.1. 常用的命令

1.2. 数据库切分

1.2.1. 垂直切分

1.2.2. 水平切分

1.2.3. 垂直拆分和水平拆分的共同缺点

1.3. 日志分析

1.4. sql防火墙配置

1.5. Mycat配置

1.5.1. schema(逻辑库)

1.5.2. table (逻辑表)

1.5.3. dataNode

1.5.4. dataHost

1.5.5. heartbeat

1.5.6. writeHost 、 readHost

1.5.7. childTable

1.5.8. server.xml中的标签

1.5.8.1. 设置用户

1.5.8.2. system标签

1.6. 全局表

1.7. Mycat的跨分片join

1.7.1. 全局表

1.7.2. ER join

1.7.3. Share Join

1.8. mycat自增主键的配置(数据库方式)

1.8.1. 测试步骤

1.8.2. 参考文章

1.9. Java操作Mycat

1.10. Mycat的事务处理

1.11. Mycat查询

1.11.1. 非分片字段查询

1.11.2. 分页查询

1.11.3. 排序查询

1.11.4. 分页排序查询

1.12. 参考文章

Mycat入门

安装

  • 点击下载
  • 配置java环境
  • 配置mysql数据库
  • 打开conf/wrapper.conf文件,将其中的wrapper.java.command的值改成服务器上的jdk地址,如wrapper.java.command=/usr/local/jdk/jdk1.8.0_172/bin/java
  • 为bin文件夹中的所有内容赋予执行的权限:chmod a+x *
  • 修改schemal.xml文件中的内容,填上对应的表,数据节点,数据主机的内容
  • 启动 :./mycat start (后台启动)、./mycat console(前台启动)
  • 开启服务器的8086端口
  • 使用navicat连接mycat,端口是8086

常用的命令

./mycat start 启动

./mycat stop 停止

./mycat console 前台运行

./mycat install 添加到系统自动启动(暂未实现)

./mycat remove 取消随系统自动启动(暂未实现)

./mycat restart 重启服务

./mycat pause 暂停

./mycat status 查看启动状态

数据库切分

  • 数据库切分分为垂直切分,水平切分

垂直切分

  • 一个数据库由很多表的构成,每个表对应着不同的业务,垂直切分是指按照业务将表进行分类,分布到不同 的数据库上面,这样也就将数据或者说压力分担到不同的库上面 。
  • 比如商城项目可以根据不同的业务将表分成用户表、订单表等,这些表分布在不同的数据库中,从而实现了垂直切分
  • 优点:
    • 拆分后业务清晰,拆分规则明确。
    • 系统之间整合或扩展容易
    • 数据维护简单。
  • 缺点:
    • 部分业务表无法 join,只能通过接口方式解决,提高了系统复杂度。
    • 受每种业务不同的限制存在单库性能瓶颈,不易数据扩展跟性能提高。
    • 事务处理复杂。
  • 由于垂直切分是按照业务的分类将表分散到不同的库,所以有些业务表会过于庞大,存在单库读写与存储瓶 颈,所以就需要水平拆分来做解决。

水平切分

  • 水平拆分不是将表做分类,而是按照某个字段的某种规则来分散到多个库之中,每个表中 包含一部分数据。简单来说,我们可以将数据的水平切分理解为是按照数据行的切分,就是将表中的某些行切分 到一个数据库,而另外的某些行又切分到其他的数据库中
  • 拆分规则:
    • 按照用户 ID 求模,将数据分散到不同的数据库,具有相同数据用户的数据都被分散到一个库中。
    • 按照日期,将不同月甚至日的数据分散到不同的库中。
    • 按照某个特定的字段求摸,或者根据特定范围段分散到不同的库中。
  • 优点:
    • 拆分规则抽象好,join 操作基本可以数据库做。
    • 不存在单库大数据,高并发的性能瓶颈。
    • 应用端改造较少。
    • 提高了系统的稳定性跟负载能力。
  • 缺点:
    • 拆分规则难以抽象。
    • 分片事务一致性难以解决。
    • 数据多次扩展难度跟维护量极大。
    • 跨库 join 性能较差。

垂直拆分和水平拆分的共同缺点

  • 引入分布式事务的问题。
  • 跨节点 Join 的问题。
  • 跨节点合并排序分页问题。
  • 多数据源管理问题。

日志分析

sql防火墙配置

  • 在server.xml中配置

Mycat配置

schema(逻辑库)

  • 一个标签,定义一个逻辑数据库。可以同时指定多个标签来指定不同的逻辑库
  • 标签体的属性如下:
    • dataNode:字符串,该属性用于绑定逻辑库到某个具体的 database 上 ,多个值用逗号分隔
    • checkSQLschema:布尔值,当该值设置为 true 时,如果我们执行语句select * from TESTDB.travelrecord;则 MyCat 会把语句修改 为select * from travelrecord; ,设置这个属性为true,可以在navicat中直接查看逻辑表中的所有数据,否则将会报异常(Table ‘testdb.travelrecord’ doesn’ t exist)
    • sqlMaxLimit:当该值设置为某个数值时。每条执行的 SQL 语句,如果没有加上 limit 语句,MyCat 也会自动的加上所对应 的值。例如设置值为 100,执行select * from TESTDB.travelrecord;的效果为和执行select * from TESTDB.travelrecord limit 100;相同。 设置该值的话,MyCat 默认会把查询到的信息全部都展示出来,造成过多的输出。所以,在正常使用中,还 是建议加上一个值,用于减少过多的数据返回.当然 SQL 语句中也显式的指定 limit 的大小,不受该属性的约束。 需要注意的是,如果运行的 schema 为非拆分库的,那么该属性不会生效。需要手动添加 limit 语句。

table (逻辑表)

  • 属性如下:

name

String

定义逻辑表的表名,这个名字就如同我在数据库中执行 create table 命令指定的名字一样,同个 schema 标 签中定义的名字必须唯一

dataNode

String

定义这个逻辑表所属的 dataNode, 该属性的值需要和 dataNode 标签中 name 属性的值相互对应。多个值用逗号分隔

rule

String

该属性用于指定逻辑表要使用的规则名字,规则名字在 rule.xml 中定义,必须与 tableRule 标签中 name 属 性属性值一一对应

ruleRequired

boolean

该属性用于指定表是否绑定分片规则,如果配置为 true,但没有配置具体 rule 的话 ,程序会报错。

primaryKey

String

该逻辑表对应真实表的主键,例如:分片的规则是使用非主键进行分片的,那么在使用主键查询的时候,就 会发送查询语句到所有配置的 DN 上,如果使用该属性配置真实表的主键。难么 MyCat 会缓存主键与具体 DN 的 信息,那么再次使用非主键进行查询的时候就不会进行广播式的查询,就会直接发送语句给具体的 DN,但是尽管 配置该属性,如果缓存并没有命中的话,还是会发送语句给具体的 DN,来获得数据。如果没有指定,那么默认使用的是主键字段是id

type

String

该属性定义了逻辑表的类型,目前逻辑表只有“全局表”和”普通表”两种类型。对应的配置: 1、全局表:global。 2、 普通表:不指定该值为 globla 的所有表

autoIncrement

boolean

mysql 对非自增长主键,使用 last_insert_id()是不会返回结果的,只会返回 0。所以,只有定义了自增长主 键的表才可以用 last_insert_id()返回主键值。 mycat 目前提供了自增长主键功能,但是如果对应的 mysql 节点上数据表,没有定义 auto_increment,那 么在 mycat 层调用 last_insert_id()也是不会返回结果的。 由于 insert 操作的时候没有带入分片键,mycat 会先取下这个表对应的全局序列,然后赋值给分片键。这样 才能正常的插入到数据库中,最后使用 last_insert_id()才会返回插入的分片键值。 如果要使用这个功能最好配合使用数据库模式的全局序列。 75 使用 autoIncrement=“true” 指定这个表有使用自增长主键,这样 mycat 才会不抛出分片键找不到的异 常。 使用 autoIncrement=“false” 来禁用这个功能,当然你也可以直接删除掉这个属性。默认就是禁用的。

subTables

String

needAddLimit

boolean

指定表是否需要自动的在每个语句后面加上 limit 限制。由于使用了分库分表,数据量有时会特别巨大。这时 候执行查询语句,如果恰巧又忘记了加上数量限制的话。那么查询所有的数据出来,也够等上一小会儿的。 所以,mycat 就自动的为我们加上 LIMIT 100。当然,如果语句中有 limit,就不会在次添加了。 这个属性默认为 true,你也可以设置成 false`禁用掉默认行为。

dataNode

  • 数据节点,用来设置

name

String

定义数据节点的名字,这个名字需要是唯一的,我们需要在 table 标签上应用这个名字,来建立表与分片对 应的关系

dataHost

String

该属性用于定义该分片属于哪个数据库实例的,属性值是引用 dataHost 标签上定义的 name 属性。

database

String

该属性用于定义该分片属性哪个具体数据库实例上的具体库,因为这里使用两个纬度来定义分片,就是:实 例+具体的库。因为每个库上建立的表和表结构是一样的。所以这样做就可以轻松的对表进行水平拆分

dataHost

  • 作为 Schema.xml 中最后的一个标签,该标签在 mycat 逻辑库中也是作为最底层的标签存在,直接定义了具 体的数据库实例、读写分离配置和心跳语句。现在我们就解析下这个标签。
  • 配置如下:

name

String

唯一标识 dataHost 标签,供上层的标签使用。

maxCon

Integer

指定每个读写实例连接池的最大连接。也就是说,标签内嵌套的 writeHost、 readHost 标签都会使用这个属 性的值来实例化出连接池的最大连接数

minCon

Integer

指定每个读写实例连接池的最小连接,初始化连接池的大小

balance

Integer

负载均衡类型,目前的取值有 3 种: 1. balance=”0”, 不开启读写分离机制,所有读操作都发送到当前可用的 writeHost 上。 2. balance=”1”,全部的 readHost 与 stand by writeHost 参与 select 语句的负载均衡,简单的说,当双 主双从模式(M1->S1,M2->S2,并且 M1 与 M2 互为主备),正常情况下,M2,S1,S2 都参与 select 语句的负载 均衡。 3. balance=”2”,所有读操作都随机的在 writeHost、 readhost 上分发。 4. balance=”3”,所有读请求随机的分发到 wiriterHost 对应的 readhost 执行,writerHost 不负担读压 力,注意 balance=3 只在 1.4 及其以后版本有,1.3 没有。

writeType

Integer

负载均衡类型,目前的取值有 3 种: 1. writeType=”0”, 所有写操作发送到配置的第一个 writeHost,第一个挂了切到还生存的第二个 writeHost,重新启动后已切换后的为准,切换记录在配置文件中:dnindex.properties . 2. writeType=”1”,所有写操作都随机的发送到配置的 writeHost,1.5 以后废弃不推荐。

dbType

String

指定后端连接的数据库类型,目前支持二进制的 mysql 协议,还有其他使用 JDBC 连接的数据库。例如: mongodb、 oracle、 spark 等。

dbDriver

String

指定连接后端数据库使用的 Driver,目前可选的值有 native 和 JDBC。使用 native 的话,因为这个值执行的 是二进制的 mysql 协议,所以可以使用 mysql 和 maridb。其他类型的数据库则需要使用 JDBC 驱动来支持。 从 1.6 版本开始支持 postgresql 的 native 原始协议。 如果使用 JDBC 的话需要将符合 JDBC 4 标准的驱动 JAR 包放到 MYCAT\lib 目录下,并检查驱动 JAR 包中 包括如下目录结构的文件:META-INF\services\java.sql.Driver。在这个文件内写上具体的 Driver 类名,例如: com.mysql.jdbc.Driver。

switchType

Integer

-1 表示不自动切换 1 默认值,自动切换 2 基于 MySQL 主从同步的状态决定是否切换 心跳语句为 show slave status 3 基于 MySQL galary cluster 的切换机制(适合集群)(1.4.1) 心跳语句为 show status like ‘wsrep%’. 这个和writeType结合使用

heartbeat

  • 这个标签内指明用于和后端数据库进行心跳检查的语句。例如,MYSQL 可以使用select user(),Oracle 可以 使用 select 1 from dual等。 这个标签还有一个 connectionInitSql属性,主要是当使用 Oracla 数据库时,需要执行的初始化 SQL 语句就 这个放到这里面来。例如:alter session set nls_date_format=’yyyy-mm-dd hh24:mi:ss’ 1.4 主从切换的语句必须是:show slave status

writeHost 、 readHost

  • 这两个标签都指定后端数据库的相关配置给 mycat,用于实例化后端连接池。唯一不同的是,writeHost 指 定写实例、 readHost 指定读实例,组着这些读写实例来满足系统的要求
  • 在一个 dataHost 内可以定义多个 writeHost 和 readHost。但是,如果 writeHost 指定的后端数据库宕机, 那么这个 writeHost 绑定的所有 readHost 都将不可用。另一方面,由于这个 writeHost 宕机系统会自动的检测 到,并切换到备用的 writeHost 上去
  • 这两个标签的属性相同,这里就一起介绍。

host

String

用于标识不同实例,一般 writeHost 我们使用M1,readHost 我们用S1。

url

String

后端实例连接地址,如果是使用 native 的 dbDriver,则一般为 address:port 这种形式。用 JDBC 或其他的 dbDriver,则需要特殊指定。当使用 JDBC 时则可以这么写:jdbc:mysql://localhost:3306/。

password

String

后端存储实例需要的用户名字 ,即是指向mysql的密码

user

String

后端存储实例需要的密码 ,即是指向mysql的用户

weight

String

权重 配置在 readhost 中作为读节点的权重(1.4 以后)

usingDecrypt

String

是否对密码加密默认 0 否 如需要开启配置 1,同时使用加密程序对密码加密

childTable

  • childTable 标签用于定义 E-R 分片的子表。通过标签上的属性与父表进行关联。

name

String

定义子表的表名。

joinKey

String

插入子表的时候会使用这个列的值查找父表存储的数据节点

parentKey

String

属性指定的值一般为与父表建立关联关系的列名。程序首先获取 joinkey 的值,再通过 parentKey 属性指定 的列名产生查询语句,通过执行该语句得到父表存储在哪个分片上。从而确定子表存储的位置。

primaryKey

String

同 table 标签所描述的

needAddLimit

boolean

同 table 标签所描述的

autoIncrement

boolean

设置是否主键自增

server.xml中的标签

设置用户

<!--
		user标签可以设置登录的用户,可以指定多个
		
		<property name="password">: 设置该用户登录的密码
		
		<property name="schemas"> :设置该用户可以访问的逻辑库,如果有多个,那么需要使用逗号分隔
		
		<property name="readOnly">true</property> : 设置该用户是否对逻辑库为只读权限
		
		<property name="benchmark">11111</property>: mycat 连接服务降级处理:benchmark 基准, 当前端的整体 connection 数达到基准值是, 对来自该账户的请求开始拒绝连接, 0 或不设
表示不限制
		
		<property name="usingDecrypt">1</property>:是否对密码加密默认 0 否 如需要开启配置 1,同时使用加密程序对密码加密
		
		privileges 子节点:对用户的 schema 及 下级的 table 进行精细化的 DML 权限控制,privileges 节点中的 check 属性是用
于标识是否开启 DML 权限检查, 默认 false 标识不检查,当然 privileges 节点不配置,等同 check=false,
由于 Mycat 一个用户的 schemas 属性可配置多个 schema ,所以 privileges 的下级节点 schema 节点同样
可配置多个,对多库多表进行细粒度的 DML 权限控制

				schema 标签: 指定逻辑库的名称,用来选择对应的表,可以有多个

        				dml:设置对指定表的crud操作,分别是insert,update,select,delete,对应的如果是0表示禁止,1表示不禁止
		
		
		
	-->
	<user name="root">
		<property name="password">123456</property>
		<property name="schemas">Test</property>
		
		<!-- 表级 DML 权限设置 -->
		<!-- 		
		<privileges check="false">
			<schema name="TESTDB" dml="0110" >
				<table name="tb01" dml="0000"></table>
				<table name="tb02" dml="1111"></table>
			</schema>
			
			<schema name="TESTDB" dml="0110" >
				<table name="tb01" dml="0000"></table>
				<table name="tb02" dml="1111"></table>
			</schema>
			
		</privileges>		
		 -->
	</user>

system标签

  • 这个标签内嵌套的所有 property 标签都与系统配置有关,请注意,下面我会省去标签 property 直接使用这 个标签的 name 属性内的值来介绍这个属性的作用。

属性

作用

概要

charset

字符集设置。

配置字符集的时候一定要坚持 mycat 的字符集与数据库端的字符集是一致的,可以通过变量来查询。比如<property name="charset">utf8</property>

defaultSqlParser

1.3 解析器默认为 fdbparser,1.4 默认为 druidparser,1.4 以后 fdbparser 作废。

由于 mycat 最初是时候 Foundation DB 的 sql 解析器,而后才添加的 Druid 的解析器。所以这个属性用来 指定默认的解析器。目前的可用的取值有:druidparser 和 fdbparser。使用的时候可以选择其中的一种,目前一 般都使用 druidparser

processors

这个属性主要用于指定系统可用的线程数,默认值为机器 CPU 核心线程数。 主要影响 processorBufferPool、 processorBufferLocalPercent、 processorExecutor 属性。 NIOProcessor 的个数也是由这个属性定义的,所以调优的时候可以适当的调高这个属性。

processorBufferChunk

这个属性指定每次分配 Socket Direct Buffer 的大小,默认是 4096 个字节。这个属性也影响 buffer pool 的 长度。如果一次性获取的数过大 buffer 不够用 经常出现警告,则可以适当调大。

processorBufferPool

这个属性指定 bufferPool 计算 比例值。由于每次执行 NIO 读、写操作都需要使用到 buffer,系统初始化的 时候会建立一定长度的 buffer 池来加快读、写的效率,减少建立 buffer 的时间。 Mycat 中有两个主要的 buffer 池: - BufferPool - ThreadLocalPool BufferPool 由 ThreadLocalPool 组合而成,每次从 BufferPool 中获取 buffer 都会优先获取 ThreadLocalPool 中的 buffer,未命中之后才会去获取 BufferPool 中的 buffer。也就是说 ThreadLocalPool 是 作为 BufferPool 的二级缓存,每个线程内部自己使用的。当然,这其中还有一些限制条件需要线程的名字是由$_ 开头。然而,BufferPool 上的 buffer 则是每个 NIOProcessor 都共享的。 默认这个属性的值为: 默认 bufferChunkSize(4096) processors 属性 1000 BufferPool 的总长度 = bufferPool / bufferChunk。 若 bufferPool 不是 bufferChunk 的整数倍,则总长度为前面计算得出的商 + 1 假设系统线程数为 4,其他都为属性的默认值,则: bufferPool = 4096 4 1000 BufferPool 的总长度 : 4000 = 16384000 / 4096

processorBufferLocalPercent

前面提到了 ThreadLocalPool。这个属性就是用来控制分配这个 pool 的大小用的,但其也并不是一个准确 的值,也是一个比例值。这个属性默认值为 100。 线程缓存百分比 = bufferLocalPercent / processors 属性。 例如,系统可以同时运行 4 个线程,使用默认值,则根据公式每个线程的百分比为 25。最后根据这个百分比 来计算出具体的 ThreadLocalPool 的长度公式如下: ThreadLocalPool 的长度 = 线程缓存百分比 BufferPool 长度 / 100 假设 BufferPool 的长度为 4000,其他保持默认值。 那么最后每个线程建立上的 ThreadLocalPool 的长度为: 1000 = 25 4000 / 100

processorExecutor

这个属性主要用于指定 NIOProcessor 上共享的 businessExecutor 固定线程池大小。 mycat 在需要处理一 些异步逻辑的时候会把任务提交到这个线程池中。新版本中这个连接池的使用频率不是很大了,可以设置一个较 小的值

sequnceHandlerType

指定使用 Mycat 全局序列的类型。 0 为本地文件方式,1 为数据库方式,2 为时间戳序列方式,3 为分布式 ZK ID 生成器,4 为 zk 递增 id 生成。

handleDistributedTransactions

分布式事务开关,0为不过滤分布式事务,1为过滤分布式事务(如果分布式事务内只涉及全局表,则不过滤),2为不过滤分布式事务,但是记录分布式事务日志

全局表

  • mycat中使用type定义全局表和普通表(type=global),没有定义type的类型的都是普通表,是需要分片的
  • 全局表适合那些数据量比较少的,变动不是很频繁的
  • 全局表的插入,更新操作会实时在所有节点上执行,保持各个分片的数据一致性。没有太激烈的update操作。
  • 全局表查询只从一个节点获取
  • 全局表可以和任何一个表进行JOIN操作
  • 需要注意的是,全局表每个分片节点上都要有运行创建表的 DDL 语句。

Mycat的跨分片join

  • 同一个分片的数据可以任意的join,join的数量也没有限制,但是不同分片的数据跨分片join的话,是查询不到结果的

全局表

  • 全局表在每一个分片上都保持着相同的数据,因此全局表可以和任意的表跨分片join

ER join

  • 我们可以根据ER关系设置每张表的关系,比如订单表依赖于用户表,我们可以设置ER join方式的,那么会根据外键(joinKey)的值和相关依赖的表分配在同一个分片上,那么就可以join了
  • 支持多表join
  • 配置如下(其中childTable中也可以嵌套childTable):
<table name="t_user" dataNode="dn1,dn2,dn3" rule="auto-sharding-long" primaryKey="id" autoIncrement="true">
			<!--订单表,
			joinKey是t_order和t_user关联的外键关系,
			parentKey指定的是t_user表中的主键
			primaryKey:指定的是t_order的主键
			autoIncrement:设置是否主键自增
-->
			<childTable name="t_order" joinKey="user_id" parentKey="id" primaryKey="id" autoIncrement="true"/>
</table>

Share Join

mycat自增主键的配置(数据库方式)

  • 在mycat中并没有实现mysql的自增主键的配置,如果需要实现的话,需要自己配置。
  • 自增主键的方式配置有多种方式,比如本地方式,数据库方式,ZK方式,时间戳的方式,这里我们测试的是数据库的方式。

测试步骤

1、修改server.xml中生成方式为数据库生成的方式

<!--将sequnceHandlerType设置为1-->
<property name="sequnceHandlerType">1</property>

2、在schema.xml中,table中增加属性autoIncrement值为true,添加mycat_sequence

<schema name="Test" checkSQLschema="true">
		<!-- auto sharding by id (long)
 		rule:指定分片的规则为根据Id自动分片
		primaryKey: 指定主键
		autoIncrement: 指定自增长,一定要为true
		-->
		<table name="t_item" dataNode="dn1,dn2,dn3" rule="auto-sharding-long" primaryKey="id" autoIncrement="true"  />
    	<!--指定自增长的表,数据节点为dn1-->
		<table name="mycat_sequence" primaryKey="name" dataNode="dn1" />
		
	</schema>
	<dataNode name="dn1" dataHost="localhost1" database="db1" />
	<dataNode name="dn2" dataHost="localhost1" database="db2" />
	<dataNode name="dn3" dataHost="localhost1" database="db3" />

3、在数据节点dn1的数据库db1中新建mycat_sequence的表,如下:

1、name:sequence:名称

2、currenct_value:当前value

3、increment:增长步长
DROP TABLE IF EXISTS MYCAT_SEQUENCE;   
CREATE TABLE MYCAT_SEQUENCE(   
    name VARCHAR(50) NOT NULL,  
    current_value INT NOT NULL,  
    increment INT NOT NULL DEFAULT 100,  
    PRIMARY KEY(name)  
) ENGINE=InnoDB;

4、在db1数据中创建存储函数,用来维持自增长

-- 获取当前sequence的值 (返回当前值,增量)  
DROP FUNCTION IF EXISTS mycat_seq_currval;  
DELIMITER $  
CREATE FUNCTION mycat_seq_currval(seq_name VARCHAR(50)) RETURNS varchar(64) CHARSET utf8  
DETERMINISTIC  
BEGIN  
DECLARE retval VARCHAR(64);  
SET retval="-999999999,null";  
SELECT concat(CAST(current_value AS CHAR),",",CAST(increment AS CHAR)) INTO retval FROM MYCAT_SEQUENCE WHERE name = seq_name;  
RETURN retval;  
END $  
DELIMITER ;  
      
-- 设置sequence值  
DROP FUNCTION IF EXISTS mycat_seq_setval;  
DELIMITER $  
CREATE FUNCTION mycat_seq_setval(seq_name VARCHAR(50),value INTEGER) RETURNS varchar(64) CHARSET utf8  
DETERMINISTIC  
BEGIN  
UPDATE MYCAT_SEQUENCE  
SET current_value = value  
WHERE name = seq_name;  
RETURN mycat_seq_currval(seq_name);  
END $  
DELIMITER ;  
    
-- 获取下一个sequence值  
DROP FUNCTION IF EXISTS mycat_seq_nextval;  
DELIMITER $  
CREATE FUNCTION mycat_seq_nextval(seq_name VARCHAR(50)) RETURNS varchar(64) CHARSET utf8  
DETERMINISTIC  
BEGIN  
UPDATE MYCAT_SEQUENCE  
SET current_value = current_value + increment WHERE name = seq_name;  
RETURN mycat_seq_currval(seq_name);  
END $  
DELIMITER ;

5、在mycat_sequence表中插入数据,用来记录t_item表的自增长数据,名称必须全部大写

​ 1、当然这里一条数据就代表一张表自增长,如果想要其他的表也能自增长,那么直接添加即可

INSERT INTO MYCAT_SEQUENCE(name, current_value, increment) VALUES ('T_TIEM', 0,1);

6、在conf/sequence_db_conf.properties的文件中添加依赖全局序列,增加序列,与table名称相同全大写

# T_ITEM是自增长的表,dn1是mycat_sequence所在的数据节点,之后每添加一张自增长的表,只需要在其中添加即可
T_ITEM=dn1

7、测试,向t_item表中添加数据

INSERT INTO t_item(name) values("chenjiabing");

8、测试使用mybatis添加数据

@Insert("INSERT into t_item(name) values(#{name})")
@Options(useGeneratedKeys = true,keyProperty = "id")   //自增长主键返回
void insert(Item item);

参考文章

Java操作Mycat

  • 只需要将连接mysql的端口改成8066即可,其他的就像是操作mysql一样

Mycat的事务处理

  • Mycat 目前没有出来跨分片的事务强一致性支持,目前单库内部可以保证事务的完整性,如果跨库事务, 在执行的时候任何分片出错,可以保证所有分片回滚,但是一旦应用发起 commit 指令,无法保证所有分片都成 功,考虑到某个分片挂的可能性不大所以称为弱 XA。
  • 也就是说,我们在单体应用中可以正常使用spring提供的事务管理器进行事务的管理,在处理出现异常的时候也是可以回滚的。

Mycat查询

非分片字段查询

  • 如果查询条件中有分片字段的话,那么mycat就可以轻松的根据分片规则找到对应的数据节点,然后在对应节点中查询,比如使用的是id取模分片规则,那么此时的id就是分片字段,一旦查询条件中有id这个字段的,就可以根据id的值定位到指定的节点中查询,否则将会在每个节点中执行sql语句,然后将每个节点的返回结果汇总返回

分页查询

  • mycat针对分页查询的执行逻辑如下:
    • 根据sql语句的过滤条件到每个数据节点筛选数据,筛选完成之后返回各个节点的分页数据
    • mycat会判断哪个节点先返回数据,真正返回给客户端的就是先返回数据的那个节点上的数据库中
  • 根据上面的分析,我们可以判断分页查询的数据每次都是不同的,不同数据节点的返回速度决定着分页查询的数据显示。
  • 解决办法:在分页查询的时候必要的时候进行排序,这样返回的结果才是正确的,不然每次返回的结果可能不同,比如select * from t_item order by id desc limit 1,29

排序查询

  • mycat 的排序查询的执行逻辑如下:
    • 将sql语句发送到各个节点进行筛选数据,返回数据给mycat
    • mycat获取到各个节点的数据的时候会根据 不同的排序规则(升序,降序)对全部节点的数据重新排序,最后所有数据排序完成的结果就是正确的结果

分页排序查询

参考文章

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 设计模式之原型模式

    爱撒谎的男孩
  • Springmvc响应Ajax请求(@ResponseBody)

    爱撒谎的男孩
  • Servlet总结四(过滤器)

    爱撒谎的男孩
  • 10分钟搞懂:亿级用户的分布式数据存储解决方案!

    原文链接:http://www.itpub.net/2019/06/28/2306/

    数据和云01
  • 10分钟搞懂:亿级用户的分布式数据存储解决方案!

    分布式数据库和分布式存储是分布式系统中难度最大、挑战最大,也是最容易出问题的地方。互联网公司只有解决分布式数据存储的问题,才能支撑更多次亿级用户的涌入。

    猿天地
  • 10分钟搞懂:亿级用户的分布式数据存储解决方案!

    主要目的是实现数据库读写分离,写操作访问主数据库,读操作访问从数据库,从而使数据库具有更强大的访问负载能力,支撑更多的用户访问。

    lyb-geek
  • 这么牛x的,亿级用户分布式存储架构,我推荐,收藏,转发

    分布式数据库和分布式存储是分布式系统中难度最大、挑战最大,也是最容易出问题的地方。互联网公司只有解决分布式数据存储的问题,才能支撑更多次亿级用户的涌入。

    搜云库技术团队
  • 10分钟搞懂:亿级用户的分布式数据存储解决方案!

    6月6日晚,林志玲与Akira公布婚讯、徐蔡坤祝福高考同学超常发挥,粉丝们百万的转发和点赞造成微博短暂宕机。

    数据和云
  • 亿级用户分布式存储,这些方案你都会了吗?

    原文:https://segmentfault.com/a/1190000019460946

    JAVA葵花宝典
  • 亿级用户分布式存储

    分布式数据库和分布式存储是分布式系统中难度最大、挑战最大,也是最容易出问题的地方。互联网公司只有解决分布式数据存储的问题,才能支撑更多次亿级用户的涌入。

    lyb-geek

扫码关注云+社区

领取腾讯云代金券