java高级 MyCat

目录

        一、什么是Mycat

        二、为什么使用数据库中间件?

        三、中间件的应用场景

                3.1 读写分离

        3.2:数据分片

        四、Mycat的原理

        五、Mycat完成读写分离

        5.1 搭建mysql数据库的主从模式

                5.1.1:mysql主从模式的原理

        5.1.2:搭建主节点--master

        5.1.3:配置从节点

        六、MyCat完成读写分离

        6.1 验证MyCat完成读写分离

        七、Mycat---垂直分库

        7.1 修改mycat配置文件--schema.xml文件

        7.2 分别再DN1节点和DN2节点创建不同的库

        7.3 通过mycat完成表的创建

        八、Mycat---水平分表

        8.3 修改schema.xml文件  

        8.4 修改rule.xml文件

        8.5 我们orders表只在mydb01库中存在,不在mydb02库中,所以我们需要再mydb02也创建orders表

        九、水平拆分后join

        十、全局表

        十一、常用分表的规则

                11.1 取模

                11.2 分片枚举

                11.3、范围约定

                        11.4 按日期(天)分片

        十二、Mycat的高可用


        一、什么是Mycat

       Mycat数据库中间件,所谓中间件,是一类连接软件组件和应用的计算机软件,以便软件各部件之间的通信。

         例如 tomcat,web的中间件。而数据库中间件是连接Java应用程序和数据库中间的软件

        二、为什么使用数据库中间件?

  • Java与数据库的紧密耦合

  • 高访问量高并发对数据库的压力

  • 读写请求数据不一致

        

        我们现在普遍的Java应用程序都是直接连接了MySQL软件进行读写操作,也就是我们在Java中的配置文件等定义了mysql的数据源,直接连接到了我们的mysql软件,但是当某些情况下我们可能需要用到了多个数据库,这个时候我们可能就需要配多个数据源去连接我们的多个数据库,这个时候我们进行sql操作的时候就会很麻烦,因为Java与数据库有了一个紧密的耦合度,但是如果我们在Java应用程序与mysql中间使用了mycat,我们只需要访问mycat就可以了,至于数据源等问题,mycat会直接帮我们搞定。

        再来说一下高访问量高并发,我们都知道mysql数据库实际上在数据查询上是有一个瓶颈的,当我们的数据太多的时候,对于互联网上有高并发的请求的时候,这个时候对我们mysql的压力是非常大的,当访问量一大,就可能会出现查不出数据,响应的时间太长等,这个时候我们可能需要有多个服务器对数据库进行读写分离,以及对数据库进行集群,这个时候我们的sql语句要进行分类,哪个sql语句要访问哪个数据库,这个时候只要交给中间件就可以了。

        三、中间件的应用场景

                3.1 读写分离

        3.2:数据分片

        垂直拆分(分库)、水平拆分(分表)

        首先我们的数据库有多个表

        

        当我们的表足够多的时候,也会造成整个数据库的瓶颈,这个时候查询是非常慢的,这个时候我们可能要对这个数据库进行垂直拆分,也就是分库

        我们需要垂直拆分了表4 5 6 放到另外一个库中。

