• mysql 事务处理


    mysql 事务处理(表的引擎必须是 innodb / BDB)
    主要是两种两法:推荐用第一种
    1.用 begin,rollback,commit 来实现
    begin 开始一个事务
    rollback 事务回滚
    commit 事务提交

    2.直接用 set  来改变 mysql的自动提交模式,系统默认是自动提交的
     set autocommit = 0; 禁止自动提交
     set autocommit = 1;  开启自动提交

    用第一种方式可这样:
    <?php
    /*
    表信息 innodb(id,text)
    */
    require_once('conn.php'); // 数据库连接信息    
    $flag = 1; // 标识是完成提交还是回滚 1.提交完成 0.失败回滚
    //因为是自动提交的(默认),所以要想用事务,就必须手动开始事务,并手动提交
    //开启事务
    mysql_query("BEGIN"); // 或者 mysql_query("START TRANSACTION"); 或者 mysql_query("begin work");
    $sql1= "insert into innodb values('', 'xxx')";
    $sql2 = "insert into innodb values('', 'iiii')";
    $sql3 = "insert into innodb values('', 'eee'ee')";
    if(!mysql_query($sql1)){$flag = 0;}

    if(!mysql_query($sql2)){$flag = 0;}
    if(!mysql_query($sql3)){$flag = 0;}

    if($flag)
    {
        mysql_query("commit");
        echo "commit";
    }else
    {
        mysql_query("rollback");
        echo "rollback";
    }
    // 因为 $sql3有误,所以是无法插入以上数据的
    //结束这事务
    mysql_query("END");
    ----------------
    第二种方式可用:
    <?php
    require_once('conn.php'); // 数据库连接信息
    // 相当于开启了事务,禁止自动提交
    mysql_query("set autocommit=0", $conn);
    $flag = 1; // 标识是完成提交还是回滚 1.提交完成 0.失败回滚
    /*
    表信息 innodb(id,text)
    */
    $sql1= "insert into innodb values('', 'xxx')";
    $sql2 = "insert into innodb values('', 'iiii')";
    $sql3 = "insert into innodb values('', 'eee'ee')";
    if(!mysql_query($sql1)){$flag = 0;}

    if(!mysql_query($sql2)){$flag = 0;}
    if(!mysql_query($sql3)){$flag = 0;}

    if($flag)
    {
        mysql_query("commit");
        echo "commit";
    }else
    {
        mysql_query("rollback");
        echo "rollback";
    }
     
    mysql_query("END", $conn); // 结束事务
    mysql_query("set autocommit=1", $conn); // 还原自动提交,取消事务
    // 因为 $sql3有误,所以是无法插入以上数据的
    /*一定在提交或者回滚后,要调用 mysql_query("END", $conn);和mysql_query("set autocommit=1", $conn);,不然会把后面的 查询也当做事务来处理,不提交时就无法执行*/

    事务应具备的ACID特征.
    Atomic(原子性), Consistent(一致性),Isolated(隔离性),Durable(持续性)
    原子性:组成事务处理的语句形成了一个逻辑单元,不能只执行其中的一部分。换

    句话说,事务是不可分割的最小单元。比如:银行转帐过程中,必须同时从一个帐

    户减去转帐金额,并加到另一个帐户中,只改变一个帐户是不合理的。
    一致性:在事务处理执行前后,MySQL数据库是一致的。也就是说,事务应该正确

    的转换系统状态。比如:银行转帐过程中,要么转帐金额从一个帐户转入另一个帐

    户,要么两个帐户都不变,没有其他的情况。
    隔离性:一个事务处理对另一个事务处理没有影响。就是说任何事务都不可能看到

    一个处在不完整状态下的事务。比如说,银行转帐过程中,在转帐事务没有提交之

    前,另一个转帐事务只能处于等待状态。
    持续性:事务处理的效果能够被永久保存下来。反过来说,事务应当能够承受所有

    的失败,包括服务器、进程、通信以及媒体失败等等。比如:银行转帐过程中,转

    帐后帐户的状态要能被保存下来。
    为了一致性,可用到 select * ... for update;(默认是行锁定,必须明确是主键

    ,不然变成了表锁了)[be careful](作用于 update / delete 操作)[此时是悲观锁]
    如:
    begin;
    //id为主键,此行被锁定,直到这个事务提交,不然不让别的线程来更新此行数据
    select * from tablename where id=1 for update;

    //没有指定主键,会锁住个表
    select * from tablename for update;

    //明确指定主键,但无此数据,则无 lock
    select * from tablename where id = 0 for update;

    //无主键,表锁
    select * from tablename where name='xx' for update;

    //主键不明确,锁表
    select * from tablename where id <> '1' for update;
    select * from tablename where id like '1' for update;

    例子:在两个命令窗口可测试:
    连接1:
    begin;
    select * from tablename where id=1 for update;
    如果此时没有 commit或rollback;

    此时开如连接2:
    update tablename set name="xxx" where id=2;
    一定要等到连接1实现了 commit或rollback,连接2才会真正执行,不然一直在等待,直到超时或提交或回滚

    for update独占锁
    lock in share mode 共享锁模式(会造成死锁)
    例如:
    连接A:
    begin;
    select * from tablename where id=1 for update;

    接着打开连接B:
    begin;
    update tablename set name="xx" where id=1;
    或者 select * from tablename where id=1 for update;
    此时必须等连接A中 commit或rollback连接B更新或删除才会执行生效
    即 for update总是先以连接A为基准点

    lock in share mode:
    连接C:
    begin;
    select * from tablename where id=1 lock in share mode;

    接着打开连接D:
    begin;
    select * from tablename where id=1 lock in share mode;

    再继续执行连接C中的如下语句:
    update tablename set name="xx" where id=1;

    再往下执行连接D中的如下语句:
    update tablename set name="yyyy" where id=1; ////此时出现死锁
    如果要避免这种情况就得在连接D中先实现提交,再继续执行
    这样理解:
    如果是 for update,就得先完成最开始的事务,如果是 lock in share mode,就

    得先完成最近的事务锁

    myisam引擎(一定是)可实现锁表法:
    lock tables tablename write;
    insert into tablename values();
    unlock tables;
    如果上述中没有 unlock的话,另外的线程无法 curd,直到上面执行 unlock

    如果 :
    lock tables tablename read;
    此时该线程只能执行查询,不能写入操作,另外的线程可以查询,但也无法写入,直到unlock

    以上锁可归纳为悲欢锁

    乐观锁则是这样的:

    一般在数据表增加一个表示状态的字段,如开始状态了1,则A连接,还没来得更新,此时B连接上来,并修改了其中的数据,此时,该状态变为2,然后,A再更新数据,结果发现此时的状态与之前的连接的不一致,变为2了,说明已经变更过了,所以会通知A连接更新失败。

  • 相关阅读:
    jQuery对象和DOM对象
    虚拟主机的部署(Apache)
    事件流:事件冒泡和事件捕获
    ThinkPHP
    级联下拉列表
    今日份抽自己!!!
    c++中关于输入字符数组的一些问题
    今日新知(关于递归中变量的声明)
    格子游戏(并查集)
    1.3-14大象喝水
  • 原文地址:https://www.cnblogs.com/lin3615/p/3899990.html
Copyright © 2020-2023  润新知