猿问

关于mysql事务操作在循环里的疑惑

需求的描述是有一个数组,循环处理数组数据,写入并更新数据库,写入+更新为一组数据处理,想要达到的效果是循环中如果某一组数据写入/更新失败,回滚当前组的数据库操作;以此需求为前提写了下面这段事务处理代码,但总觉得这样写不合适
$this->db->trans_begin();
foreach($record_dataas$key=>$value){
/**
*更新数据库操作
**/
若干代码.......
/**
*插入数据库操作
**/
若干代码.......
if($this->db->trans_status()===FALSE){
$this->db->trans_rollback();
}else{
$this->db->trans_commit();
//这里需要记录当前组操作成功的
$ok_ids[]=$value['id'];
$user_monetary[$value['user_id']]=$diff;
}
}
上面这段代码是一段典型的CI框架手动开启数据库事务的例子,有几个纠结/疑惑的点:
我把开启事务放在循环之前,把执行事务处理的部分放在代码里,可以把更新+插入当做一组数据处理,如果我循环执行到中间,有一组数据执行失败,触发了回滚,会不会把我之前的已经处理过的数据也回滚掉?
如果我把开启事务放在循环体里,因为每次进入循环体都要开启事务,然后进行事务处理,会不会影响执行效率,每次循环次数在100~500之间不等;
由于上面的疑惑写了一段测试代码:
$ins_data=[
'monetary'=>202,
'consume_time'=>20170798,
];
$this->db->trans_begin();
for($i=0;$i<100;$i++){
if($i==50){
$ins_data['user_id']=366750;
}else{
$ins_data['user_id']=3667;
}
$this->xxx_model->insert($ins_data);//插入到数据库
if($i==50){
$this->db->trans_rollback();
}else{
$this->db->trans_commit();
}
}
运行这段代码的结果是:插入操作无一例外正常执行,366750这条记录还是插入了数据库里面,并无产生回滚事件。
查阅资料:
在事务中,每个正确的原子操作都会被顺序执行,直到遇到错误的原子操作,此时事务会将之前的操作进行回滚。回滚的意思是如果之前是插入操作,那么会执行删除插入的记录,如果之前是update操作,也会执行update操作将之前的记录还原。因此,正确的原子操作是真正被执行过的。是物理执行。
看到说直到遇到错误的原子操作才能进行回滚,为了验证这个,我放弃了在循环中执行事务,把代码改成了在循环体外执行事务的处理:
$ins_data=[
'monetary'=>202,
'consume_time'=>20170798,
];
$this->db->trans_begin();
for($i=0;$i<100;$i++){
$this->xxx_model->insert($ins_data);//插入到数据库
}
$this->db->trans_rollback();
//$this->db->trans_commit();
上面这段代码中,当最后操作rollback的时候,数据库并不会插入数据,当是commit的时候,数据库才会插入数据。那么这一现象就打翻了前面说的只有遇到错误的原子操作才能进行回滚的陈述,这时候我就更懵了。
那么什么是事务?事务的触发条件是什么?符合我这种场景的数据操作该如何进行事务处理呢?还请路过的大神能够指点一下、抱拳~
慕容森
浏览 317回答 2
2回答

元芳怎么了

比如你有三个数据库操作,而且需要按照以下顺序执行减去库存更新钱包写日志你可以这样做事务开始如果减去库存成功继续往下否则事务回滚如果更新钱包成功继续往下,否则事务回滚如果写日志成功继续往下否则事务回滚提交事务以上执行,如果第2步回滚了,那么数据库无任何变化;如果第3步回滚了,那么第2步的操作被撤销;如果第4步回滚了,那么第2第3步都被撤销;如果第5步执行了,那么这三步全部执行成功。
随时随地看视频慕课网APP

相关分类

JavaScript
我要回答