当我们垂直拆分了之后,可能又会出现单个表中的数据达到千万以上,这个时候对表造成了一个瓶颈,这个时候我们对表进行拆分。

 

         我们可以把表的一部分数据拆分到另外的一个数据库。       

        中间件---完成: (1)读写分离 (2)垂直分库 (3)水平分表   

        四、Mycat的原理

        Mycat 的原理中最重要的一个动词是“拦截”,它拦截了用户发送过来的 SQL 语句,首先对 SQL 语句做了一些特定的分析:如分片分析路由分析读写分离分析、缓存分析等,然后将此 SQL 发 往后端的真实数据库,并将返回的结果做适当的处理,最终再返回给用户。

          这种方式把数据库的分布式从代码中解耦出来,程序员察觉不出来后台使用 Mycat 还是 MySQL

        五、Mycat完成读写分离

                

        从上面的从我们可以看出,mycat可以对sql进行读写分离的操作。 当执行的sql语句为查询则访问从节点MySQL,如果执行的sql语句为写操作则访问主节点。

        5.1 搭建mysql数据库的主从模式

                5.1.1:mysql主从模式的原理

        从上层来看,复制分成三步:

  • Master 主库在事务提交时,会把数据变更作为事件Events 记录在二进制日志文件 Binlog 中。

  • 主库推送二进制日志文件 Binlog 中的日志事件到从库的中继日志 Relay Log 。

  • slave重做中继日志中的事件,将改变反映它自己的数据。  

                准备的条件

        1. 安装数据库----如果没安装就查看这个网址---https://www.cnblogs.com/tony-hyn/p/15777762.html
        2. 启动mysql -----systemctl start mysqld
        3. 查看mysql是否设置了远程连接.  window中的navicat连接mysql. 

                克隆一份虚拟机 

        

         修改mysql的UUID保证不一样

         

         找到 find -name auto.cnf 并删除该问题

         重启mysql服务器

        

        5.1.2:搭建主节点--master

        158作为主节点

                在master 的配置文件(/etc/my.cnf)中,配置如下内容:

#mysql 服务ID,保证整个集群环境中唯一
server-id=1

#mysql binlog 日志的存储路径和文件名
log-bin=/var/lib/mysql/mysqlbin

#错误日志,默认已经开启
#log-err

#mysql的安装目录
#basedir

#mysql的临时目录
#tmpdir

#mysql的数据存放目录
#datadir

#是否只读,1 代表只读, 0 代表读写
read-only=0

#忽略的数据, 指不需要同步的数据库
binlog-ignore-db=mysql

#指定同步的数据库
#binlog-do-db=db01

         执行完毕之后,需要重启Mysql:                 systemctl restart mysqld

         查看master状态                         show master status;

         字段含义:

                File : 从哪个日志文件开始推送日志文件
                Position : 从哪个位置开始推送日志
                Binlog_Ignore_DB : 指定不需要同步的数据库

        5.1.3:配置从节点

                在 slave 端/etc/my.cnf配置文件中,配置如下内容:

#mysql服务端ID,唯一
server-id=2

#指定binlog日志
log-bin=/var/lib/mysql/mysqlbin

                执行完毕之后,需要重启Mysql:                 systemctl restart mysqld

                执行如下指令 :---指定主从关系         

change master to master_host= '192.168.223.158', master_user='root', master_password='123456',master_log_file='mysqlbin.000001',master_log_pos=154;

         指定当前从库对应的主库的IP地址,用户名,密码,从哪个日志文件开始的那个位置开始同步推送日志。

        开启同步操作

        start slave;

        show slave status\G;

        上面截图的必须是yes才可以。  

                

        停止同步操作:

        stop slave;
        reset master;

        六、MyCat完成读写分离

        

                准备一台mycat服务器。192.168.223.160.

         目录结构

        修改配置文件

  1. schema.xml: 定义我们的逻辑库和节点信息

  2. rule.xml: 定义分表的规则

  3. server.xml 定义mycat账户和密码

        1.修改schema.xml  

<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
    <!-- schema:定义逻辑库的标签
	        name: 逻辑库的名称,
			checkSQLschema: 是否检查sql表结构
			sqlMaxLimit: sql最大的显示条数 根据业务以及服务器配置。
			dataNode: 数据节点的名称。 
	-->
	<schema name="TESTDB" checkSQLschema="true" sqlMaxLimit="100" dataNode="dn1">
		
	</schema>
	<!-- dataNode: 定义数据节点的。
	       name: 数据节点的名称要和上面schema标签中的dataNode属性值一致.
		   dataHost: 数据主机名
		   database: 真实数据库名
	 -->
	<dataNode name="dn1" dataHost="host1" database="qy158" />
	<!-- dataHost:定义数据主机
	        name:主机名称保证和上面dataNode标签中的datHost属性值相同
	 -->
	<dataHost name="host1" maxCon="1000" minCon="10" balance="0"
			  writeType="0" dbType="mysql" dbDriver="jdbc" switchType="1"  slaveThreshold="100">
		<!-- 主从之间的维护靠心跳 -->	  
		<heartbeat>select user()</heartbeat>
		
		<!-- 定义主节点的标签 -->
		<writeHost host="hostM1" url="192.168.223.158:3306" user="root"
				   password="123456">
			<readHost host="slave1" url="192.168.223.159:3306" user="root" password="123456"></readHost>	   
		</writeHost>
		<!-- <writeHost host="hostM2" url="localhost:3316" user="root" password="123456"/> -->
	</dataHost>
	
