分布事务问题
经过前面的分布事务的探索,可以确定,采用SQL加mysql xa 分布事务来做基于多个数据库实例的操作,一点问题都没有.
但理论是简单的,现实是复杂的!现在项目要采用分布事务,有以下要求:
1)分布事务要封装成简单的调用接口,方便调用和调试.
2)事务里调用的不仅仅是简单SQL,为稳定和效率起见,要调用的是封装的存储过程!
实现:
经过接口封装,
测试代码如下:
$t = new TradeInfo();//开始交易实例
$testCase = new UserAccount();//用户帐务中心实例
$t->xStart();
$testCase->xStart();
try {
$testCase->updateUserAccount(.......);//更新帐务
$t->saveRegisterInfo(.......);//更新交易信息
$testCase->xCommit();//分布提交
$t->xCommit();//分布提交
}catch (Exception $e)
{
print_r($e);
$testCase->xRollback();//回滚
$t->xRollback();//回滚
}
//接口封装见后
如同西天取经,不是一帆风顺!问题遇到不少!现在就几个关键问题解决方法列于下:
问题1.
如何生成事务的唯一xid.
解决方法:
参照mysql xid的手册,写一个生成方法!
问题2.
在window上采用pdo_mysql只能执行一次存储过程,所以更不用说分布事务了.
解决方法:
更换平台在Linux上进行测试,就没问题呢!
问题3:
XAER_RMFAIL: The command cannot be executed when global transaction is in the ACTIVE state
分析
1.可能是有隐含事务在前面执行.
2 可能有不支持SQL
解决方法:
1)避免不能在事务里使用的SQL
2)检查涉及表结构不是INNODB
3)检查的存储过程有错误
4)避免接口里数据API是否已经有事务语句执行!
问题4:
失败了,事务不XA ROLLBACK
分析:
程序调用或存储过程编写有问题.
解决:
1 开启mysql的generalog 迸行察看sql日志.查找调用或存储过程问题.
附:
封装接口伪代码:
class QueryObj
{
protected $xid;
function getXid()
{
return xxxx;//编写自己的xid逻辑,建议抄java的
}
function xStart()
{
$grid=$this->getXid(1);
$query="XA START '$grid'";
$dbh->query($query);
}
function xCommit ()
{
$grid=$this->getXid();
$dbh->query("XA END '$grid'");
$dbh->query("XA PREPARE '$grid'");
$dbh->query("XA COMMIT '$grid'");
}
function xRollback ()
{
$grid=$this->getXid();
$dbh->query("XA END '$grid'");
$dbh->query("XA ROLLBACK '$grid'");
}
}