事务

一】概念:事务指逻辑上的一组操作,组成这组操作的各个单元,要么全部成功,要么全部不成功。
         (每种数据库都有事务的支持,但支持的强度不同)
二】SQL语句操作事务命令
        1)开启事务
            START TRANSACTION  
        2)回滚事务
            ROLLBACK
        3)提交事务
            COMMIT
        
        code:

            START TRANSCATION;
            DELETE FROM user where id>50;
            ROLLBACK;
            COMMIT;

 


        注意:
            1> 在事务范围内回滚是允许的,但如果COMMIT后再回滚无效。
            2> 其实每条SQL都有事务存在,只是数据库默认将此事务隐藏起来了
        
三】JDBC控制事务语句
        步骤:
            1)设置事务为非自动提交
                Connection.setAutoCommit(false);
            2)进行回滚操作,一般放在catch语句中
                Connection.rollback();
            3)进行事务的提交
                Connection.commit();
        code:
         

      转账案例:jack-->merry
            
            conn = JDBCUtils.getConnection();
            try {
                //设置事务为非自动提交
                conn.setAutoCommit(false);
                pstmt = conn.prepareStatement(TranSqlMapping.JACK_OUT_SQL);//UPDATE test_transcation SET salary=salary-1000 WHERE name='jack'
                pstmt.executeUpdate();
                int i = 10 / 0;
                pstmt = conn.prepareStatement(TranSqlMapping.MERRY_INT_SQL);//UPDATE test_transcation SET salary=salary+1000 WHERE name='merry'
                pstmt.executeUpdate();
                //提交事务
                conn.commit();
            } catch (SQLException e) {
                try {
                    // 当出错时进行“回滚事务”操作
                    conn.rollback();
                    conn.commit();
                } catch (SQLException e1) {
                    e1.printStackTrace();
                }
                e.printStackTrace();
            } finally {
                JDBCUtils.closeAll(rs, pstmt, conn);
            }

 

 


        
 四】设置事务的回滚点
            1)设置一个回滚点
                Savepoint Connection.setSavepoint();
            2)回滚到指定的回滚点
                void Connection.rollback(Savepoint sp);
            总结:
             1)事务的操作必须针对同一个Connection
             2)事务的操作中可以设置一个回滚点,可以回滚到特定的回滚点处
            
五】事务的特性(ACID)
                     1>原子性(A):事务中的各个操作是一个不可分割的子操作,必须将其看成一个整体。
                     2>一致性(C):事务前后,由一个一致状态转移到另一个一致状态
                  *3>隔离性(I):事务中,不同线程操作同张表同条记录时,互相隔离。
                     4>持久性(D):事务一旦生效,在没有操作该记录时的情况下,永远保持不变
六】三个缺点(未被隔离性)
                     1>脏读:一个线程看到了另一个线程未提交的数据
                     2>不可重复读:在一个事务内读取表中的某一个记录,多次读取的结果不同。
                             /*上述两项:强调的是查询,内容变,但数量不变*/
                     3>虚读/幻读:在一个事务内读取到了别的事务插入的数据,导致前后结果不一致
                             /*上述一项:强调的是插入,数量变*/
七】事务的隔离级别——解决三个缺点的办法
                1)查看当前事务的隔离级别
                        SELECT @@TX_ISOLATION;
                        
                2)SQL修改当前事务的隔离级别
                        SET TRANSACTION ISOLATION LEVEL 【事务级别】
                    eg:
                        SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
                        SET TRANSACTION ISOLATION LEVEL READ COMMINTTED;
                        SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;(默认)
                        SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
                        
                3)通过JDBC来设置当前事务的隔离级别
                    1> void setTransactionlsolation(int level)
                   
                        参数:level为Connection中的静态属性
                        static int TRANSACTION_NONE
                                  指示事务不受支持的常量。
                        *static int TRANSACTION_READ_COMMITTED
                                  指示不可以发生脏读的常量;不可重复读和虚读可以发生。
                        static int TRANSACTION_READ_UNCOMMITTED
                                  指示可以发生脏读 (dirty read)、不可重复读和虚读 (phantom read) 的常量。
                        *static int TRANSACTION_REPEATABLE_READ
                                  指示不可以发生脏读和不可重复读的常量;虚读可以发生。
                        static int TRANSACTION_SERIALIZABLE
                                  指示不可以发生脏读、不可重复读和虚读的常量。
                        
                    code:

                     conn = JDBCUtils.getConnection();
                        try {
                            // 设置事务的提交方式为非自动提交
                            conn.setAutoCommit(false);
                            // 设置事务的隔离级别为TRANSACTION_SERIALIZABLE
                            conn.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE);
                            pstmt = conn.prepareStatement(TranSqlMapping.SELECT_ALL);
                            Thread.sleep(10 * 1000);
                            //当另一个线程在进行INSERT等操作的时候此句会阻塞
                            rs = pstmt.executeQuery();
                            // 提交事务
                            conn.commit();
                        } catch (SQLException e) {
                            try {
                                conn.rollback();
                                conn.commit();
                            } catch (SQLException e1) {
                                e1.printStackTrace();
                            }
                            e.printStackTrace();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        } finally {
                            JDBCUtils.closeAll(rs, pstmt, conn);
                        }            

                           
                           
总结:
                1)在项目中,对于SELECT操作不需要事务,对于其它操作(update/delete/insert)操作需要事务。
                2)项目中,事务可能在dao层,也可以能在service层无论在哪一层,都必须确保使用的都是同一个Connection
                3)为了确保在Service和Dao层中用到的Connection一致,可以使用以下方法:
                    a)将Service中的Connection传入Dao中
                            缺点:Service和Dao代码过分耦合
                                        在Service中引入了非业务逻辑操作
                    b)将JdbcUtils类中的Connection做成单例模式
                    c)***使用ThreanLocal<T>类将每个线程和自己的Connection绑定在一起,每个线程修改自己的Connection不会影响其它线程的Connection(相当于是副本的模式)
                    
                        code:
                            //JDBCUtils
                            
                    d)在分层结构中,关闭Connection必须要.

posted on 2014-10-08 17:13  SkyGood  阅读(300)  评论(0编辑  收藏  举报