MySQL社区

 找回密码
 注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

搜索
查看: 5782|回复: 10

[事务及锁] 新人诚心求教(关于mysql事务概念)

[复制链接]
发表于 2014-3-17 09:36:15 | 显示全部楼层 |阅读模式
本人新人,现在在学习mysql过程中有这样一个疑问:

在一本叫做《mysql必知必会》的书中有这样一个例子:


start transaction;
delete from orderitems where order_num =20010; --语句1
delete from orders where order_num=20010;-- 语句2
commit;

这个例子中,从系统中完全删除订单20010。因为涉及更新两个数据库表orders 和orderitems,所以使用事务处理块来保证
订单不被部分删除。最后的commit语句仅在不出错时写出更改。如果第一条delete语句起作用,但第二条失败,则delete不
会提交(实际上,他是被自动撤销的)。

呃,对于上面的例子我个人理解是:一个事务中,所有语句都成功,才能正确提交事务,只要一个事务中有一条语句存在异
常,那么事务即使被提交,结果也不会保存到表中(个人理解,可能表达不是很清晰,请见谅)

那么我就做了如下的一个例子:

一、建立一个实验表
create table test (id int(10) not null)engine=innodb;

二、开启一个事务
start transaction;
insert into test values(1); -- 语句1
insert into test values(null); --语句2
commit;

三、结果
如果按照我的理解,在这个事务中因为语句2出现了异常,所以即使我提交事务,语句1的结果也不会被保存到数据库中,可
是实际的结果是语句1的结果被保存到了数据库中,所以我产生了疑惑,我也询问了身边的人以及查阅了不同的书,但是结论
分成了两种:一种和我原来的想法是相同的,另一种说法就是,提交事务后,正确的保存,不正确的不保存。于是我实在是分
不清究竟哪种说法是对的。

本人新手,诚心求教,可能我比较笨吧,还望大家能给予帮助,谢谢



发表于 2014-3-19 15:01:15 | 显示全部楼层
本帖最后由 je_ck 于 2014-3-19 15:31 编辑

事务是跟着连接(connect)在一起的。
你的第一个insert语句是正常的。所以对于当前连接来说是有效的。
第二个语句是错误的,所以它提示你错了,然后卡在第二个insert的语句中了,它需要你手动写rollback 语句。

这是你再使用这个连接(connect)查询数据库的话,它会维持当前连接的内容。
对于其他连接来说,这个事情根本没有发生。


从此可以看出事务的实现本质。
1、在commit语句之前的所有操作数据,都会提交到一个“临时表”中。
2、当commit时,才真正作用到数据库中。
3、事务是依赖连接的。
注:当发生异常时要进行异常处理,如果不处理的话, 会给别人带来麻烦。

发表于 2014-3-18 20:21:58 | 显示全部楼层
是的,最好要做异常控制。
楼主的这种情况是正常的,分析如下:
1.由于楼主是一条条手工进行命令行测试的,所以相当于每条命令行都做了异常控制(比如某个命令行出错,命令行中马上会有报错信息,此时我们还能进行rollback或commit:由于语句2已经是异常了(commit和rollback都不会修改数据库了),所以此时在语句2后的那个rollback或commit就相当于针对语句1了)。
2.如果我们把这些命令写到存储过程中,则不会执行到语句2后面的commit命令,因为此时没做异常控制时,就会在发生异常时自动把异常前的所有动作进行提交。

所以,我们理清这些机制之后,就会明白楼主的测试和事务原子性是相符的了。
 楼主| 发表于 2014-3-18 10:44:26 | 显示全部楼层
没有人愿意指点在下一二么?还是我哪里描述的有问题,还请指教
发表于 2014-3-18 16:24:34 | 显示全部楼层
这样应该是不管怎样都提交了吧。

貌似是要判读一下吧
如果出错就rollback
如果正常事务提交。

