zoukankan      html  css  js  c++  java
  • 【0928 | Day 39】事务(精讲)

    一、事务

    在mysql中,事务其实是一个最小的不可分割的工作单元,事务能够保证一个业务的完整性

    比如我们的银行转账:
       a给b转100块钱,相当于
       update user set monry=money-100 where name='a'
    update user set monry=money+100 where name='b'

    需要两条语句,在实际情况中,如果只有一条语句执行成功,而另一条没有执行成功,就会出现数据前后不一致的情况。

    事务用来解决:多条sql语句可能会有同时成功的要求,要么就同时失败。

    1. mysql如何控制事务?

    mysql默认是自动提交的

    mysql> select @@autocommit;
    +--------------+
    | @@autocommit |
    +--------------+
    |            1 |
    +--------------+
    1 row in set (0.52 sec)
    

    2. 默认事务开启的作用是什么?

    • 当我们去执行一个sql语句的时候,效果会立即体现出来,且不能回滚。
    • 这里又出现了一些概念(回滚),我们举例来说:
    • 创建一个数据库,再创建数据表,插入数据
    mysql> create database bank;
    Query OK, 1 row affected (0.64 sec)
    
    mysql> use bank;
    Database changed
    
    mysql> create table user(
        -> id int primary key,
        -> name varchar(20),
        -> money int
        -> );
    Query OK, 0 rows affected (0.93 sec)
    mysql> insert into user values(1,'a',1000);
    Query OK, 1 row affected (0.51 sec)
    
    mysql> select * from user;
    +----+------+-------+
    | id | name | money |
    +----+------+-------+
    |  1 | a    |  1000 |
    +----+------+-------+
    1 row in set (0.00 sec)
    

    事务回滚:撤销sql的执行效果 (rollback;)

    下面调用rollback

    mysql> rollback;
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> select * from user;
    +----+------+-------+
    | id | name | money |
    +----+------+-------+
    |  1 | a    |  1000 |
    +----+------+-------+
    1 row in set (0.00 sec)
    

    可以看到,即使调用了rollback,数据依然存在,说明是不能够回滚的,添加数据的语句执行完后默认就提交了。

    我们可以通过设置默认事务为0的方式来进行改变,也就是设置mysql默认提交为falseset autocommit=0;(1为开启,0为关闭)

    mysql> set autocommit=0;
    Query OK, 0 rows affected (0.54 sec)
    
    mysql> select @@autocommit;
    +--------------+
    | @@autocommit |
    +--------------+
    |            0 |
    +--------------+
    1 row in set (0.00 sec)
    

    上面的操作,关闭了mysql的自动提交(commit)

    这里在操作一遍来验证:(这时候自动提交已经关闭了)

    mysql> insert into user values(2,'b',1000); #插入数据
    Query OK, 1 row affected (0.00 sec)
    
    mysql> select * from user;
    +----+------+-------+
    | id | name | money |
    +----+------+-------+
    |  1 | a    |  1000 |
    |  2 | b    |  1000 |
    +----+------+-------+
    2 rows in set (0.00 sec)
    
    mysql> rollback;  #进行回滚
    Query OK, 0 rows affected (0.07 sec)
    
    mysql> select * from user;
    +----+------+-------+
    | id | name | money |
    +----+------+-------+
    |  1 | a    |  1000 |
    +----+------+-------+
    1 row in set (0.00 sec)
    

    惊不惊喜,刚才插入的数据没有了。我们在执行完语句时(关闭默认提交),看到的效果只是一个临时效果,并没有真实的发生在我们数据库里面,是在一张虚拟的表中。

    这里可以用commit提交

    #再插入一次数据
    mysql> insert into user values(2,'b',1000);
    Query OK, 1 row affected (0.00 sec)
    
    #手动提交数据
    mysql> commit;
    Query OK, 0 rows affected (0.15 sec)
    
    #再撤销,是不可以撤销的(事务的一个特性:持久性)
    mysql> rollback;
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> select * from user;
    +----+------+-------+
    | id | name | money |
    +----+------+-------+
    |  1 | a    |  1000 |
    |  2 | b    |  1000 |
    +----+------+-------+
    2 rows in set (0.00 sec)
    

    只要commit了,rollback也没有用了,持久哦~

    自动提交: @@autocommit=1

    手动提交: commit

    回滚: rollback(在没有提交的情况下,是可以提交的)

    也就是说,事务给我们提供了一个返回的机会!!!

    就像前面说的,当发现有一条语句没有执行成功的情况下,可以回滚了。在检查无误之后,再手动commit让它生效,产生真实效果。

    我们再把事务关闭,改为自动提交:

    mysql> set autocommit=1;
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> select @@autocommit;
    +--------------+
    | @@autocommit |
    +--------------+
    |            1 |
    +--------------+
    1 row in set (0.00 sec)
    

    3. 事务的其他打开方式?

    手动开启事务:begin或者 start transaction,都可以帮我们手动开启一个事务

    这里进行转账例子:

    mysql> update user set money=money-100 where name='a';
    Query OK, 1 row affected (0.95 sec)
    Rows matched: 1  Changed: 1  Warnings: 0
    
    mysql> update user set money=money+100 where name='b';
    Query OK, 1 row affected (0.14 sec)
    Rows matched: 1  Changed: 1  Warnings: 0
    
    mysql> select * from user;
    +----+------+-------+
    | id | name | money |
    +----+------+-------+
    |  1 | a    |   900 |
    |  2 | b    |  1100 |
    +----+------+-------+
    2 rows in set (0.00 sec)
    
    #事务回滚
    mysql> rollback;
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> select * from user;
    +----+------+-------+
    | id | name | money |
    +----+------+-------+
    |  1 | a    |   900 |
    |  2 | b    |  1100 |
    +----+------+-------+
    2 rows in set (0.00 sec)
    
    

    这里发现现在rollback是没有任何效果的,因为现在autocommit=1,为自动提交模式,每当执行一句话就立即生效了。

    现在在输入这两个语句之前,输入begin或者 start transaction

    #加上begin;或者 start transaction 开启事务
    mysql> begin;
    Query OK, 0 rows affected (0.01 sec)
    
    #对a、b进行转账操作
    mysql>  update user set money=money-100 where name='a';
    Query OK, 1 row affected (0.00 sec)
    Rows matched: 1  Changed: 1  Warnings: 0
    mysql> update user set money=money+100 where name='b';
    Query OK, 1 row affected (0.00 sec)
    Rows matched: 1  Changed: 1  Warnings: 0
    
    #看一下表
    mysql> select * from user;
    +----+------+-------+
    | id | name | money |
    +----+------+-------+
    |  1 | a    |   800 |
    |  2 | b    |  1200 |
    +----+------+-------+
    2 rows in set (0.00 sec)
    
    #事务回滚
    mysql> rollback;
    Query OK, 0 rows affected (0.57 sec)
    
    mysql> select * from user;
    +----+------+-------+
    | id | name | money |
    +----+------+-------+
    |  1 | a    |   900 |
    |  2 | b    |  1100 |
    +----+------+-------+
    2 rows in set (0.00 sec)
    

    事务开启后,一旦 commit 提交,就不可回滚(也就是这个事务在提交的时候结束了),此时再rollback也没有用了

    二、事物的四大特性

    1. 原子性

    • 事务是一组不可分割的单位,要么同时成功,要么同时不成功

    2. 一致性

    • 事物前后的数据完整性应该保持一致(数据库的完整性:如果数据库在某一时间点下,所有的数据都符合所有的约束,则称数据库为完整性的状态)

    3. 隔离性

    • 事物的隔离性是指多个用户并发访问数据时,一个用户的事物不能被其它用户的事务所干扰,多个并发事务之间数据要相互隔离

    4. 持久性

    • 持久性是指一个事物一旦被提交,它对数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响
  • 相关阅读:
    android判断程序是否前台显示---及判断屏幕是否是亮的----附赠BAIDU定位的工具类实现代码
    Lock and synchronized 摘自官网, 摘录下来方便笔记
    SQLite 基础
    如何stop,suspend一个线程 在deprecated的情况下
    HashMap 的遍历 for:each 和EntrySet两种方法
    ListView图片异步加载与缓存策略
    android debug学习笔记 monkeyrunner
    回溯法和DFS leetcode Combination Sum
    leetcode Count and Say
    leetcode Jump Game I II 待续 贪心看不懂啊!!!!
  • 原文地址:https://www.cnblogs.com/fxyadela/p/11605151.html
Copyright © 2011-2022 走看看