对mysql事务提交、回滚的错误理解

1、原由mysql

  begin或者START TRANSACTION开始一个事务sql

  rollback事务回滚
  commit 事务确认
数据库

 人们对事务的解释以下:事务由做为一个单独单元的一个或多个SQL语句组成,若是其中一个语句不能完成,整个单元就会回滚(撤销),全部影响到的数据将返回到事务开始之前的状态。于是,只有事务中的全部语句都成功地执行才能说这个事务被成功地执行。函数

  这句话自己没有什么问题,问题是我给理解错了,我测试中问题描述为以下:测试

 mysql事务中有两条insert语句,其中第二条语句是错误的,在运行完事务后,第一条仍然插进去了,代码以下。spa

 //建立表:
CREATE TABLE `test_tab` (
`f1`  int(11) NOT NULL ,
`f2`  varchar(11)  DEFAULT NULL ,
PRIMARY KEY (`f1`)
)
ENGINE=InnoDB

//执行事务:
START TRANSACTION;
INSERT INTO test_tab VALUES    (1, '2');
INSERT INTO test_tab VALUES    (1, '3');
COMMIT;

(错误:这只是我一开始的认为)一开始认为只要把事务写出来,最后用commit提交一下,数据库会自动判断这些语句是否全执行成功,若是成功则把全部的数据插入到数据库,若是有一条失败就自动回滚至原始状态!显然我认为错了。3d

我执行上面的语句后的结果是:code

[SQL]START TRANSACTION;blog

受影响的行: 0事务

时间: 0.000s

[SQL]

INSERT INTO test_tab VALUES (1, '2');

受影响的行: 1

时间: 0.001s

[SQL]

INSERT INTO test_tab VALUES (1, '3');

[Err] 1062 - Duplicate entry '1' for key 'PRIMARY'

咱们看结果能够知道INSERT INTO test_tab VALUES (1, '3');这一句由于主键冲突运行失败,从而这一条下面的commit也没有执行。

须要注意的是:这时已经开启了一个事务,而且已经执行了一条正确的插入语句,虽然没有体如今数据库中,但若是之后在该链接中又执行了一条commit beginstart transaction新开一个事务会将该连接中的其余未提交的事务提交,至关于commit)你会发现已经将刚才的INSERT INTO test_tab VALUES (1, '2');写进了数据库。

 

因此事务的回滚不是这么理解的,正确的理解应该是,若是事务中全部sql语句执行正确则须要本身手动提交commit;不然有任何一条执行错误,须要本身提交一条rollback,这时会回滚全部操做,而不是commit会给你自动判断和回滚。

 

二 解决办法

  1. C++调用方式:(简单示例)

先定义一个变量标志bool m_flag=true;

再执行事务和sql语句如:(execute为本身写的函数,以下)

execute( m_sqlCon, “begin”);

execute(m_sqlCon,”INSERT INTO test_tab VALUES (1, '2')”);

execute(m_sqlCon,”INSERT INTO test_tab VALUES (1, '3')”);

若是执行过程当中任意一语句出错则将该标志m_flag置为false

这时不该该去提交commit,而是用一个函数去判断标志是否为false,若是为false说明执行的sql语句中有失败的,就执行rollback,不然说明所有正确,执行commit。以下面的 commit_transaction()方法。

 

代码大体以下,如使用须要修改!

 1 privat void execute(MYSQL m_sqlCon, string sqlStatement)
 2 {
 3 r = mysql_real_query(m_sqlCon, sqlStatement, (unsigned long)strlen(sqlStatement));
 4     if (r)
 5         m_flag = false; // 出错则标记一下
 6 }
 7 public bool commit_transaction()
 8 {
 9         int ret_error = 0;
10         if (!m_flag)
11         {
12             cancel_transaction();
13             return false;
14         }
15         else
16         {
17             if (!(ret_error = mysql_commit(m_sqlCon)))
18             {
19                 cancel_transaction();
20                 return true;
21             }
22         }
23         return true;
24 }

 

2.利用存储过程:

 1 CREATE PROCEDURE PRO2()
 2 BEGIN
 3     DECLARE t_error INTEGER;
 4     DECLARE    CONTINUE HANDLER FOR SQLEXCEPTION SET t_error = 1;
 5 
 6     START TRANSACTION;
 7         INSERT INTO test_tab VALUES    (1, '2');
 8         INSERT INTO test_tab VALUES    (1, '3');
 9         
10         IF t_error = 1 THEN
11             ROLLBACK;
12         ELSE
13             COMMIT;
14         END IF;
15 END

 

而后调用 CALL  PRO2()

这个直接能够利用mysql去决定他应该是回滚仍是提交。

相关文章
相关标签/搜索