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

来源:互联网 发布:如何下载淘宝数据包 编辑:程序博客网 时间:2024/06/03 20:52

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语句,一条更新一条查询。如果执行更新语句后,另一个用户此时执行了查询操作获取到了这个并未提交的数据之后,事务继续执行查询语句时抛出异常然后事务回滚,但是那个用户已经查询了错误的数据进行业务处理了,故会导致脏读。
这里写图片描述

但是这里有个问题,事务未提交之前数据库的数据是没有变化的,即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的值持久化到表中了,这就是导致脏读的原理。

1 0
原创粉丝点击