如,仅供参考:
$conn = mysql_connect('localhost','root','root') or die ("数据连接错误!!!");
mysql_select_db('test',$conn);
mysql_query("set names 'GBK'"); //使用GBK中文编码;
//开始一个事务
mysql_query("BEGIN"); //或者mysql_query("START TRANSACTION");
$sql = "INSERT INTO `user` (`id`, `username`, `sex`) VALUES (NULL, 'test1', '0')";
$sql2 = "INSERT INTO `user` (`did`, `username`, `sex`) VALUES (NULL, 'test1', '0')";//这条我故意写错
$res = mysql_query($sql);
$res1 = mysql_query($sql2);  
if($res && $res1){
mysql_query("COMMIT");
echo '提交成功。';
}else{
mysql_query("ROLLBACK");
echo '数据回滚。';
}
mysql_query("END");
 楼主| 发表于 2014-3-18 21:51:21 | 显示全部楼层
kider 发表于 2014-3-18 16:24
这样应该是不管怎样都提交了吧。

貌似是要判读一下吧

谢谢前辈的解答,不知道我是不是可以这么理解,事务的提交其实还是要靠逻辑判断来控制,如果事务中所有语句都成功,我们就commit事务,如果有异常,我们就rollback?
 楼主| 发表于 2014-3-18 21:52:25 | 显示全部楼层
nycle 发表于 2014-3-18 20:21
是的,最好要做异常控制。
楼主的这种情况是正常的,分析如下:
1.由于楼主是一条条手工进行命令行测试的 ...

谢谢前辈的解答,不知道我是不是可以这么理解,事务的提交其实还是要靠逻辑判断来控制,如果事务中所有语句都成功,我们就commit事务,如果有异常,我们就rollback?
发表于 2014-3-19 09:12:17 | 显示全部楼层
无论你xxxx,事务他就在那里~
只不过我们要知道,发生异常时如果没有进行异常控制,则异常之前的业务会被自动提交。
业务控制的只是什么时候要进行commit或者rollback,也就是我们只是控制事务的开关动作,事务内部的特性是不变的。
发表于 2014-3-19 10:56:04 | 显示全部楼层
这两篇关于MySQL事务的帖子值得细看看:

另外做了个例子,你可以实际测测:


存储过程
DELIMITER $$
USE `test`$$

DROP PROCEDURE IF EXISTS `sp_mysqlpub`$$
CREATE PROCEDURE sp_mysqlpub (v_value INT)
BEGIN
/** 标记是否出错 */  
DECLARE t_error INT DEFAULT 0;  
/** 如果出现sql异常,则将t_error设置为1后继续执行后面的操作 */  
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SET t_error=1; -- 出错处理
  START TRANSACTION;   -- 或 SET autocommit = off;
  INSERT INTO test VALUES(8888);
  INSERT INTO test VALUES(v_value);

  IF t_error=1 THEN  
        ROLLBACK; -- 事务回滚  
  ELSE  
        COMMIT; -- 事务提交  
  END IF;
END$$

DELIMITER ;

CALL sp_mysqlpub(1);
CALL sp_mysqlpub(11);
CALL sp_mysqlpub(NULL);
CALL sp_mysqlpub('abc'); -- 特殊情况

SHOW WARNINGS;
表:
CREATE TABLE `test` (
  `id` int(10) NOT NULL
) ENGINE=InnoDB;



 楼主| 发表于 2014-3-19 13:46:28 | 显示全部楼层
kider 发表于 2014-3-19 10:56
这两篇关于MySQL事务的帖子值得细看看:
  • MySQL存储过程之事务管理

  • 非常感谢前辈耐心的解答,真的非常感谢,您的例子非常生动,我感觉对于事务的理解已经有了头绪,真的非常感谢您
     楼主| 发表于 2014-3-19 16:09:18 | 显示全部楼层
    je_ck 发表于 2014-3-19 15:01
    事务是跟着连接(connect)在一起的。
    你的第一个insert语句是正常的。所以对于当前连接来说是有效的。
    ...

    谢谢前辈的指点
    您需要登录后才可以回帖 登录 | 注册

    本版积分规则

    QQ|申请友链|小黑屋|Archiver|手机版|MySQL社区 ( 京ICP备07012489号   
    联系人:周生; 联系电话:13911732319

    GMT+8, 2024-3-29 00:54 , Processed in 0.074385 second(s), 24 queries , Gzip On.

    Powered by Discuz! X3.2

    © 2001-2013 Comsenz Inc.

    快速回复 返回顶部 返回列表