zoukankan      html  css  js  c++  java
  • 事务详解

    事务概述

    1 什么是事务
      银行转账!张三转10000块到李四的账户,这其实需要两条SQL语句:
        给张三的账户减去10000元;
        给李四的账户加上10000元。
      如果在第一条SQL语句执行成功后,在执行第二条SQL语句之前,程序被中断了(可能是抛出了某个异常,也可能是其他什么原因),那么李四的账户没有加上10000元,而张三却减去了10000元。这肯定是不行的!你现在可能已经知道什么是事务了吧!事务中的多个操作,要么完全成功,要么完全失败!不可能存在成功一半的情况!也就是说给张三的账户减去10000元如果成功了,那么给李四的账户加上10000元的操作也必须是成功的;否则给张三减去10000元,以及给李四加上10000元都是失败的!

    2 事务的四大特性(ACID)
      事务的四大特性是:
        原子性(Atomicity):事务中所有操作是不可再分割的原子单位。事务中所有操作要么全部执行成功,要么全部执行失败。
        一致性[其他特性都是为了这一特性服务的。](Consistency):事务执行后,数据库状态与其它业务规则保持一致。如转账业务,无论事务执行成功与否,参与转账的两个账号余额之和应该是不变的。
        隔离性(Isolation):隔离性是指在并发操作中,不同事务之间应该隔离开来,使每个并发中的事务不会相互干扰。
        持久性(Durability):一旦事务提交成功,事务中所有的数据操作都必须被持久化到数据库中,即使提交事务后,数据库马上崩溃,在数据库重启时,也必须能保证通过某种机制恢复数据。

    3 MySQL中的事务
      在默认情况下,MySQL每执行一条SQL语句,都是一个单独的事务。如果需要在一个事务中包含多条SQL语句,那么需要开启事务和结束事务。
        开启事务:start transaction;
        结束事务:commit或rollback。
      在执行SQL语句之前,先执行start transaction,这就开启了一个事务(事务的起点),然后可以去执行多条SQL语句,最后要结束事务,commit表示提交,即事务中的多条SQL语句所做出的影响会持久化到数据库中。或者rollback,表示回滚,即回滚到事务的起点,之前做的所有操作都被撤消了!
      下面演示zs给li转账10000元的示例:
        START TRANSACTION;
        UPDATE account SET balance=balance-10000 WHERE id=1;
        UPDATE account SET balance=balance+10000 WHERE id=2;
        ROLLBACK[回滚结束,事务执行失败];
        START TRANSACTION;
        UPDATE account SET balance=balance-10000 WHERE id=1;
        UPDATE account SET balance=balance+10000 WHERE id=2;
        COMMIT[提交结束,事务执行成功];
        START TRANSACTION;
        UPDATE account SET balance=balance-10000 WHERE id=1;
        UPDATE account SET balance=balance+10000 WHERE id=2;
        quit[退出,MySQL会自动回滚事务。];

    JDBC事务
      在jdbc中处理事务,都是通过Connection完成的!
      同一事务中所有的操作,都在使用同一个Connection对象!

    1 JDBC中的事务
      Connection的三个方法与事务相关:
        setAutoCommit(boolean):设置是否为自动提交事务,如果true(默认值就是true)表示自动提交,也就是每条执行的SQL语句都是一个单独的事务,如果设置false,那么就相当于开启了事务了;con.setAutoCommit(false)表示开启事务!!!
        commit():提交结束事务;con.commit();表示提交事务
        rollback():回滚结束事务。con.rollback();表示回滚事务

      jdbc处理事务的代码格式:

    try {
      con.setAutoCommit(false);//开启事务…
      ….  //SQL语句
      …  //SQL语句
      con.commit();//try的最后提交事务
    } catch() {
      con.rollback();//回滚事务
    }

    事务隔离级别

    1   事务的并发读问题
      脏读[不能允许出来的事情!]:读取到另一个事务未提交数据;
      不可重复读:两次读取不一致;
      幻读(虚读):读到另一事务已提交数据。

    2 并发事务问题
      因为并发事务导致的问题大致有5类,其中两类是更新问题,三类是读问题。  

        丢失更新(第一类丢失更新)撤销一个事务时,把其他事务已提交的更新数据覆盖(A和B事务并发执行,A事务执行更新后,提交;B事务在A事务更新后,B事务结束前也做了对该行数据的更新操作,然后回滚,则两次更新操作都丢失了)。这种并发问题是由于完全没有隔离事务造成的。只要设置隔离级别,数据库就能保证此类问题不发生。

        覆盖更新(第二类丢失更新)这是不可重复读中的特例,一个事务覆盖另一个事务已提交的更新数据(即A事务更新数据,然后B事务更新该数据,A事务查询发现自己更新的数据变了)。 

        脏读(dirty read):读到另一个事务的未提交更新数据,即读取到了脏数据;
        不可重复读(unrepeatable read):对同一记录的两次读取不一致,因为另一事务对该记录做了修改;
        幻读(虚读)(phantom read):对同一张表的两次查询不一致,因为另一事务插入了一条记录;

      脏读
        事务1:张三给李四转账100元
        事务2:李四查看自己的账户

        t1:事务1:开始事务
        t2:事务1:张三给李四转账100元
        t3:事务2:开始事务
        t4:事务2:李四查看自己的账户,看到账户多出100元(脏读)
        t5:事务2:提交事务
        t6:事务1:回滚事务,回到转账之前的状态
      不可重复读
        事务1:酒店查看两次1048号房间状态
        事务2:预订1048号房间

        t1:事务1:开始事务
        t2:事务1:查看1048号房间状态为空闲
        t3:事务2:开始事务
        t4:事务2:预定1048号房间
        t5:事务2:提交事务
        t6:事务1:再次查看1048号房间状态为使用
        t7:事务1:提交事务
        对同一记录的两次查询结果不一致!

      幻读
        事务1:对酒店房间预订记录两次统计
        事务2:添加一条预订房间记录

        t1:事务1:开始事务
        t2:事务1:统计预订记录100条
        t3:事务2:开始事务
        t4:事务2:添加一条预订房间记录
        t5:事务2:提交事务
        t6:事务1:再次统计预订记录为101记录
        t7:事务1:提交
        对同一表的两次查询不一致!

      不可重复读和幻读的区别:
        不可重复读是读取到了另一事务的更新;
        幻读是读取到了另一事务的插入(MySQL中无法测试到幻读);

    3 四大隔离级别

      4个等级的事务隔离级别,在相同数据环境下,使用相同的输入,执行相同的工作,根据不同的隔离级别,可以导致不同的结果。不同事务隔离级别能够解决的数据并发问题的能力是不同的。

      1 SERIALIZABLE(串行化)[三种读问题都能处理]
        不会出现任何并发问题,因为它是对同一数据的访问是串行的,非并发访问的;
        性能最差;

      2 REPEATABLE READ[脏读、不可重复读,不能处理幻读](可重复读)(MySQL默认)
        防止脏读和不可重复读,不能处理幻读问题;
        性能比SERIALIZABLE好

      3 READ COMMITTED[只能处理脏读,不能处理不可重复读和幻读。](读已提交数据)(Oracle默认)
        防止脏读,没有处理不可重复读,也没有处理幻读;
        性能比REPEATABLE READ好
      4 READ UNCOMMITTED[啥也不处理!](读未提交数据)
        可能出现任何事务并发问题
        性能最好

    5 MySQL隔离级别
      MySQL的默认隔离级别为Repeatable read,可以通过下面语句查看:select @@tx_isolation

      也可以通过下面语句来设置当前连接的隔离级别:SET tx_isolation=...;例如:SET tx_isolation='read-committed';

    6 JDBC设置隔离级别
      con. setTransactionIsolation(int level)
      参数可选值如下:
        Connection.TRANSACTION_READ_UNCOMMITTED;
        Connection.TRANSACTION_READ_COMMITTED;
        Connection.TRANSACTION_REPEATABLE_READ;
        Connection.TRANSACTION_SERIALIZABLE。

    事务总结:
      事务的特性:ACID;
      事务开始边界与结束边界:开始边界(con.setAutoCommit(false)),结束边界(con.commit()或con.rollback());
      事务的隔离级别: READ_UNCOMMITTED、READ_COMMITTED、REPEATABLE_READ、SERIALIZABLE。多个事务并发执行时才需要考虑并发事务。

  • 相关阅读:
    231. Power of Two
    204. Count Primes
    205. Isomorphic Strings
    203. Remove Linked List Elements
    179. Largest Number
    922. Sort Array By Parity II
    350. Intersection of Two Arrays II
    242. Valid Anagram
    164. Maximum Gap
    147. Insertion Sort List
  • 原文地址:https://www.cnblogs.com/fengmingyue/p/6057389.html
Copyright © 2011-2022 走看看