</mycat:schema>

        2.修改server.xml

        定义逻辑账户和密码

<?xml version="1.0" encoding="UTF-8"?>
<!-- - - Licensed under the Apache License, Version 2.0 (the "License"); 
	- you may not use this file except in compliance with the License. - You 
	may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 
	- - Unless required by applicable law or agreed to in writing, software - 
	distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT 
	WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the 
	License for the specific language governing permissions and - limitations 
	under the License. -->
<!DOCTYPE mycat:server SYSTEM "server.dtd">
<mycat:server xmlns:mycat="http://io.mycat/">

	<!-- user定义逻辑账户的标签
	         name:表示逻辑账户名
	 -->
	<user name="aaa">
		<!-- 逻辑密码 -->
		<property name="password">******</property>
		<!-- 关联的逻辑库schema中的名称对应 -->
		<property name="schemas">TESTDB</property>
	</user>
</mycat:server>

        3. 启动MyCat

        6.1 验证MyCat完成读写分离

        springboot+整合mybatis-plus

        原因是mycat使用的mysql驱动版本为5.1的 而springboot的mysql驱动8.0的。 必须保证他们的版本号一致  

        

         从上面的结果无法看出读取的是主节点还是从节点的数据。为了让你能看出从slave节点读取的数据,我们故意让从节点的数据与主节点不一致。

        七、Mycat---垂直分库

         一个数据库由很多表的构成,每个表对应着不同的业务,垂直切分是指按照业务将表进行分类, 分布到不同 的数据库上面,这样也就将数据或者说压力分担到不同的库上面

        分库的原则:

                一个问题:在两台主机上的两个数据库中的表,能否关联查询?        不能

         分库的原则:有紧密关联关系的表应该在一个库里,相互没有关联关系的表可以分到不同的库里。

#客户表 rows:20万
CREATE TABLE customer(
 id INT AUTO_INCREMENT,
 NAME VARCHAR(200),
 PRIMARY KEY(id)
);
#订单表 rows:600万
CREATE TABLE orders(
 id INT AUTO_INCREMENT,
 order_type INT,
 customer_id INT,
 amount DECIMAL(10,2),
 PRIMARY KEY(id) 
); 
#订单详细表 rows:600万
CREATE TABLE orders_detail(
 id INT AUTO_INCREMENT,
 detail VARCHAR(2000),
 order_id INT,
 PRIMARY KEY(id)
);
#订单状态字典表 rows:20
CREATE TABLE dict_order_type(
 id INT AUTO_INCREMENT,
 order_type VARCHAR(200),
 PRIMARY KEY(id)
);

        客户表----独立放入一个库中.

订单表 订单详情表 订单状态表----独立放入一个库中

        为了减少服务器的启动数量.---我们就把原来的主从关系先取消  

                 stop slave; 关闭主从关系

        7.1 修改mycat配置文件--schema.xml文件

