JavaWeb学习之事务

一、事务(Transaction):其实是一组操作(包含许多个单一的逻辑)。只要有一个逻辑没有执行成功,那么都算失败。 所有的数据都回归到最初的状态(回滚)

例如:银行转账

A用户向B用户转账,这样的话转账中就有两个逻辑操作,1、A用户账户金额要减少  2、B用户账户金额要增加,此时就需要把这两个逻辑操作放入事务中

代码格式:

@Test
    public void testTransaction(){
        
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        try {
            conn = JDBCUtil.getConn();
            
            //连接,事务默认就是自动提交的。 关闭自动提交。
            conn.setAutoCommit(false);
            
            String sql = "update account set money = money - ? where id = ?";
            ps = conn.prepareStatement(sql);
            
            //扣钱, 扣ID为1 的100块钱
            ps.setInt(1, 100);
            ps.setInt(2, 1);
            ps.executeUpdate();//加钱, 给ID为2 加100块钱
            ps.setInt(1, -100);
            ps.setInt(2, 2);
            ps.executeUpdate();
            
            //成功: 提交事务。
            conn.commit();
            
        } catch (SQLException e) {
            try {
                //事变: 回滚事务
                conn.rollback();
            } catch (SQLException e1) {
                e1.printStackTrace();
            }
            e.printStackTrace();
            
        }finally {
            JDBCUtil.release(conn, ps, rs);
        }
    }

二、事务的特性

  ①、原子性:事务中包含的逻辑,不可分割。

  ②、一致性:事务执行前后。数据完整性

  ③、隔离性:事务在执行期间不应该受到其他事务的影响

  ④、持久性:事务执行成功,那么数据应该持久保存到磁盘上。

三、隔离级别

  ①、读未提交(read uncommitted)

      引发问题: 脏读

  ②、读已提交(read committed)

      解决: 脏读 , 引发: 不可重复读,SQL Server没有这个问题

  ③、可重复读(repeatable-read)

      解决: 脏读 、 不可重复读 , 引发: 幻读 

  ④、可串行化(SERIALIZABLE)

      解决: 脏读、 不可重复读 、 幻读

  mySql 默认的隔离级别是 可重复读

  Oracle 默认的隔离级别是  读已提交

  Sql Server 默认的隔离级别是  读已提交

四、事务的安全隐患

  不考虑隔离级别设置,那么会出现以下问题

    ①、读

      脏读:一个事务读到了另一个事务未提交的数据        

        事务A:

USE Bank
GO
--使用默认隔离级别
BEGIN TRANSACTION
UPDATE ACCOUNT SET Money=Money-300 WHERE Id=1
WAITFOR DELAY '00:00:10'
ROLLBACK TRANSACTION

        事务B:

USE Bank
GO
--设置隔离级别:未提交读
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
BEGIN TRANSACTION
--发生在事务回滚前
SELECT * FROM ACCOUNT WHERE Id=1
WAITFOR DELAY '00:00:10'
--发生在事务回滚后
SELECT * FROM ACCOUNT WHERE Id=1
COMMIT TRANSACTION

        先执行事务A再执行事务B结果:

           

      不可重复读:一个事务读到了另一个事务已提交的数据,造成前后两次查询结果不一致 

        事务A:

USE Bank
GO
--使用默认隔离级别
BEGIN TRANSACTION
UPDATE ACCOUNT SET Money=Money-300 WHERE Id=1
WAITFOR DELAY '00:00:10'
COMMIT TRANSACTION --注意

        事务B:

USE Bank
GO
--设置隔离级别:读已提交
SET TRANSACTION ISOLATION LEVEL READ COMMITTED
BEGIN TRANSACTION
--发生在事务回滚前
SELECT * FROM ACCOUNT WHERE Id=1
WAITFOR DELAY '00:00:10'
--发生在事务回滚后
SELECT * FROM ACCOUNT WHERE Id=1
COMMIT TRANSACTION

        先执行事务B再执行事务A结果:

           

      幻读:一个事务读到了另一个事务insert的数据 ,造成前后查询结果不一致

        事务A      

USE Bank
GO
--使用默认隔离级别
BEGIN TRANSACTION
INSERT INTO ACCOUNT VALUES('Kimi',1000)
COMMIT TRANSACTION

        事务B

USE Bank
GO
--设置隔离级别:读已提交
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ
BEGIN TRANSACTION
--发生在事务提交前
SELECT * FROM ACCOUNT
WAITFOR DELAY '00:00:10'
--发生在事务提交后
SELECT * FROM ACCOUNT
COMMIT TRANSACTION

         先执行事务B再执行事务A结果不一致,为幻读:

          

    ②、写

      丢失更新

        

 

         

 

       数据丢失更新可以通过锁机制,来加以控制

五、总结

 

  脏读 更新丢失 不可重复读 幻读
Read Uncommitted 可能 可能 可能 可能
Read Committed 不可能 可能 可能 可能
Repeatable Read 不可能 不可能 不可能 可能
Serializable 不可能 不可能 不可能 不可能

 

posted @ 2020-03-25 15:29  一杯水M  阅读(237)  评论(0编辑  收藏  举报