07、Mysql事务

130 阅读8分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第32天,点击查看活动详情

07、事务

01.事务_概念:

    1).什么是"事务" : 事务,是数据库中的概念,它是指程序的一个"业务"在数据库中要由多个SQL语句完成,例如:

              转账业务:张三给李四转账1000元:

              数据库中:

                    1).张三账户减少1000元;

                    2).李四账户增加1000元;

              如果在执行第一条语句之后,系统崩溃,或者断电,将会导致张三账户减少1000元而李四账户没有增加,

              就会导致数据错误。对于这种情况,要求数据库软件必须要有能力,将这些SQL语句看成是一个"整体",

              执行后,要么全部成功,要么全部失败。这种操作能力就叫:事务处理。

02.事务_MySQL中处理事务的方式:

    1).MySQL中默认的事务处理方式:自动提交(自动事务)。它将每条SQL语句都作为一个独立的事务执行,执行后,立即修改数据库,数据会被永久修改。语句和语句之间没有任何关联。这种方式不能满足我们业务的需求;

在事务中,如果执行了DDL语句,数据库会在执行DDL语句之前,提交事务

事务涉及的语句属于DCL语句

在一个事务没有关闭,打开一个新的事务,数据库会自动提交上一个事务

    2).查看MySQL中的事务处理方式:

        show variables like 'autocommit';
        查询结果:
            autocommit    ON (自动提交--开启)          

    3).MySQL中处理事务的方式:

        1).关闭自动提交,设置为手动提交:(只对当前登录用户有效)      cmd 命令下,关闭cmd 页面 就自动变为自动提交
            1).关闭自动提交
                set autocommit = off;
            2).发送SQL语句:
                update ....
                insert ....
                delete ....
            3).提交
                    commit;
               回滚
                rollback;

        2).在自动提交状态下,开启一个临时事务:【重点掌握】
            1).开启临时事务:
                start transaction;
            2).发送SQL语句:
                update ...
                insert ...
                delete ...
            3).提交
                commit;    //会立即结束本次事务,恢复到自动提交状态
               回滚
                rollback;//会立即结束本次事务,恢复到自动提交状态

手动事务:

1)显示的开启一个事务:start transaction

2)事务提交:commit代表从开启事务到事务提交 中间的所有的sql都认为有效  真正的更新数据库

3)事务的回滚:rollback 代表事务的回滚 从开启事务到事务回滚 中间的所有的 sql操作都认为无效数据库没有被更新

03.事务_JDBC中处理事务的方式【重点掌握】:

    .....
    //关闭自动提交
    conn.setAutoCommit(false);
    .....

    try{
        //4.发送SQL语句
        ......          
        //提交                                   ////  判断影响行数是否为 1,抛异常或者  回滚 return;  如果不为1,代表操作未成功,mysql不会抛异常,需要手动处理
        conn.commit();
    }catch(Exception e){
        //回滚
        conn.rollback();
    }
    .....              // 最后需要释放资源,    关闭资源跟恢复自动提交效果一样    如果后面还有事务操作的话 ,需要先设置 一下 恢复为自动提交  操作完下一个事务 才 关闭

                    //5.恢复为自动提交

                   conn.setAutoCommit(true);

默认是自动事务:

执行sql语句:executeUpdate()  ---- 每执行一次executeUpdate方法 代表 事务自动提交
通过jdbc的API手动事务:
开启事务:conn.setAutoComnmit(false);
提交事务:conn.commit();
回滚事务:conn.rollback();
注意:控制事务的connnection必须是同一个

执行sql的connection与开启事务的connnection必须是同一个才能对事务进行控制

04.事务_DBUtils中处理事务的方式【重点掌握】:

    //1.创建一个QueryRunner对象
    QueryRunner qr = new QueryRunner();//如果要使用事务处理,这里就不需要连接池构造
    //2.从连接池获取一个Connection对象
    Connection conn = DataSourceUtils.getConnection();
    //3.关闭自动提交
    conn.setAutoCommit(false);
    //4.执行查询
    try{
        int row1 = qr.update(conn, "update account set balance = balance - 1000 where uname = 'zhangsan'");
        int row2 = qr.update(conn, "update account set balance = balance + 1000 where uname = 'lisi'");
        if(row1 == 0 || row2 == 0){                                   //  判断影响行数是否为 1,抛异常或者  回滚 return;  如果不为1,代表操作未成功,mysql不会抛异常,需要手动处理
            throw new Exception();
        }
        //提交
        conn.commit();
        System.out.println("提交......");
    }catch(Exception e){
        //回滚
        conn.rollback();
        System.out.println("回滚...");
    }

    //5.恢复为自动提交
    conn.setAutoCommit(true);
    //6.归还连接
    conn.close();          // 归还没有关闭所以要 恢复自动提交