<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
    <!-- schema:定义逻辑库的标签
	        name: 逻辑库的名称,
			checkSQLschema: 是否检查sql表结构
			sqlMaxLimit: sql最大的显示条数 根据业务以及服务器配置。
			dataNode: 数据节点的名称。 
	-->
	<schema name="TESTDB" checkSQLschema="true" sqlMaxLimit="100" dataNode="dn1">
		 <!-- customer表 放入dn2-->
		 <table name="customer" dataNode="dn2"></table>
	</schema>
	<!-- dataNode: 定义数据节点的。
	       name: 数据节点的名称要和上面schema标签中的dataNode属性值一致.
		   dataHost: 数据主机名
		   database: 真实数据库名
	 -->
	<dataNode name="dn1" dataHost="host1" database="mydb01" />
	<dataNode name="dn2" dataHost="host2" database="mydb02" />
	<!-- dataHost:定义数据主机
	        name:主机名称保证和上面dataNode标签中的datHost属性值相同
	 -->
	<dataHost name="host1" maxCon="1000" minCon="10" balance="0"
			  writeType="0" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100">
		<!-- 主从之间的维护靠心跳 -->	  
		<heartbeat>select user()</heartbeat>
		<!-- 定义主节点的标签 -->
		<writeHost host="hostM1" url="192.168.223.158:3306" user="root"
				   password="123456">
		</writeHost>
		<!-- <writeHost host="hostM2" url="localhost:3316" user="root" password="123456"/> -->
	</dataHost>
	
	<dataHost name="host2" maxCon="1000" minCon="10" balance="0"
			  writeType="0" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100">
		<!-- 主从之间的维护靠心跳 -->	  
		<heartbeat>select user()</heartbeat>
		<!-- 定义主节点的标签 -->
		<writeHost host="hostM1" url="192.168.223.159:3306" user="root"
				   password="123456">
		</writeHost>
		<!-- <writeHost host="hostM2" url="localhost:3316" user="root" password="123456"/> -->
	</dataHost>
	
</mycat:schema>

        7.2 分别再DN1节点和DN2节点创建不同的库

                dn1=====>mydb01
                dn2=====>mydb02

        7.3 通过mycat完成表的创建

                mysql -uaaa -P 8066 -h 192.168.223.160 -p123456

        -u: mycat逻辑账户

        -P: mycat的端口号

        -h: mycat服务端的ip

        -p: mycat的逻辑密码

#客户表 rows:20万
CREATE TABLE customer(
 id INT AUTO_INCREMENT,
 NAME VARCHAR(200),
 PRIMARY KEY(id)
);
#订单表 rows:600万
CREATE TABLE orders(
 id INT AUTO_INCREMENT,
 order_type INT,
 customer_id INT,
 amount DECIMAL(10,2),
 PRIMARY KEY(id) 
); 
#订单详细表 rows:600万
CREATE TABLE orders_detail(
 id INT AUTO_INCREMENT,
 detail VARCHAR(2000),
 order_id INT,
 PRIMARY KEY(id)
);
#订单状态字典表 rows:20
CREATE TABLE dict_order_type(
 id INT AUTO_INCREMENT,
 order_type VARCHAR(200),
 PRIMARY KEY(id)
);

        八、Mycat---水平分表

    1、简介

        相对于垂直拆分,水平拆分不是将表做分类,而是按照某个字段的某种规则来分散到多个库之中,每个表中包含一部分数据。简单来说,我们可以将数据的水平切分理解为是按照数据行的切分,就是将表中的某些行切分 到一个数据库,而另外的某些行又切分到其他的数据库中

     2、水平分表按照什么列来分?                        例如: 订单表

                        订单表 rows:1000万

CREATE TABLE orders(
id INT AUTO_INCREMENT,
order_type INT,
customer_id INT,
amount DECIMAL(10,2),
PRIMARY KEY(id) 
); 

        按照一列进行拆分。

        按照id---- 查询订单时---查询最近的订单数据。---之前的订单很少有人访问

        按照订单的日期---双11 双12 ---这种日期的数据存入一张表---该表的记录会非常多。

        客户id---->比较均匀的分到相应的表中,而且访问也比较均匀。

        8.3 修改schema.xml文件  

