码迷,mamicode.com
首页 > 数据库 > 详细

Java开发工程师(Web方向) - 03.数据库开发 - 第4章.事务

时间:2017-08-24 14:51:12      阅读:227      评论:0      收藏:0      [点我收藏+]

标签:原因   money   cti   工作   lte   failed   用户   nsa   nec   

第4章--事务

事务原理与开发

事务Transaction: 

什么是事务?

事务是并发控制的基本单位,指作为单个逻辑工作单元执行的一系列操作,且逻辑工作单元需满足ACID特性。

i.e. 银行转账:开始交易;张三账户扣除100元;李四账户增加100元;结束交易。

事务的特性:ACID

原子性 Atomicity:整个交易必须作为一个整体来执行。(要么全部执行,要么全部不执行)

一致性 Consistency:整个交易总体资金不变

隔离性 Isolation:

case1: 若张三给李四转账过程中,赵五给张三转账了200元。两个交易并发执行。

T1   T2

读取张三余额100;

                              读取张三余额100;

给李四转账100,

更新张三余额为0;

交易结束                  赵五转入200,

                              更新张三余额为300

交易结束

case2: 脏读:张三给别人转账100之后张三存钱200,存钱后转账由于系统原因失败回滚。

读取一个事务未提交的更新

T1 T2

读取张三余额100

(转账) 更新张三余额0

读取张三余额0

T1 Rollback() (存钱) 更新张三余额200

T2结束(张三账户余额为200)

case3: 不可重复读:同一个事务,两次读取同一数值的结果不同,成为不可重复读。

T1张三读取自己余额为100;T2读取张三余额100;T2存钱更新为300;T1张三读取余额为300。T1中两次读取张三余额即为不可重复读。

case4: 幻读:两次读取的结果包含的行记录不一样。

T1读取所有用户(张三、李四);T2新增用户赵五;T1读取所有用户(3个);T1/T2结束。T1中两次读取的结果中行记录数不同,称为幻读。

 

需要避免上述cases的产生

隔离性:交易之间相互隔离,在一个交易完成之前,不能受到其他交易的影响

持久性 Durability:整个交易过程一旦结束,无论出现任何情况,交易都应该是永久生效的

使用JDBC进行事务控制:

Connection类中

.setAutoCommit():开启事务(若为false,则该Connection对象后续的sql都将作为事务来处理;若为true,则该Connection对象后续的所有sql都将作为单独的语句执行(默认为true))

.commit():事务被提交,即事务生效并结束

.rollback():回滚,回退到事务开始之前的状态

i.e.

ALTER TABLE user ADD Account int;
UPDATE User SET Account = 100 WHERE id = 1;
UPDATE User SET Account = 0 WHERE id > 1;

技术分享

实现ZhangSi(1)给LiSan(2)转账的过程:

(非事务:)

