我正在使用Zend_Db在事务内插入一些数据。我的函数启动一个事务,然后调用另一个也尝试启动事务的方法,但是当然失败了(我正在使用MySQL5)。因此,问题是-如何检测到交易已经开始?这是代码示例:
try {
Zend_Registry::get('database')->beginTransaction();
$totals = self::calculateTotals($Cart);
$PaymentInstrument = new PaymentInstrument;
$PaymentInstrument->create();
$PaymentInstrument->validate();
$PaymentInstrument->save();
Zend_Registry::get('database')->commit();
return true;
} catch(Zend_Exception $e) {
Bootstrap::$Log->err($e->getMessage());
Zend_Registry::get('database')->rollBack();
return false;
}
在PaymentInstrument :: create内部,还有另一个beginTransaction语句,该语句产生一个异常,指出交易已经开始。
该框架无法知道您是否开始了事务。您甚至可以使用$db->query('START TRANSACTION')框架不知道的内容,因为它不会解析您执行的SQL语句。
关键是,跟踪您是否已开始事务是应用程序的责任。这不是框架可以做的事情。
我知道有些框架会尝试执行此操作,并进行一些类似的事情,例如计算开始事务的次数,仅在完成提交或回退匹配次数后才解决它。但这完全是伪造的,因为您的任何函数都无法知道落实或回滚是否会真正做到这一点,或者它们是否在另一层嵌套中。
(你能告诉我我已经进行过几次讨论吗?:-)
更新1: Propel是一个PHP数据库访问库,它支持“内部事务”的概念,当您告诉它时,它不会提交。开始事务只会增加一个计数器,而提交/回滚会减少该计数器。下面是邮件列表线程的摘录,在此我描述了几种失败的情况。
更新2: Doctrine DBAL也具有此功能。他们称之为交易嵌套。
不管喜欢与否,事务是“全局的”,并且它们不遵循面向对象的封装。
问题场景1
我致电commit(),我的更改是否已落实?如果我在“内部事务”中运行,则不是。管理外部事务的代码可以选择回滚,而我的更改将在我不知情或无法控制的情况下被丢弃。
例如:
模式A:开始交易 模型A:执行一些更改 模式B:开始交易(静音无操作) 模式B:执行一些更改 模式B:提交(静音无操作) 模型A:回滚(同时丢弃模型A更改和模型B更改) 模型B:WTF !?我的变更怎么了? 问题场景2
内部事务回滚,它可以丢弃外部事务进行的合法更改。当控制权返回到外部代码时,它认为其事务仍然处于活动状态并且可以提交。使用您的补丁程序,他们可以调用commit(),并且由于transDepth现在为0,因此它将$transDepth在不提交任何内容后静默设置为-1并返回true。
问题场景3
如果我致电commit()或rollback()没有活动的交易,它将设置$transDepth为-1。下一个beginTransaction()将级别增加到0,这意味着事务既不能回滚也不能提交。随后的调用commit()只会将事务递减至-1或更大,直到执行另一次多余的操作beginTransaction()以再次增加级别,您将永远无法提交。
基本上,试图在应用程序逻辑中管理事务而不允许数据库进行簿记是一个注定的想法。如果要求两个模型在一个应用程序请求中使用显式事务控制,则必须打开两个数据库连接,每个模型一个。然后,每个模型都可以拥有自己的活动事务,可以相互独立地进行提交或回滚。来源:stack overflow
版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。