<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
    <!-- schema:定义逻辑库的标签
	        name: 逻辑库的名称,
			checkSQLschema: 是否检查sql表结构
			sqlMaxLimit: sql最大的显示条数 根据业务以及服务器配置。
			dataNode: 数据节点的名称。 
	-->
	<schema name="TESTDB" checkSQLschema="true" sqlMaxLimit="100" dataNode="dn1">
		 <!-- customer表 放入dn2-->
		 <table name="customer" dataNode="dn2"></table>
		 <!-- rule:规则:表示orders表中的记录按照该规则分配到dn1和dn2节点上-->
		 <table name="orders" dataNode="dn1,dn2" rule="mod_rule"></table>
	</schema>
	<!-- dataNode: 定义数据节点的。
	       name: 数据节点的名称要和上面schema标签中的dataNode属性值一致.
		   dataHost: 数据主机名
		   database: 真实数据库名
	 -->
	<dataNode name="dn1" dataHost="host1" database="mydb01" />
	<dataNode name="dn2" dataHost="host2" database="mydb02" />
	<!-- dataHost:定义数据主机
	        name:主机名称保证和上面dataNode标签中的datHost属性值相同
	 -->
	<dataHost name="host1" maxCon="1000" minCon="10" balance="0"
			  writeType="0" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100">
		<!-- 主从之间的维护靠心跳 -->	  
		<heartbeat>select user()</heartbeat>
		<!-- 定义主节点的标签 -->
		<writeHost host="hostM1" url="192.168.223.158:3306" user="root"
				   password="123456">
		</writeHost>
		<!-- <writeHost host="hostM2" url="localhost:3316" user="root" password="123456"/> -->
	</dataHost>
	
	<dataHost name="host2" maxCon="1000" minCon="10" balance="0"
			  writeType="0" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100">
		<!-- 主从之间的维护靠心跳 -->	  
		<heartbeat>select user()</heartbeat>
		<!-- 定义主节点的标签 -->
		<writeHost host="hostM1" url="192.168.223.159:3306" user="root"
				   password="123456">
		</writeHost>
		<!-- <writeHost host="hostM2" url="localhost:3316" user="root" password="123456"/> -->
	</dataHost>
	
</mycat:schema>

        8.4 修改rule.xml文件

                该文件是用来定义分表的规则

        8.5 我们orders表只在mydb01库中存在,不在mydb02库中,所以我们需要再mydb02也创建orders表

        #订单表 rows:600万
CREATE TABLE orders(
 id INT AUTO_INCREMENT,
 order_type INT,
 customer_id INT,
 amount DECIMAL(10,2),
 PRIMARY KEY(id)
);

        通过mycat往orders表添加数据。

        分表插入数据时,必须提高列的列表。因为你如果不提供人家无法知道对应那一列的值  

        INSERT INTO orders(id,order_type,customer_id,amount) VALUES (1,101,100,100100);
        INSERT INTO orders(id,order_type,customer_id,amount) VALUES(2,101,100,100300);
        INSERT INTO orders(id,order_type,customer_id,amount) VALUES(3,101,101,120000);
        INSERT INTO orders(id,order_type,customer_id,amount) VALUES(4,101,101,103000);
        INSERT INTO orders(id,order_type,customer_id,amount) VALUES(5,102,101,100400);
        INSERT INTO orders(id,order_type,customer_id,amount) VALUES(6,102,100,100020);

         最终效果:

 

        九、水平拆分后join

        join:联表查询。

        思考: 如果订单详情表和订单表进行联表查询,由于订单表中的记录被拆分到两个库中了,而我们的订单详情表在一个库中存在,那么如果真的要联表查询的化,订单详情只会关联当前库中的订单表。

        原则:

        使用ER表解决上面的字表关联查询的问题,其将子表的存储位置依赖于主表,并且物理上紧邻存放,因此彻底解决了JION 的效率和性能问 题,根据这一思路,提出了基于E-R 关系的数据分片策略,子表的记录与所关联的父表记录存放在同一个数据分片上。

        修改schema.xml 

