• 事务的处理


    事务:  逻辑上的一组操作,组成这组操作的各个单元,要么全部成功,要么全部失败。

    事务的特性:

      原子性:事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。

      一致性:必须是数据库从一个一致性状态变换到另一个一致性状态。

      隔离性:多个用户并发访问数据库时,数据库为每个用户开启的事务,不能被其他事务的操作干扰,多个并发事务之间要相互隔离。

      持久性:一个事务一旦被提交,他对数据库中的改变就是永久性的,接下来即时数据库发生故障也不会对齐又任何影响。

    start transaction  开启事务

    Rollback 回滚事务

    Commit 提交事务

    默认情况下,Connection会自动提交sql语句:

    Connection.setAutoCommit(false);

    start transaction;

    Connection.rollback();

    rollback;

    Connection.commit();

    commit;


    案例: 

    package bank;
    
    import static org.junit.Assert.*;
    
    import java.sql.Connection;
    import java.sql.PreparedStatement;
    import java.sql.SQLException;
    
    import org.junit.Test;
    
    import utils.JdbcUtils;
    
    public class TransactionTest {
    
        @Test
        public void test() throws Exception {
            Connection conn = JdbcUtils.getConnection();
            PreparedStatement pstmt1 = conn.prepareStatement("update bank set money = money - ? where id = ?");
            pstmt1.setFloat(1, 9800);
            pstmt1.setInt(2, 1);
            
            int n = pstmt1.executeUpdate();
            System.out.println("pstmt1="+n);
            //使得执行不成功
            System.out.println(10/0);
            
            PreparedStatement pstmt2 = conn.prepareStatement("update bank set money = money + ? where id = ?");
            pstmt2.setFloat(2, 9800);
            pstmt2.setInt(2, 2);
            
            n = pstmt2.executeUpdate();
            System.out.println("pstmt2="+n);
            
            
            
            JdbcUtils.release(null, pstmt1, conn);
            JdbcUtils.release(null, pstmt2, conn);
        }
        
        //采用事务来处理转账失败情况
        @Test
        public void testTransaction() throws Exception {
            Connection conn = JdbcUtils.getConnection();
            PreparedStatement pstmt1 = null;
            PreparedStatement pstmt2 = null;
            //事务需要在一个连接对象中执行
            //不允许自动提交
            conn.setAutoCommit(false);
            //抓异常
            try{
                
                pstmt1 = conn.prepareStatement("update bank set money = money - ? where id = ?");
                pstmt1.setFloat(1, 9800);
                pstmt1.setInt(2, 1);
                
                int n = pstmt1.executeUpdate();
                System.out.println("pstmt1="+n);
                //使得执行不成功
    //            System.out.println(10/0);
                
                pstmt2 = conn.prepareStatement("update bank set money = money + ? where id = ?");
                pstmt2.setFloat(1, 9800);
                pstmt2.setInt(2, 2);
                
                n = pstmt2.executeUpdate();
                System.out.println("pstmt2="+n);
                //手动提交
                conn.commit();
            }catch(Exception e){
                //让事务进行回滚
                conn.rollback();
                System.out.println("error");
            }
        
            JdbcUtils.release(null, pstmt1, conn);
            JdbcUtils.release(null, pstmt2, conn);
        }
    
    }

     事务的隔离性

    脏读:一个事务读取了另外一个事务未提交的数据。

    假设A向B转账100元,对应sql为:

    update account set money  = money - 100 where name = 'a';


    update account set money  = money + 100 where name = 'b';

    当第一条语句执行完之后,第二条还没有执行,如果此时B查询自己的账户,就会发现自己多了100元。如果A等B走后再回滚,B就会损失100元。

    不可重复读(针对一条记录的,同一条记录前后不一样)

    在一个事务内读取表中的某一行数据,多次读取结果不同。

    第二次查询时,转入100元,两次查询不一致。很多人认为这种情况是正常的,当然是以后边查询结果为准。可以考虑这样的情况,比如银行的程序要讲查询结果输出到电脑屏幕和写入文件中,结果在一个事务中,针对输出结果的目的地,进行两次查询不一致,导致屏幕和文件的结果不一致,工作人员也不知道以哪个为准了。

    和脏读的区别是,脏读是读取前一事务未提交的脏数据,不可重复读是重新读取了前一事务已提交的数据。

     虚读(幻读):同一张表前后不一样的记录数。

    数据库定义了四种隔离级别:

    Serializable: 可避免脏读,不可重复读,虚读情况的发生。

    Repeatable read: 可避免脏读,不可重复读情况的发生。

    Read committed:可避免脏读情况发生。

    Read uncommitted: 最低级别,以上情况均无法保证。

    查询当前事务隔离级别: select @@tx_isolation 

    设置事务隔离级别: set transaction isolation Repeatable read;

     数据库的锁

    共享锁:一个事务开启时,使用了共享锁,其他事务也可以设置共享锁,读数据没有问题。

    select * from student in share mode;

    排它锁:一个事务开启时,使用了排它锁,其他事务只能等待。update insert 等语句会自动加排它锁。

    select * from student for update;

    常用操作:

    start transaction;  + commit ; 开启结束一个事务

    set character_set_client=gbk;

    set character_set_results=gbk;

  • 相关阅读:
    python提供的网络接口API和Linux Socket API间的关系探究 liushu
    业务领域建模Domain Modeling liushu
    分析一套源代码的代码规范和风格并讨论如何改进优化代码 liushu
    案例分析:设计模式与代码的结构特性 liushu
    如何提高程序员的键盘使用效率 liushu
    网络相关的命令工具研究报告 liushu
    用例建模Use Case Modeling liushu
    WdatePicker日历控件使用方法
    添加Web服务引用,服务引用,WCF服务开发
    JS大总结
  • 原文地址:https://www.cnblogs.com/taiguyiba/p/6201959.html
Copyright © 2020-2023  润新知