MyCat 学习笔记 第十二篇.数据分片 之 分片事务处理
1 环境说明
VM 模拟3台MYSQL 5.6 服务器
VM1 192.168.31.187:3307
VM2 192.168.31.212:3307
VM3 192.168.31.150: 3307
MYCAT 1.5 服务部署在宿主机上
MYCAT 192.168.31.207 :8806【SQL执行端口】 / 9066【管理端口】
2 应用场景
2.0 MYCAT配置
schema.xml
<schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100">
<table name="t_demo_travel_record" dataNode="dn1,dn2,dn3" rule="auto-sharding-long" />
<table name="t_demo_travel_record_child" dataNode="dn1,dn2,dn3" rule="auto-sharding-long" />
</schema>
<dataNode name="dn1" dataHost="vm1" database="test" />
<dataNode name="dn2" dataHost="vm2" database="test" />
<dataNode name="dn3" dataHost="vm3" database="test" />
<dataHost name="vm1" maxCon="1000" minCon="10" balance="0"
writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
<heartbeat>select user()</heartbeat>
<writeHost host="vm1M1" url="192.168.31.187:3307" user="root" password="root123"></writeHost>
</dataHost>
<dataHost name="vm2" maxCon="1000" minCon="10" balance="0"
writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
<heartbeat>select user()</heartbeat>
<writeHost host="vm2M1" url="192.168.31.212:3307" user="root" password="root123"></writeHost>
</dataHost>
<dataHost name="vm3" maxCon="1000" minCon="10" balance="0"
writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
<heartbeat>select user()</heartbeat>
<writeHost host="vm3M1" url="192.168.31.150:3307" user="root" password="root123"></writeHost>
</dataHost>
rule.xml
<tableRule name="auto-sharding-long">
<rule>
<columns>id</columns>
<algorithm>rang-long</algorithm>
</rule>
</tableRule>
<function name="rang-long"
class="org.opencloudb.route.function.AutoPartitionByLong">
<property name="mapFile">autopartition-long.txt</property>
<property name="defaultNode">0</property>
</function>
autopartition-long.txt
# range start-end ,data node index
# K=1000,M=10000.
0-500M=0
500M-1000M=1
1000M-1500M=2
2.1 手动关闭事,跨数据库进行更新操作。
用一套简单点的JAVA来做这次数据验证
DataSource ds = jdbc.getDataSource();
conn = ds.getConnection();
conn.setAutoCommit(false);
pstm1 = conn.prepareStatement("insert into t_demo_travel_record (id,context) values (?,?)");
pstm1.setInt(1, 5000);
pstm1.setString(2, "这条记录应该进行DN1");
pstm1.addBatch();
pstm1.setInt(1, 5999999);
pstm1.setString(2, "这条记录应该进行DN2");
pstm1.addBatch();
pstm1.setInt(1, 14991499);
pstm1.setString(2, "这条记录应该进行DN3");
pstm1.addBatch();
pstm1.executeBatch();
conn.commit();
MYCAT 192.168.31.207: 8806 查询已插入的记录
mysql> select * from t_demo_travel_record where id in (5000,5999999,14991499);
+----------+-------------+
| id | context |
+----------+-------------+
| 5000 | ????????DN1 |
| 14991499 | ????????DN3 |
| 5999999 | ????????DN2 |
+----------+-------------+
3 rows in set (0.01 sec)
VM1 192.168.31.187:3307 物理库
mysql> select * from t_demo_travel_record where id in (5000,5999999,14991499);
+------+-------------+
| id | context |
+------+-------------+
| 5000 | ????????DN1 |
+------+-------------+
1 row in set (0.01 sec)
VM2 192.168.31.212:3307
mysql> select * from t_demo_travel_record where id in (5000,5999999,14991499);
+---------+-------------+
| id | context |
+---------+-------------+
| 5999999 | ????????DN2 |
+---------+-------------+
1 row in set (0.00 sec)
VM3 192.168.31.150: 3307
mysql> select * from t_demo_travel_record where id in (5000,5999999,14991499);
+----------+-------------+
| id | context |
+----------+-------------+
| 14991499 | ????????DN3 |
+----------+-------------+
1 row in set (0.00 sec)
2.2 异常操作,验证下数据是否回滚
模拟数据如下,最后一条主键重复。
pstm1.setInt(1, 5001);
pstm1.setString(2, "这条记录应该进行DN1");
pstm1.addBatch();
pstm1.setInt(1, 5999998);
pstm1.setString(2, "这条记录应该进行DN2");
pstm1.addBatch();
pstm1.setInt(1, 14991499);
pstm1.setString(2, "这条记录应该进行DN3");
pstm1.addBatch();
程序执行报错:
2016-02-03 00:36:10,229 INFO : [] com.alibaba.druid.pool.DruidDataSource [DruidDataSource.java:669] - {dataSource-1} inited
java.sql.BatchUpdateException: Duplicate entry '14991499' for key 'PRIMARY'
...
再看下数据库里并没有执行前2句SQL语句,mycat 在数据分片插入不同的数据库时已给我们做了一定的数据库事务控制。
mysql> select * from t_demo_travel_record where id in (5001,5999998,14991499);
+----------+-------------+
| id | context |
+----------+-------------+
| 14991499 | ????????DN3 |
+----------+-------------+
1 row in set (0.01 sec)
再来看下MYCAT日志,根据分片原则,分析将SQL语句发向不同的数据结点
02/03 00:36:10.279 DEBUG [$_NIOREACTOR-1-RW] (ServerQueryHandler.java:56) -ServerConnection [id=31, schema=TESTDB, host=127.0.0.1, user=test,txIsolation=3, autocommit=false, schema=TESTDB]insert into t_demo_travel_record (id,context) values (5001,'这条记录应该进行DN1')
02/03 00:36:10.279 DEBUG [$_NIOREACTOR-1-RW] (NonBlockingSession.java:113) -ServerConnection [id=31, schema=TESTDB, host=127.0.0.1, user=test,txIsolation=3, autocommit=false, schema=TESTDB]insert into t_demo_travel_record (id,context) values (5001,'这条记录应该进行DN1'), route={
1 -> dn1{insert into t_demo_travel_record (id,context) values (5001,'这条记录应该进行DN1')}
} rrs
02/03 00:36:10.281 DEBUG [$_NIOREACTOR-1-RW] (ServerQueryHandler.java:56) -ServerConnection [id=31, schema=TESTDB, host=127.0.0.1, user=test,txIsolation=3, autocommit=false, schema=TESTDB]insert into t_demo_travel_record (id,context) values (5999998,'这条记录应该进行DN2')
02/03 00:36:10.281 DEBUG [$_NIOREACTOR-1-RW] (NonBlockingSession.java:113) -ServerConnection [id=31, schema=TESTDB, host=127.0.0.1, user=test,txIsolation=3, autocommit=false, schema=TESTDB]insert into t_demo_travel_record (id,context) values (5999998,'这条记录应该进行DN2'), route={
1 -> dn2{insert into t_demo_travel_record (id,context) values (5999998,'这条记录应该进行DN2')}
} rrs
02/03 00:36:10.281 DEBUG [$_NIOREACTOR-1-RW] (MySQLConnection.java:445) -con need syn ,total syn cmd 1 commands SET autocommit=0;schema change:false con:MySQLConnection [id=28, lastTime=1454430970281, user=root, schema=test, old shema=test, borrowed=true, fromSlaveDB=false, threadId=30, charset=utf8, txIsolation=3, autocommit=true, attachment=dn2{insert into t_demo_travel_record (id,context) values (5999998,'这条记录应该进行DN2')}, respHandler=SingleNodeHandler [node=dn2{insert into t_demo_travel_record (id,context) values (5999998,'这条记录应该进行DN2')}, packetId=0], host=192.168.31.212, port=3307, statusSync=null, writeQueue=0, modifiedSQLExecuted=true]
02/03 00:36:10.284 DEBUG [$_NIOREACTOR-1-RW] (ServerQueryHandler.java:56) -ServerConnection [id=31, schema=TESTDB, host=127.0.0.1, user=test,txIsolation=3, autocommit=false, schema=TESTDB]insert into t_demo_travel_record (id,context) values (14991499,'这条记录应该进行DN3')
02/03 00:36:10.284 DEBUG [$_NIOREACTOR-1-RW] (NonBlockingSession.java:113) -ServerConnection [id=31, schema=TESTDB, host=127.0.0.1, user=test,txIsolation=3, autocommit=false, schema=TESTDB]insert into t_demo_travel_record (id,context) values (14991499,'这条记录应该进行DN3'), route={
1 -> dn3{insert into t_demo_travel_record (id,context) values (14991499,'这条记录应该进行DN3')}
} rrs
准备同步数据库操作,发现SQL语句在DN3上编译失败
02/03 00:36:10.285 DEBUG [$_NIOREACTOR-1-RW] (MySQLConnection.java:445) -con need syn ,total syn cmd 1 commands SET autocommit=0;schema change:false con:MySQLConnection [id=8, lastTime=1454430970285, user=root, schema=test, old shema=test, borrowed=true, fromSlaveDB=false, threadId=24, charset=utf8, txIsolation=3, autocommit=true, attachment=dn3{insert into t_demo_travel_record (id,context) values (14991499,'这条记录应该进行DN3')}, respHandler=SingleNodeHandler [node=dn3{insert into t_demo_travel_record (id,context) values (14991499,'这条记录应该进行DN3')}, packetId=0], host=192.168.31.150, port=3307, statusSync=null, writeQueue=0, modifiedSQLExecuted=true]
02/03 00:36:10.286 WARN [$_NIOREACTOR-0-RW] (SingleNodeHandler.java:222) -execute sql err : errno:1062 Duplicate entry '14991499' for key 'PRIMARY' con:MySQLConnection [id=8, lastTime=1454430970269, user=root, schema=test, old shema=test, borrowed=true, fromSlaveDB=false, threadId=24, charset=utf8, txIsolation=3, autocommit=false, attachment=dn3{insert into t_demo_travel_record (id,context) values (14991499,'这条记录应该进行DN3')}, respHandler=SingleNodeHandler [node=dn3{insert into t_demo_travel_record (id,context) values (14991499,'这条记录应该进行DN3')}, packetId=1], host=192.168.31.150, port=3307, statusSync=org.opencloudb.mysql.nio.MySQLConnection$StatusSync@48537945, writeQueue=0, modifiedSQLExecuted=true] frontend host:127.0.0.1/50644/test
再下来开始回滚所有数据结点上的更新操作。
02/03 00:36:10.305 DEBUG [$_NIOREACTOR-1-RW] (ServerQueryHandler.java:56) -ServerConnection [id=31, schema=TESTDB, host=127.0.0.1, user=test,txIsolation=3, autocommit=false, schema=TESTDB]rollback
02/03 00:36:10.305 DEBUG [$_NIOREACTOR-1-RW] (RollbackNodeHandler.java:71) -rollback job run for MySQLConnection [id=8, lastTime=1454430970269, user=root, schema=test, old shema=test, borrowed=true, fromSlaveDB=false, threadId=24, charset=utf8, txIsolation=3, autocommit=false, attachment=dn3{insert into t_demo_travel_record (id,context) values (14991499,'这条记录应该进行DN3')}, respHandler=SingleNodeHandler [node=dn3{insert into t_demo_travel_record (id,context) values (14991499,'这条记录应该进行DN3')}, packetId=1], host=192.168.31.150, port=3307, statusSync=org.opencloudb.mysql.nio.MySQLConnection$StatusSync@48537945, writeQueue=0, modifiedSQLExecuted=true]
02/03 00:36:10.305 DEBUG [$_NIOREACTOR-1-RW] (RollbackNodeHandler.java:71) -rollback job run for MySQLConnection [id=16, lastTime=1454430970269, user=root, schema=test, old shema=test, borrowed=true, fromSlaveDB=false, threadId=33, charset=utf8, txIsolation=3, autocommit=false, attachment=dn1{insert into t_demo_travel_record (id,context) values (5001,'这条记录应该进行DN1')}, respHandler=SingleNodeHandler [node=dn1{insert into t_demo_travel_record (id,context) values (5001,'这条记录应该进行DN1')}, packetId=1], host=192.168.31.187, port=3307, statusSync=null, writeQueue=0, modifiedSQLExecuted=true]
02/03 00:36:10.306 DEBUG [$_NIOREACTOR-1-RW] (RollbackNodeHandler.java:71) -rollback job run for MySQLConnection [id=28, lastTime=1454430970269, user=root, schema=test, old shema=test, borrowed=true, fromSlaveDB=false, threadId=30, charset=utf8, txIsolation=3, autocommit=false, attachment=dn2{insert into t_demo_travel_record (id,context) values (5999998,'这条记录应该进行DN2')}, respHandler=SingleNodeHandler [node=dn2{insert into t_demo_travel_record (id,context) values (5999998,'这条记录应该进行DN2')}, packetId=1], host=192.168.31.212, port=3307, statusSync=null, writeQueue=0, modifiedSQLExecuted=true]
02/03 00:36:10.312 DEBUG [$_NIOREACTOR-0-RW] (NonBlockingSession.java:361) -clear session resources org.opencloudb.server.NonBlockingSession@603ec61b
释放数据库链接
02/03 00:36:10.312 DEBUG [$_NIOREACTOR-0-RW] (NonBlockingSession.java:229) -release connection MySQLConnection [id=8, lastTime=1454430970269, user=root, schema=test, old shema=test, borrowed=true, fromSlaveDB=false, threadId=24, charset=utf8, txIsolation=3, autocommit=false, attachment=dn3{insert into t_demo_travel_record (id,context) values (14991499,'这条记录应该进行DN3')}, respHandler=org.opencloudb.mysql.nio.handler.RollbackNodeHandler@394047fa, host=192.168.31.150, port=3307, statusSync=org.opencloudb.mysql.nio.MySQLConnection$StatusSync@48537945, writeQueue=0, modifiedSQLExecuted=true]
02/03 00:36:10.312 DEBUG [$_NIOREACTOR-0-RW] (NonBlockingSession.java:229) -release connection MySQLConnection [id=16, lastTime=1454430970269, user=root, schema=test, old shema=test, borrowed=true, fromSlaveDB=false, threadId=33, charset=utf8, txIsolation=3, autocommit=false, attachment=dn1{insert into t_demo_travel_record (id,context) values (5001,'这条记录应该进行DN1')}, respHandler=org.opencloudb.mysql.nio.handler.RollbackNodeHandler@394047fa, host=192.168.31.187, port=3307, statusSync=null, writeQueue=0, modifiedSQLExecuted=true]
02/03 00:36:10.312 DEBUG [$_NIOREACTOR-0-RW] (NonBlockingSession.java:229) -release connection MySQLConnection [id=28, lastTime=1454430970269, user=root, schema=test, old shema=test, borrowed=true, fromSlaveDB=false, threadId=30, charset=utf8, txIsolation=3, autocommit=false, attachment=dn2{insert into t_demo_travel_record (id,context) values (5999998,'这条记录应该进行DN2')}, respHandler=org.opencloudb.mysql.nio.handler.RollbackNodeHandler@394047fa, host=192.168.31.212, port=3307, statusSync=null, writeQueue=0, modifiedSQLExecuted=true]
02/03 00:36:10.313 DEBUG [$_NIOREACTOR-0-RW] (RollbackReleaseHandler.java:58) -autocomit is false,but no commit or rollback ,so mycat rollbacked backend conn MySQLConnection [id=8, lastTime=1454430970269, user=root, schema=test, old shema=test, borrowed=true, fromSlaveDB=false, threadId=24, charset=utf8, txIsolation=3, autocommit=false, attachment=null, respHandler=org.opencloudb.mysql.nio.handler.RollbackReleaseHandler@2b358b73, host=192.168.31.150, port=3307, statusSync=org.opencloudb.mysql.nio.MySQLConnection$StatusSync@48537945, writeQueue=0, modifiedSQLExecuted=true]
02/03 00:36:10.313 DEBUG [$_NIOREACTOR-0-RW] (PhysicalDatasource.java:403) -release channel MySQLConnection [id=8, lastTime=1454430970269, user=root, schema=test, old shema=test, borrowed=true, fromSlaveDB=false, threadId=24, charset=utf8, txIsolation=3, autocommit=false, attachment=null, respHandler=null, host=192.168.31.150, port=3307, statusSync=null, writeQueue=0, modifiedSQLExecuted=false]
02/03 00:36:10.313 DEBUG [$_NIOREACTOR-0-RW] (RollbackReleaseHandler.java:58) -autocomit is false,but no commit or rollback ,so mycat rollbacked backend conn MySQLConnection [id=16, lastTime=1454430970269, user=root, schema=test, old shema=test, borrowed=true, fromSlaveDB=false, threadId=33, charset=utf8, txIsolation=3, autocommit=false, attachment=null, respHandler=org.opencloudb.mysql.nio.handler.RollbackReleaseHandler@4856412e, host=192.168.31.187, port=3307, statusSync=null, writeQueue=0, modifiedSQLExecuted=true]
02/03 00:36:10.313 DEBUG [$_NIOREACTOR-0-RW] (PhysicalDatasource.java:403) -release channel MySQLConnection [id=16, lastTime=1454430970269, user=root, schema=test, old shema=test, borrowed=true, fromSlaveDB=false, threadId=33, charset=utf8, txIsolation=3, autocommit=false, attachment=null, respHandler=null, host=192.168.31.187, port=3307, statusSync=null, writeQueue=0, modifiedSQLExecuted=false]
02/03 00:36:10.313 DEBUG [$_NIOREACTOR-0-RW] (RollbackReleaseHandler.java:58) -autocomit is false,but no commit or rollback ,so mycat rollbacked backend conn MySQLConnection [id=28, lastTime=1454430970269, user=root, schema=test, old shema=test, borrowed=true, fromSlaveDB=false, threadId=30, charset=utf8, txIsolation=3, autocommit=false, attachment=null, respHandler=org.opencloudb.mysql.nio.handler.RollbackReleaseHandler@16d1581c, host=192.168.31.212, port=3307, statusSync=null, writeQueue=0, modifiedSQLExecuted=true]
02/03 00:36:10.313 DEBUG [$_NIOREACTOR-0-RW] (PhysicalDatasource.java:403) -release channel MySQLConnection [id=28, lastTime=1454430970269, user=root, schema=test, old shema=test, borrowed=true, fromSlaveDB=false, threadId=30, charset=utf8, txIsolation=3, autocommit=false, attachment=null, respHandler=null, host=192.168.31.212, port=3307, statusSync=null, writeQueue=0, modifiedSQLExecuted=false]
02
OK,通过2个场景验证了MYCAT的事务一致性。
再补一句,大家可以通过MYSQL权威指南文档了解到其实MYCAT实现一种弱XA的事务控制,怎么理解这个弱XA事务控制。
举例有3个结点,MYCAT根据分片规则依次在不同物理库中预执行,如果当中任何一个发现问题则回滚所有。
若预执行成功,3个结点分别进行commit操作时发生异常,则mycat无法回滚已提交的事务。当然,这种机率很小很小~~~
另外一个问题在于,如果发锁升级导致单结点无法操作时,会对整体应用产生比较大的影响。
本篇完
MyCat 学习笔记 第十二篇.数据分片 之 分片事务处理的更多相关文章
- Django学习笔记第十二篇--关于自定义数据库字段数据类型
一.需求背景: django的models模块提供了很多数据字段的数据类型field,但是总有写奇葩需求不能依靠默认字段满足,所以需要自定义数据数据库数据字段类型.所有的自定义field应该在app路 ...
- MyCat 学习笔记 第十篇.数据分片 之 ER分片
1 应用场景 这篇来说下mycat中自带的er关系分片,所谓er关系分片即可以理解为有关联关系表之间数据分片.类似于订单主表与订单详情表间的分片存储规则. 本文所说的er分片分为两种: a. 依据主键 ...
- 汇编入门学习笔记 (十二)—— int指令、port
疯狂的暑假学习之 汇编入门学习笔记 (十二)-- int指令.port 參考: <汇编语言> 王爽 第13.14章 一.int指令 1. int指令引发的中断 int n指令,相当于引 ...
- VSTO 学习笔记(十二)自定义公式与Ribbon
原文:VSTO 学习笔记(十二)自定义公式与Ribbon 这几天工作中在开发一个Excel插件,包含自定义公式,根据条件从数据库中查询结果.这次我们来做一个简单的测试,达到类似的目的. 即在Excel ...
- Binder学习笔记(十二)—— binder_transaction(...)都干了什么?
binder_open(...)都干了什么? 在回答binder_transaction(...)之前,还有一些基础设施要去探究,比如binder_open(...),binder_mmap(...) ...
- Egret入门学习日记 --- 第十二篇(书中 5.1节 内容)
第十二篇(书中 5.1节 内容) 昨天把 第4章完成了. 今天来看第5章. 接下来是 5.1节 的内容. 总结一下 5.1节 的重点: 1.如何制作一个公用按钮皮肤. 跟着做: 重点1:如何制作一个公 ...
- MySQL数据库学习笔记(十二)----开源工具DbUtils的使用(数据库的增删改查)
[声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/4 ...
- java之jvm学习笔记六-十二(实践写自己的安全管理器)(jar包的代码认证和签名) (实践对jar包的代码签名) (策略文件)(策略和保护域) (访问控制器) (访问控制器的栈校验机制) (jvm基本结构)
java之jvm学习笔记六(实践写自己的安全管理器) 安全管理器SecurityManager里设计的内容实在是非常的庞大,它的核心方法就是checkPerssiom这个方法里又调用 AccessCo ...
- Android学习笔记(十二)——实战:制作一个聊天界面
//此系列博文是<第一行Android代码>的学习笔记,如有错漏,欢迎指正! 运用简单的布局知识,我们可以来尝试制作一个聊天界面. 一.制作 Nine-Patch 图片 : Nine-Pa ...
随机推荐
- [团队项目] Scrum 项目 3.0 SCRUM 流程的步骤2: Spring 计划
SCRUM 流程的步骤2: Spring 计划 1. 确保product backlog井然有序.(参考示例图1) 2. Sprint周期,一个冲刺周期,长度定为两周,本学期还有三个冲刺周期. 3 ...
- C#操作IIS程序池及站点的创建配置
最近在做一个WEB程序的安装包:对一些操作IIS进行一个简单的总结:主要包括对IIS进行站点的新建以及新建站点的NET版本的选择,还有针对IIS7程序池的托管模式以及版本的操作:首先要对Microso ...
- 通过UIView获取UIViewController
需求很简单,通过UIViewController.view内的任意控件获取当前UIViewController: 立马开写: /** * @brief 通过viewController内的view,获 ...
- 看了一本Unity3D的教程
国内写的<Unity 3D游戏开发>. 实例挺多,对于有基础的人来说,上手会挺快的: 但进阶的东西没有涉及,可能与书的定位有关吧
- 轻量级的移动 webapp 框架Jingle
一大早爬起来,发现这样的一个东东,国产,感觉实用性很强,试着用用. 1.28补记: 试着用jingle做了一个网站的移动版,感觉如果在布局上要求不高的话 - 目前支持的布局只有list,还是挺不错,做 ...
- Hibernate的初步
1.简介 在java开发领域,基于数据库应用的设计与实现一直都是面向关系的,Hibernate对象/关系映射ORM框架的出现为java面向对象开发提供了易于使用的数据持久化解决方案. ORM介绍: ( ...
- ahjesus 部署lighttpd
这个就不写了,直接传送门过去看,按照说的做就可以了 如果你想要安装最新版的,传送门 需要注意的是configure这一步,你看完他的help以后还要输入 ./configure 才能继续下一步 再就是 ...
- VS2010在空解决方案中添加项目
如题,在空解决方案中添加第一个项目的时候会看不到那个solution解决方案文件,而是你当前添加的项目,当你再添加其他项目的时候就悲催了,找不到这个solution,只能在这个项目文件上新加文件,很郁 ...
- 使用自定义字体 @font-face 小试
第一次了解到@font-face是小伙伴给我展示的功能 感觉奇妙的不得了 @font-face 是CSS3中的一个模块 使用它你就可以将你自定义的web字体 去实现一些奇妙的想法 首先先介绍 ...
- Underscore学习笔记1
项目用了很久underscore.每次都是临时查手册,没有系统的研究过,最近有空正好看看 github地址:https://github.com/lily1010/underscore_learn 一 ...