<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
    <!-- schema:定义逻辑库的标签
	        name: 逻辑库的名称,
			checkSQLschema: 是否检查sql表结构
			sqlMaxLimit: sql最大的显示条数 根据业务以及服务器配置。
			dataNode: 数据节点的名称。 
	-->
	<schema name="TESTDB" checkSQLschema="true" sqlMaxLimit="100" dataNode="dn1">
		 <!-- customer表 放入dn2-->
		 <table name="customer" dataNode="dn2"></table>
		 <!-- rule:规则:表示orders表中的记录按照该规则分配到dn1和dn2节点上-->
		 <table name="orders" dataNode="dn1,dn2" rule="mod_rule">
			  <!-- childTable:orders的子表
			           name:子表的名称
					   primaryKey: 子表的主键
					   joinKey: 子表中的外键列
					   parentKey: 关联的父表的主键
			  -->
			  <childTable name="orders_detail" primaryKey="id" joinKey="order_id" parentKey="id"/>
		 </table>
	</schema>
	<!-- dataNode: 定义数据节点的。
	       name: 数据节点的名称要和上面schema标签中的dataNode属性值一致.
		   dataHost: 数据主机名
		   database: 真实数据库名
	 -->
	<dataNode name="dn1" dataHost="host1" database="mydb01" />
	<dataNode name="dn2" dataHost="host2" database="mydb02" />
	<!-- dataHost:定义数据主机
	        name:主机名称保证和上面dataNode标签中的datHost属性值相同
	 -->
	<dataHost name="host1" maxCon="1000" minCon="10" balance="0"
			  writeType="0" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100">
		<!-- 主从之间的维护靠心跳 -->	  
		<heartbeat>select user()</heartbeat>
		<!-- 定义主节点的标签 -->
		<writeHost host="hostM1" url="192.168.223.158:3306" user="root"
				   password="123456">
		</writeHost>
		<!-- <writeHost host="hostM2" url="localhost:3316" user="root" password="123456"/> -->
	</dataHost>
	
	<dataHost name="host2" maxCon="1000" minCon="10" balance="0"
			  writeType="0" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100">
		<!-- 主从之间的维护靠心跳 -->	  
		<heartbeat>select user()</heartbeat>
		<!-- 定义主节点的标签 -->
		<writeHost host="hostM1" url="192.168.223.159:3306" user="root"
				   password="123456">
		</writeHost>
		<!-- <writeHost host="hostM2" url="localhost:3316" user="root" password="123456"/> -->
	</dataHost>
	
</mycat:schema>

        在159服务器创建订单详情表 

CREATE TABLE orders_detail(
 id INT AUTO_INCREMENT,
 detail VARCHAR(2000),
 order_id INT,
 PRIMARY KEY(id)
);

        通过mycat添加订单详情表的记录  

INSERT INTO orders_detail(id,detail,order_id) values(7,'detail1',1);
INSERT INTO orders_detail(id,detail,order_id) VALUES(8,'detail1',2);
INSERT INTO orders_detail(id,detail,order_id) VALUES(9,'detail1',3);
INSERT INTO orders_detail(id,detail,order_id) VALUES(10,'detail1',4);
INSERT INTO orders_detail(id,detail,order_id) VALUES(11,'detail1',5);
INSERT INTO orders_detail(id,detail,order_id) VALUES(12,'detail1',6);

        java代码测试 ------联表查询

 @Autowired
    private OrderDetailMapper orderDetailMapper;

    @Test
    public void test08(){
        List<OrderDetail> allWithOrders = orderDetailMapper.findAllWithOrders();
        allWithOrders.stream().forEach(System.out::println);
    }

        dao层

<?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.ykq.dao.OrderDetailMapper">

  <resultMap id="my" type="com.ykq.entity.OrderDetail">
      <id property="id" column="odid" />
      <result property="detail" column="detail"/>
      <result property="orderId" column="order_id"/>
      <association property="orders" javaType="com.ykq.entity.Orders">
          <id property="id" column="oid"/>
           <result property="orderType" column="order_type"/>
           <result property="customerId" column="customer_id"/>
           <result property="amount" column="amount"/>
      </association>
  </resultMap>

  <sql id="aa">
      od.id odid,detail,order_id,o.id oid,order_type,customer_id,amount
  </sql>
  <select id="findAllWithOrders" resultMap="my">
        select  <include refid="aa"/> from orders_detail od join orders o on od.order_id=o.id
  </select>
