java web 41 : MySQL数据库事务

----------------------------------------------------
unit09-事务总结
----------------------------------------------------
一、事务及事务的四大特性
1、什么是事务
    事务:将一堆的SQL语句绑定在一起执行,结果是要么全都执行成功(都成功才算成功),要么全都执行失败(有一个失败就按全失败来处理)!
    举例:转账,张三(1000元)给李四(1000元)转账100元
    开启事务--------
    张三账户减去100元:
        update 账户表 set money=money-100 where name='张三'; -- 900
    李四账户加上100元:
        update 账户表 set money=money+100 where name='李四'; -- 1000
    结束事务: 提交/回滚
2、事务的四个特性
    (1)原子性:事务中的所有操作都是一个整体,不能被分割,要么全都执行成功,要么全都执行失败!
    (2)一致性:在事务执行前后的业务数据之和,是保持一致的。
        举例:转账,张三(1000元)给李四(1000元)转账100元
        开启事务:--------------
        张三(1000) - 100 = 900
        李四(1000) + 100 = 1100
        结束事务:提交/回滚--------
        不管事务最后是提交了,还是回滚了,张三和李四的账户金额之和,在转账前、后是保持一致的!
        
    (3)隔离性:在事务并发时,多个事务之间是具有隔离性的,在一个事务中是看不到另外一个事务正在进行中的数据状态
        举例:
        事务1: -- 查询张三和李四的账户金额之和
            张三账户(500) + 李四账户(1000) = 1500 -- 不会出现

            如果事务1在执行时,事务2还没有结束,事务1只能看到事务2还没有开始时的数据的状态:
                张三账户(1000) + 李四账户(1000) = 2000
            如果事务1在执行时,事务2已经结束,事务1可以看到事务2已经结束后的数据的状态:
                张三账户(500) + 李四账户(1500) = 2000
            
        事务2: -- 张三(1000元)给李四(1000元)转账500元
            张三(1000) - 500 = 500    -- 执行了
            李四(1000) + 500 = 1500    -- 还没有来得及执行

        上面结论的前提是:在事务的隔离级别较高时!
        
    (4)持久性:事务提交后,在事务中对数据的更新会持久的保存到数据库中
        在事务提交之前,事务中执行的操作,并没有真正的更新到数据库。
        开始事务: -- 张三(1000元)给李四(1000元)转账500元
            张三(1000) - 500 = 500    
            李四(1000) + 500 = 1500
        结束事务:提交/回滚
        在事务提交执行,张三减去500,以及李四加上500,其实并没有真正修改张三和李四的账户金额,只是在日志中记录了,将来如果事务提交了,在事务提交后,才会真正的到数据库中,更新张三账户金额为500,更新李四账户金额为1500!

3、MySQL中的事务
    默认情况下,MySQL中每一条SQL都是一个事务!
    每次在执行SQL语句之前,会默认开启事务,在执行这条SQL语句之后,会自动提交事务!
    如果需要让两条或者两条以上的SQL语句在一个事务中执行,需要在执行之前开启事务,在最后一条SQL语句执行完后,立即结束事务!
    MySQL中开启事务: start transaction;
    MySQL中结束事务: commit(提交)/rollback(回滚)
    如果事务中的所有SQL语句都执行成功了,最后我们可以提交事务;
    如果事务中的SQL语句有一条执行失败,就按全失败来处理,最后我们会回滚(撤销)事务;

    演示A账户给B账户转账:
    (1)开启事务
    start transaction;
    (2)A账户减去100元:
    update acc set money=money-100 where name='A'; -- 900
    (3)B账户加上100元:
    update acc set money=money+100 where name='B'; -- 1100
    (4)查询A、B的账户金额(在不同的cmd窗口进行查看)
    select * from acc;
    (5)将事务回滚(撤销)、将事务提交
    rollback; / commit;