有参构造:QueryRunner runner = new QueryRunner(DataSource dataSource);                    //  如果用这个构造,调用方法的时候,还传了一个 conn 就近 qr.update(conn, sql)用的连接是传的 conn,如果conn为null的话,该方法会异常

有参构造将数据源(连接池)作为参数传入QueryRunner,QueryRunner会从连    接池中获得一个数据库连接资源操作数据库,所以直接使用无Connection参数     的update方法即可操作数据库

无参构造:QueryRunner runner = new QueryRunner();              // 为保证一个事务操作使用的是同一个 conn   ,所以这里要用无参构造,手动获取连接

无参的构造没有将数据源(连接池)作为参数传入QueryRunner,那么我们在使 用QueryRunner对象操作数据库时要使用有Connection参数的方法



05.代码分层_代码分层的概念_意义:

    1).之前我们将所有业务代码都写在一个类中,如果程序很复杂,代码量会非常的庞大,对后期的维护和更新都带来了麻烦。

    2).我们可以将这些代码按照不同的功能,存储在不同的类中。

       早期的前辈们发现任何的软件都包含以下两部分代码:

        1).用于接收数据、显示数据的代码;    视图层(View)

        2).用于业务逻辑处理。            控制层(Controller)

        3).数据模型,用于在两层之间传递数据;    模型层(Model)

       这就是最早期的:MVC模式

    3).对于大型的企业级软件,这三层远远不够,我们使用的是五层架构:

        1).用于接收数据、显示数据的代码:        视图层(View)

        2).接收前端数据、命令,转发到相应的业务层:    控制层(Controller)

        3).用于处理具体业务逻辑的业务层:        业务层(Service)

        4).用户访问数据库的持久层:            持久层(DAO模式)

        5).数据模型,用于层和层之间传递数据        模型层(Model)

    4).五层架构的调用规则:

        1).从前到后:视图层-->控制层-->业务层-->持久层

           这四层之间有一个"顺序的依赖关系",不能跨层调用。

           反向没有依赖关系。持久层永远不会主动调用业务层,业务层也永远不会主动调用控制层....

           后层的对象只能被前层的对象调用,并为其返回值,不能主动调用前层对象的方法。

    5).意义:代码按照功能分类存储,如果要修改某些代码,只要找到相应的类即可,不会影响其他类的代码;

       弊端:代码量增加;层层调用也会带来调试的困难。

       总体上:利大于弊

06.事务的特性【了解】:

    1).事务的特性:

        原子性:强调事务的不可分割.多条语句要么都成功,要么都失败。

        一致性:强调的是事务的执行的前后,数据要保持一致.

        隔离性:一个事务的执行不应该受到其他事务的干扰.

        持久性:事务一旦结束(提交/回滚)数据就持久保持到了数据库.

    2).如果两个事务不隔离,可能产生的情况:

        脏读        :一个事务读到另一个事务还没有提交的数据.               //   一个用户的事务操作到一半,并未提交的数据,被另一个用户  读到

        不可重复读    :一个事务读到了另一个事务已经提交的update的数据,导致在当前的事务中多次查询结果不一致.               // 用户 1 操作数据库 操作到一半,未提交, 用户二 此时读数据 ,读到用户 1 操作到一半的数据,  用户1 继续操作数据库,提交, 用户

                                                                                                                                                                                        //   2再读 ,这次读的 跟上次用户2 读到的数据不相同

        虚读/幻读    :一个事务读到另一个事务已经提交的insert的数据,导致在当前的事务中多次的查询结果不一致.                    //  好像是mysql 已经解决 

    3).四个隔离级别:

        1 read uncommitted    :未提交读.脏读,不可重复读,虚读都可能发生.
        2 read committed    :已提交读.避免脏读.但是不可重复读和虚读有可能发生.(Oracle默认)
        4 repeatable read    :可重复读.避免脏读,不可重复读.但是虚读有可能发生.(MySql默认)
        8 serializable        :串行化的.避免脏读,不可重复读,虚读的发生.                  // -相当于锁表  ,一个事务操作时,未提交之前, 另一个事务只能等待,等上个事务操作完,该事务才能操作

    4).查看当前的隔离级别:

        select @@tx_isolation;

    5).设置当前会话的隔离级别:

        set session transaction isolation level 上述四个隔离级别之一;


ThreadLocal:实现的是通过线程绑定的方式传递参数
                  概念:
                       事务的特性ACID
                       并发问题:脏读、不可重读、虚读\幻读
                       解决并发:设置隔离级别
                             read uncommitted
                             read committed
                             repeatable read (mysql默认)
                             serialazable

                       隔离级别的性能:
                             read uncommitted>read committed>repeatable read>serialazable
                       安全性:

                             read uncommitted<read committed<repeatable read<serialazable