public static void TransferNonTransaction() {
    Connection conn = null;
    PreparedStatement ptmt = null;
    
    try {
        conn = DriverManager.getConnection(DB_URL, USER_NAME, PASSWORD);
        String sql = "UPDATE User SET Account = ? WHERE userName = ? AND id = ?;";
        // transfer 100 from ZhangSi(1) to LiSan(2)
        ptmt = conn.prepareStatement(sql);
        ptmt.setInt(1, 0);
        ptmt.setString(2, "ZhangSi");
        ptmt.setInt(3, 1);
        ptmt.execute();

        ptmt.setInt(1, 100);
        ptmt.setString(2, "LiSan");
        ptmt.setInt(3, 2);
        ptmt.execute();
    } catch (SQLException e) {
        e.printStackTrace();
    } finally {
        try {
            if (conn != null) conn.close();
            if (ptmt != null) ptmt.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

 

执行完第一个ptmt.execute()后,数据库中ZhangSi的Account=0, LiSan的Account=0;

出现了一个中间状态,对于整个业务逻辑的实现是不可接受的。如果此时程序崩溃了将不可挽回。

(事务:)

public static void TransferByTransaction() {
    Connection conn = null;
    PreparedStatement ptmt = null;
    try {
        conn = DriverManager.getConnection(DB_URL, USER_NAME, PASSWORD);
        
        // Using Transaction mechanism
        conn.setAutoCommit(false);
        String sql = "UPDATE User SET Account = ? WHERE userName = ? AND id = ?;";
        ptmt = conn.prepareStatement(sql);
        ptmt.setInt(1, 0);
        ptmt.setString(2, "ZhangSi");
        ptmt.setInt(3, 1);
        ptmt.execute();

        ptmt.setInt(1, 100);
        ptmt.setString(2, "LiSan");
        ptmt.setInt(3, 2);
        ptmt.execute();
        
        // Commit the transaction
        conn.commit();
        
    } catch (SQLException e) {
        // if something wrong happens, rolling back
        if(conn != null) {
            try {
                conn.rollback();
            } catch (SQLException e1) {
                e1.printStackTrace();
            }
        }
        e.printStackTrace();
    } finally {
        try {
            if (conn != null) conn.close();
            if (ptmt != null) ptmt.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

 

若在第一个ptmt.execute()时断点,并查询数据库,结果为事务执行之前的状态,并不是中间状态。

直到conn.commit()方法执行完毕,事务中的所有操作在数据库中才有效。

Connection类中的检查点功能:

.setSavePoint():在执行过程中创建保存点,以便rollback()可以回滚到该保存点

.rollback(SavePoint savePoint):回滚到某个检查点

i.e.

public static void rollbackTest() {
    Connection conn = null;
    PreparedStatement ptmt = null;
    // save point
    Savepoint sp = null;
    try {
        conn = DriverManager.getConnection(DB_URL, USER_NAME, PASSWORD);
        
        conn.setAutoCommit(false);
        String sql = "UPDATE User SET Account = ? WHERE userName = ? AND id = ?;";
        ptmt = conn.prepareStatement(sql);
        ptmt.setInt(1, 0);
        ptmt.setString(2, "ZhangSi");
        ptmt.setInt(3, 1);
        ptmt.execute();
        // create a save point
        sp = conn.setSavepoint();

        ptmt.setInt(1, 100);
        ptmt.setString(2, "LiSan");
        ptmt.setInt(3, 2);
        ptmt.execute();

        // throw an exception manually for the purpose of testing
        throw new SQLException();
        
    } catch (SQLException e) {
        // if something wrong happens, rolling back to the save point created before
        // and then transfer the money to Guoyi(3)
        if(conn != null) {
            try {
                conn.rollback(sp);
                System.out.println("Transfer from ZhangSi(1) to LiSan(2) failed;\n"
                        + "Transfer to GuoYi(3) instead");
                
                // other operations
                ptmt.setInt(1, 100);
                ptmt.setString(2, "GuoYi");
                ptmt.setInt(3, 3);
                ptmt.executeQuery();
                conn.commit();
            } catch (SQLException e1) {
                e1.printStackTrace();
            }                     
        }
        
        e.printStackTrace();
    } finally {
        try {
            if (conn != null) conn.close();
            if (ptmt != null) ptmt.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

 

事务的隔离级别:4个级别

读未提交(read uncommited):可能导致脏读

读提交(read commited):不可能脏读,但是会出现不可重复读

重复读(repeatable read):不会出现不可重复读,但是会出现幻读

串行化(serializable):最高隔离级别,不会出现幻读,但严格的并发控制、串行执行导致数据库性能差

N.B. 1. 事务隔离级别越高,数据库性能越差,但对于开发者而言编程难度越低。

  2. MySQL默认事务隔离级别为重复读 repeatable read

JDBC设置隔离级别:

Connection对象中,

.getTransactionIsolation();

.setTransactionIsolation();

 

死锁分析与解决

 

 

 

 

 

 

Java开发工程师(Web方向) - 03.数据库开发 - 第4章.事务

标签:原因   money   cti   工作   lte   failed   用户   nsa   nec   

原文地址:http://www.cnblogs.com/FudgeBear/p/7422845.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!