</mapper>

        十、全局表

        dict---->状态 比如支付状态 性别 0 1

        订单数据字典表.---存放订单得状态---->支付 未支付 取消 待发货 已发货 已确认。。。。

        由于订单数据字典表 再每个节点上都需要。所以我们把数据字典表定义为全局表。

        什么样得表适合做全局表.

  • 变动不频繁

  • 数据量总体变化不大

  • 数据规模不大,很少有超过数十万条记录.

        鉴于此,Mycat 定义了一种特殊的表,称之为“全局表”,全局表具有以下特性:

  • 全局表的插入、更新操作会实时在==所有节点上执行==,保持各个分片的数据一致性

  • 全局表的查询操作,只从一个节点获取

  • 全局表可以跟任何一个表进行 JOIN 操作将字典表或者符合字典表特性的一些表定义为全局表,则从另外一个方面,很好的解决了数据JOIN 的难题。通过全局表+基于 E-R 关系的分片策略,Mycat 可以满足 80%以上的企业应用开发

        修改schema.xml  

<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
    <!-- schema:定义逻辑库的标签
	        name: 逻辑库的名称,
			checkSQLschema: 是否检查sql表结构
			sqlMaxLimit: sql最大的显示条数 根据业务以及服务器配置。
			dataNode: 数据节点的名称。 
	-->
	<schema name="TESTDB" checkSQLschema="true" sqlMaxLimit="100" dataNode="dn1">
		 <!-- customer表 放入dn2-->
		 <table name="customer" dataNode="dn2"></table>
		 <!-- rule:规则:表示orders表中的记录按照该规则分配到dn1和dn2节点上-->
		 <table name="orders" dataNode="dn1,dn2" rule="mod_rule">
			  <!-- childTable:orders的子表
			           name:子表的名称
					   primaryKey: 子表的主键
					   joinKey: 子表中的外键列
					   parentKey: 关联的父表的主键
			  -->
			  <childTable name="orders_detail" primaryKey="id" joinKey="order_id" parentKey="id"/>
		 </table>
		 <!-- type:global表示全局表的意思-->
		 <table name="dict_order_type" dataNode="dn1,dn2" type="global"></table>
	</schema>
	<!-- dataNode: 定义数据节点的。
	       name: 数据节点的名称要和上面schema标签中的dataNode属性值一致.
		   dataHost: 数据主机名
		   database: 真实数据库名
	 -->
	<dataNode name="dn1" dataHost="host1" database="mydb01" />
	<dataNode name="dn2" dataHost="host2" database="mydb02" />
	<!-- dataHost:定义数据主机
	        name:主机名称保证和上面dataNode标签中的datHost属性值相同
	 -->
	<dataHost name="host1" maxCon="1000" minCon="10" balance="0"
			  writeType="0" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100">
		<!-- 主从之间的维护靠心跳 -->	  
		<heartbeat>select user()</heartbeat>
		<!-- 定义主节点的标签 -->
		<writeHost host="hostM1" url="192.168.223.158:3306" user="root"
				   password="123456">
		</writeHost>
		<!-- <writeHost host="hostM2" url="localhost:3316" user="root" password="123456"/> -->
	</dataHost>
	
	<dataHost name="host2" maxCon="1000" minCon="10" balance="0"
			  writeType="0" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100">
		<!-- 主从之间的维护靠心跳 -->	  
		<heartbeat>select user()</heartbeat>
		<!-- 定义主节点的标签 -->
		<writeHost host="hostM1" url="192.168.223.159:3306" user="root"
				   password="123456">
		</writeHost>
		<!-- <writeHost host="hostM2" url="localhost:3316" user="root" password="123456"/> -->
	</dataHost>
	
</mycat:schema>

        通过mycat创建全局表  

CREATE TABLE dict_order_type(
 id INT AUTO_INCREMENT,
 order_type VARCHAR(200),
 PRIMARY KEY(id)
);

        添加数据

