事务的处理

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

事务的特性:

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

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

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

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

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;

原文地址:https://www.cnblogs.com/taiguyiba/p/6201959.html