Mysql Yii2数据库事务行为支持可重复读取
我有以下问题。我有一个web应用程序(用phpyii2编写),其中多个post请求预计会在很短的时间内到达应用程序服务器。业务逻辑应该非常严格,这意味着只有第一个请求的数据应该插入MySQL表,其余的都应该忽略。 客户端在post请求中同时发送父记录和最新子记录的id。 我以这种方式使用Yii的db事务Mysql Yii2数据库事务行为支持可重复读取,mysql,concurrency,yii2,transactions,transaction-isolation,Mysql,Concurrency,Yii2,Transactions,Transaction Isolation,我有以下问题。我有一个web应用程序(用phpyii2编写),其中多个post请求预计会在很短的时间内到达应用程序服务器。业务逻辑应该非常严格,这意味着只有第一个请求的数据应该插入MySQL表,其余的都应该忽略。 客户端在post请求中同时发送父记录和最新子记录的id。 我以这种方式使用Yii的db事务 $transaction = Yii::$app->db->beginTransaction(); $parent = ObjectParent::findOne(Yii::$app
$transaction = Yii::$app->db->beginTransaction();
$parent = ObjectParent::findOne(Yii::$app->request->post('parent_id')));
$latest_child = ObjectChild::findOne(Yii::$app->request->post('latest_child_id')));
if($parent->latest_child_id == $latest_child->id) {
try{
$new_child = $latest_child->createNewChild();
$parent->setLatestChild($new_child->id);
$transaction->commit();
} catch{
$transaction->rollback();
}
}
如果请求按顺序进行,则第二个请求将被忽略,因为最新子记录的id与来自客户端的id不匹配。但我的问题是,数据库中插入了多行。数据库的隔离级别是可重复读取的,这应该保证(据我所知)在事务中读取的行在提交之前不会更改。如果这是真的,那么它就不会成为问题,因为它会使第二个事务“中断”。
问题可能是,Yii可能不使用或不知道这些DB锁,因此不知道记录已经是事务的一部分,并根据对象的当前状态进行验证。DB当然不知道任何关于验证规则的事情,所以从它的角度来看也是可以的
我的解决办法是:
感谢Repeatable read only可确保在事务中读取行时,重新读取这些行会得到相同的结果。另一个事务可能会改变结果 要对其进行一些锁定,可以执行以下操作:
SELECT ... [LOCK IN SHARE MODE|FOR UPDATE]
但是,对于确保父/子项插入是唯一的情况,我建议将
(父项id,子项id)
作为表中的唯一键或主键,这样重复插入将生成重复键异常。可重复只读确保,如果在事务中读取行,重新读取这些行会得到相同的结果。另一个事务可能会改变结果
要对其进行一些锁定,可以执行以下操作:
SELECT ... [LOCK IN SHARE MODE|FOR UPDATE]
但是,为了确保父/子插入是唯一的,我建议将(父/子id)
作为表中的唯一键或主键,这样重复插入将生成重复键异常