INSERT INTO DICT_ORDER_TYPE(id,order_type) VALUES(101,'Pay');
INSERT INTO DICT_ORDER_TYPE(id,order_type) VALUES(102,'NotPay');

        观察到每个节点都存在该表,而且该表的数据内容是一样

        十一、常用分表的规则

                11.1 取模

                此规则为对分片字段求摸运算。也是水平分表最常用规则

                11.2 分片枚举

                 通过在配置文件中配置可能的枚举 id,自己配置分片,本规则适用于特定的场景,比如有些业务需要按照省份或区县来做保存,而全国省份区县固定的,这类业务使用本条规则。

                实现方式如下:1.修改schema.xml配置文件

        测试表为orders_ware_info,配置在dn1和dn2节点,规则是新增一个sharding_by_intfile

                                        2.修改rule.xml配置文件

                                        3.修改partition-hash-int.txt配置文件

                

        表示areacode为110就存到第一个数据节点,为120就存到第二个数据节点  

                                        4.重启Mycat使配置生效

                使用mycat创建订单归属区域信息表:

CREATE TABLE orders_ware_info
(
`id` INT AUTO_INCREMENT comment '编号',
`order_id` INT comment '订单编号',
`address` VARCHAR(200) comment '地址',
`areacode` VARCHAR(20) comment '区域编号',
PRIMARY KEY(id)
);

                插入数据:

INSERT INTO ORDERS_WARE_INFO(id, order_id,address,areacode) VALUES (1,1,'北京','110');
INSERT INTO ORDERS_WARE_INFO(id, order_id,address,areacode) VALUES (2,2,'天津','120');

                通过数据库直接查询:

                spdb_pzex:

      

                spdb_portal_wechat:  

                11.3、范围约定

                此分片适用于,提前规划好分片字段某个范围属于哪个分片。

        

                        1.修改schema.xml配置文件

        上面定义以及所存储的数据节点分片规则

                    2.修改rule.xml配置文件    

                3. 修改autopartition-long.txt配置文件

                

                4.重启Mycat使配置生效

                在mycat中创建支付信息表payment_info:

CREATE TABLE payment_info( `id` INT AUTO_INCREMENT comment '编号', `order_id` INT comment '订单编号', `payment_status` INT comment '支付状态', PRIMARY KEY(id));

                插入数据:  

INSERT INTO PAYMENT_INFO (id,order_id,payment_status) VALUES (1,101,0);INSERT INTO PAYMENT_INFO (id,order_id,payment_status) VALUES (2,102,1);INSERT INTO PAYMENT_INFO (id,order_id ,payment_status) VALUES (3,103,0);INSERT INTO PAYMENT_INFO (id,order_id,payment_status) VALUES (4,104,1);

                分别查看两个host数据节点的数据:         

                        spdb_pzex:

                        spdb_portal_wechat:

                        11.4 按日期(天)分片

                        此规则为按天分片。设定时间格式、范围 ---日志

                1.修改schema.xml配置文件

                

                2.修改rule.xml配置文件

                

         需要自定义一个分片函数shardingByDate:

            3.重启Mycat使配置生效    

                在mycat中创建用户信息表login_info:

CREATE TABLE login_info( `id` INT AUTO_INCREMENT comment '编号', `user_id` INT comment '用户编号', `login_date` date comment '登录日期', PRIMARY KEY(id));

                 插入数据:

INSERT INTO LOGIN_INFO(id,user_id,login_date) VALUES (1,101,'2019-01-01');
INSERT INTO LOGIN_INFO(id,user_id,login_date) VALUES (2,102,'2019-01-02');
INSERT INTO LOGIN_INFO(id,user_id,login_date) VALUES (3,103,'2019-01-03');
INSERT INTO LOGIN_INFO(id,user_id,login_date) VALUES (4,104,'2019-01-04');
INSERT INTO LOGIN_INFO(id,user_id,login_date) VALUES (5,103,'2019-01-05');
INSERT INTO LOGIN_INFO(id,user_id,login_date) VALUES (6,104,'2019-01-06');

         

                分别查看两个host数据节点的数据:

                        spdb_pzex:

                        spdb_portal_wechat:

        十二、Mycat的高可用

 

        详情可查看:基于 HA 机制的 Mycat 高可用_爱上口袋的天空的博客-CSDN博客

         总结: mycat -- 读写分离 垂直分库 水平分表[ 联表操作【ER原理】 水平拆分的规则]。

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值