二、事务的并发读问题(了解)
    多个事务对相同的数据同时进行操作,这叫做事务并发。
    在事务并发时,如果没有采取必要的隔离措施,可能会导致各种并发问题,破坏数据的完整性等。这些问题中,其中有三类是读问题,分别是:脏读、不可重复读、幻读。
    (1)脏读: 在一个事务中,读取到了另外一个事务未提交更新的数据,称之为脏读
        举例: A(买家) B(卖家)
        A转账给B100元:
        开启事务: A - 100 = 900
                B + 100 = 1100
        此时没有提交事务...
        B在另外一个事务中查询到账户增加了100元,也就是1100

        由于MySQL默认不允许出现脏读,所以要想演示脏读现象,必须得将mysql的事务隔离级别设置为最低,如下:
        set tx_isolation='read-uncommitted';

    (2)不可重复读: 在一个事务中对同一数据的两次查询结果不一致,是因为有另一事务对该数据进行了修改操作!
        举例:
        事务1: 在事务1中查询A账户的金额
            第1次查询: select * from acc where name='A'; -- 1000
            第2次查询: select * from acc where name='A'; -- 900

        事务2: A给B转账100元
            update acc set money=money-100 where name='A';
            ...
            提交事务
    (3)幻读: 在一个事务中对同一张表的两次查询结果不一致,是因为有另一事务对表进行了插入或者删除操作!
        举例:
        事务1:
            第1次查询: select * from acc where id=3; -- 不存在
            插入一条id为3的记录: insert into acc value(3,'C',2000); -- 插入失败!
            第2次查询: select * from acc where id=3; -- 已存在

        事务2: 开启事务
            插入了一条id为3的记录: insert into acc value(3,'C',3000);
            提交了事务

三、事务的隔离级别
1、事务的隔离级别
    READ UNCOMMITTED(读未提交数据)
        特点: 安全性最差,不能防止任何的并发读问题,但性能最高,不推荐使用!
        
    READ COMMITTED(读已提交数据) -- Oracle默认的隔离级别
        特点: 安全性比"读未提交"较好,可以防止脏读,但不能防止不可重复读,也不能防止幻读,性能比"读未提交"差。

    REPEATABLE READ(可重复读) -- MySQL默认的隔离级别
        特点: 安全性比"读已提交"较好,可以防止脏读、不可重复读,但不能防止幻读,性能比"读已提交"较差
        由于mysql默认的隔离级别不允许出现脏读和不可重复读,因此要想在mysql中演示这两个现象,
        必须要设置mysql的隔离级别为最低级别,也就是“读未提交”
        
    SERIALIZABLE(串行化)
        特点: 安全性最好,可以防止脏读、不可重复读、幻读,性能最差,也不推荐使用!

2、如何设置事务的隔离级别(了解)
    因为数据库有自己默认的事务隔离级别,我们不需要去设置!
2.1.mysql中如何设置事务的隔离级别
    mysql中如何查询当前使用的事务隔离级别:
        select @@tx_isolation;
    mysql中如何设置事务的隔离级别:
        set tx_isolation='read-uncommitted'; -- 设置隔离级别为"读未提交"
        set tx_isolation='read-committed'; -- 设置隔离级别为"读已提交"
        set tx_isolation='repeatable-read'; -- 设置隔离级别为"可以重复读"
        set tx_isolation='serialiable'; -- 设置隔离级别为"串行化"
        
2.2.JDBC中如何设置事务的隔离级别
    JDBC中通过Connection提供的方法设置事务隔离级别:
        Connection.setTransactionIsolation(int level)

    level参数可选值如下:
        Connection.TRANSACTION_READ_UNCOMMITTED 1(读未提交数据)
        Connection.TRANSACTION_READ_COMMITTED     2(读已提交数据)
        Connection.TRANSACTION_REPEATABLE_READ     4(可重复读)
        Connection.TRANSACTION_SERIALIZABLE     8(串行化)
        Connection.TRANSACTION_NONE             0(不使用事务)

    JDBC转账的例子:代码参考讲义!
    JDBC也是在执行一条SQL语句之前,默认开启事务,执行之后,立即提交事务!
    因此要想在JDBC中,将两条或以上的SQL语句放在一个事务中执行,需要关闭自动提交事务!
        conn.setAutoCommit(false);

 
 

posted @ 2020-08-19 14:57  Saturn5  阅读(44)  评论(0)    收藏  举报