mysql事务隔离级别为Read uncommitted产生脏读原因

Read uncommitted是mysql innodb引擎的最低事务隔离级别。他并不能保证并发情况下的数据的安全性。

例如使用jdbc事务模仿Read uncommitted隔离级别:

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class MainController {

    public void main(){
            Connection conn=null;
            try{
        Class.forName("com.mysql.jdbc.Driver");
//实例化一个数据库连接                 conn=DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/merchandise_center", "root", "123456");
            //关闭sql执行的自动提交,jdbc默认是执行一条sql时默认就会操作数据库的数据了
            conn.setAutoCommit(false);
//设置事务的隔离级别为READ_UNCOMMITTED    conn.setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED);
            //更新语句
            PreparedStatement ps=conn.prepareStatement("update t_finance_service set finance_service_name = \"工商银行1\"");
             //查询语句
            PreparedStatement ps1=conn.prepareStatement("select * from t_finance_service where finance_service_id=\"1\"");
            ps.execute();
            ResultSet result= ps1.executeQuery();
            //事务提交
            conn.commit();
            while(result.next()){
                System.out.println(result.getString(2));
            }
        }catch(Exception e){
            e.printStackTrace();
            try {
                //报错回滚
                conn.rollback();
            } catch (SQLException e1) {
            }
        }
    }
    }

脏读就可能在conn.commit()发生。因为conn.commit()提交后会执行上述两条sql语句,一条更新一条查询。如果执行更新语句后,另一个用户此时执行了查询操作获取到了这个并未提交的数据之后,事务继续执行查询语句时抛出异常然后事务回滚,但是那个用户已经查询了错误的数据进行业务处理了,故会导致脏读。
mysql事务隔离级别为Read uncommitted产生脏读原因_第1张图片

但是这里有个问题,事务未提交之前数据库的数据是没有变化的,即1)执行时数据库的数据是没有改变的,但是2)是怎么查到1)执行完毕的值呢?这就要知道sql的执行过程以及事务原理了。

sql执行过程:
首先sql命令交由数据库引擎在共享SQL区找到是否存在该条sql的执行计划,若没有找到则首先编译该条sql,然后把该条sql放入共享SQL区,若找到直接执行该条sql计划,执行时首先是从数据高速缓冲区查找改条记录,如果有改条记录则直接在数据高速缓冲区执行sql指令操作数据,如果是查询语句则直接返回,如果是改、删则把数据持久化到数据库硬盘中。如果没有数据在高速缓存区,则首先从表中读取数据在高速缓存区再操作。

事务原理夹杂sql过程进行讲解:
首先数据库是使用了两个日志来保证事务的隔离性与一致性原则,redo、undo这两个日志文件,redo永远记录这数据的最新值即可以看成数据高速缓存区,当执行一个事务时,事务中可能有多个sql,执行一条sql时redo记录执行完sql的最新值,然后undo一直记录这数据的原始值,所以其他用户访问时可以读取redo里的值,当事务回滚是把undo的值持久化数据高速缓存区中。然后事务提交则把redo的值持久化到表中了,这就是导致脏读的原理。

你可能感兴趣的:(高并发,事务)