码迷,mamicode.com
首页 > 数据库 > 详细

【持久层】数据库事务基础——事务的隔离级别

时间:2015-07-26 11:08:50      阅读:264      评论:0      收藏:0      [点我收藏+]

标签:数据库   事务   隔离级别   

内容导读:

    前三节数据库事务、并发带来的风险以及数据库锁都是为了铺垫事务的隔离性。

    事务的隔离性不是无缘无故就存在的,他的存在是为了解决某一类问题,带来某一些操作的便捷;解决的问题是指数据库并发操作中数据一致性保证,带来的便捷是指定义好隔离级别之后,数据库会为操作自动加锁(不同的隔离级别拥有不同的自动锁粒度),而不用每次操作都手动的加锁。

    写着写着觉得没什么可写的,本文已沦为简单的笔记····


一、数据库事务

    将一组数据库操作看作一个具备特殊数据库语义的执行单元,该执行单元具备ACID的事务属性。在数据库事务的ACID属性中,原子性、隔离性和持久性都是为了保证数据的一致性。ACID的数据库语义如下所示。

1. atomic(原子性)

    该执行单元中的所有操作,要么全部执行成功,要么全部不执行。

2. consistency(一致性)

    执行单元执行完成前后的状态是一致的。一个转账的例子加以说明。

    转账前状态:A账户1000块,B账户1000块,转账前的状态是A+B=2000块;

    执行单元操作:A向B转账200块;

    转账后状态:A账户800块,B账户1200块,转账后的状态是A+B=2000块;

    结论:转账前和转账后的状态一致,都是2000块;并没有发生状态不一致情况导致账户A、账户B或银行中任何一方受损或受益。

3. isolation(隔离性)

    隔离性描述的是数据库对待并发操作的态度,即在并发操作数据库的环境下,不同事务之间对彼此造成影响的程度。根据用户对数据一致性环境的需求,数据库支持不同的隔离级别。
    千万要注意,在数据库并发环境下讨论隔离性才有意义,本质上数据库的隔离级别就是自动事务的代名词。更多细节,下文详细讨论。

4. durability(持久性)

    持久性描述的是当事务成功提交之后,提交数据会被持久化到数据库中,即使数据库立即崩溃,也能够在重启的时候恢复。持久性基于操作日志,简单来说,就是记录数据库操作语句,一条数据库语句包含了数据库的操作和数据,因此只要日志不受损,即使数据库存储介质损坏,也能够通过日志恢复。


二、并发带来的风险

    并发操作数据库会导致一些风险,这些风险可以归类为三类读问题和两类更新问题。

1. 脏读

    一个事务中读到另一个事务未提交的update。如下图所示,事务A中读到了事务B中未提交的操作,从而导致出现数据不一致的状况。

技术分享

2. 不可重复度

    一个事务中读到另一个事务提交的update。和脏读的区别是,读到的update事务是否已被提交。

    读到另一个事务提交的update在大多数情况下无伤大雅,但是如果是在月底做报表的时候,这种情况就出问题了。你需要统计上一个月的数据,但是在统计过程中不断有update,即便你在准确的时间点开启了事务,但是统计的数据依然不准确。解决的办法是为数据库加锁,但是如果你觉得每次统计都重复相同的动作会很麻烦,可以设置隔离级别,让数据库为你自动加锁。

技术分享

3. 虚读

    一个事务中读到另一个事务提交的insert。和不可重复读的区别是,一个是读到提交的update,一个是读到提交的insert。

    借用不可重复读中月底报表的例子,读到提交的update,这意味着数据库中原来就存在该条记录,这是修改了字段;而读到insert,则意味着数据库中原来是不存在这条记录的。虽然在统计的sql中添加了where的时间条件,但是读到存在此前的记录和不存在的记录,显然事务之间的影响程度是不一样的。

技术分享

4. 第一类丢失更新

    一个事务的回滚覆盖了另一个事务提交的update。这类丢失更新对数据库造成的影响是很严重的,除非数据库不支持事务,否则无论哪一种隔离级别都必须防止该风险。

技术分享

5. 第二类丢失更新

    一个事务提交的update覆盖了另一个事务提交的update。

技术分享


三、数据库锁

    锁不外乎独占锁和共享锁,放在数据库环境中有行锁和表锁,再细粒度分下来,行共享锁、行独占锁、表共享锁、表独占锁、表共享行独占锁。数据库锁和程序中的锁作用相似,都是为了解决并发环境中的风险——安全性、活跃性和性能问题。

    实际上,数据库在并发环境中出现的问题都可以通过加锁来得到解决,本质上也是这么来干的,但是很多加锁操作都是相似的,没必要一直重复相同的动作,因此出现了事务的隔离级别。

    MySQL锁详解:点击打开链接


四、事务隔离级别

1. isolation的意义

    要解决数据库并发中出现的问题,和写java代码一样,需要通过锁来获取正确的执行时序,这样一来,每次执行操作前都要先执行sql中关于锁的语句,为了简便操作,于是通过设置数据库隔离级别,让数据库自动加锁。

2. isolation的详解

    ANSI/ISO SQL 92标准定义了4个等级的隔离级别,分别是READ_UNCOMMITED、READ_COMMITED、REPETABLE_READ、SERIALIZABLE,四个等级的隔离成都递增,允许的并发程度递减,其中mysql默认支持第三种隔离级别,oracle默认支持第二种隔离级别。

    关于隔离级别的一些简单操作。

mysql> SELECT @@tx_isolation;//查看当前事务的隔离级别
+-----------------+
| @@tx_isolation  |
+-----------------+
| REPEATABLE-READ |
+-----------------+
1 row in set

mysql> SET TRANSACTION ISOLATION LEVEL READ COMMITTED;//临时更改数据库隔离级别,仅对本次会话有效
Query OK, 0 rows affected

mysql> SELECT @@tx_isolation;//查看已经被更改的隔离级别
+----------------+
| @@tx_isolation |
+----------------+
| READ-COMMITTED |
+----------------+
1 row in set
    数据库隔离级别对并发问题的解决情况。

技术分享

五、JDBC对事务的支持

    JDBC编程中,所有和事务有关的操作都被封装到了connection对象中(by the way,connection的实现被封装成了虚引用保存在driver的ConcurrentHashMap中),源码节选及注释如下。

/**
* com.mysql.jdbc.ConnectionImpl:mysql对connection接口的实现类
*/
public interface java.sql.Connection  extends Wrapper, AutoCloseable {
	/**
     * A constant indicating that transactions are not supported.
	 * 没有事务情况的也不存在隔离级别
     */
    int TRANSACTION_NONE = 0;

    /**
     * A constant indicating that
     * dirty reads, non-repeatable reads and phantom reads can occur.
     * This level allows a row changed by one transaction to be read
     * by another transaction before any changes in that row have been
     * committed (a "dirty read").  If any of the changes are rolled back,
     * the second transaction will have retrieved an invalid row.
	 * 除了第一类丢失更新之外,三类读问题和第二类都是更新都会发生
     */
    int TRANSACTION_READ_UNCOMMITTED = 1;

    /**
     * A constant indicating that
     * dirty reads are prevented; non-repeatable reads and phantom
     * reads can occur.  This level only prohibits a transaction
     * from reading a row with uncommitted changes in it.
	 * 防止脏读和第一类丢失更新
     */
    int TRANSACTION_READ_COMMITTED   = 2;

    /**
     * A constant indicating that
     * dirty reads and non-repeatable reads are prevented; phantom
     * reads can occur.  This level prohibits a transaction from
     * reading a row with uncommitted changes in it, and it also
     * prohibits the situation where one transaction reads a row,
     * a second transaction alters the row, and the first transaction
     * rereads the row, getting different values the second time
     * (a "non-repeatable read").
	 * 防止脏读、不可重复读和第一类丢失更新、第二类丢失更新,不能防止虚读
     */
    int TRANSACTION_REPEATABLE_READ  = 4;

    /**
     * A constant indicating that
     * dirty reads, non-repeatable reads and phantom reads are prevented.
     * This level includes the prohibitions in
     * <code>TRANSACTION_REPEATABLE_READ</code> and further prohibits the
     * situation where one transaction reads all rows that satisfy
     * a <code>WHERE</code> condition, a second transaction inserts a row that
     * satisfies that <code>WHERE</code> condition, and the first transaction
     * rereads for the same condition, retrieving the additional
     * "phantom" row in the second read.
	 * 防止脏读、不可重复读、虚读,第一类、第二类丢失更新,此时数据库相当于串行处理事务,并发程度最低
     */
    int TRANSACTION_SERIALIZABLE     = 8;
	
	/** 
	* Are we in autoCommit mode? 
	* JDBC默认是自动提交事务,每次操作数据库都自动进行事务
	*/
	private boolean autoCommit = true;
	/**
	* 连接对象支持的事务操作:
	* 关于setAutoCommit,因为JDBC默认是自动提交事务,也就是执行一个SQL语句就会提交一次事务,因此如果要想控制事务的提交,设置autoCommit为false即可;
	* 这里设置autoCommit为false,并没有和数据库交互,实际上数据库的隔离级别设置的自动事务并不受影响,这句代码只影响JDBC
	*/
	void setAutoCommit(boolean autoCommit) throws SQLException;
	void commit() throws SQLException;
	void rollback() throws SQLException;
	void setTransactionIsolation(int level) throws SQLException;
	int getTransactionIsolation() throws SQLException;
	Savepoint setSavepoint() throws SQLException;
	Savepoint setSavepoint(String name) throws SQLException;
	void rollback(Savepoint savepoint) throws SQLException;
	
}


附注:

    写到最后已经不想写了,后面很多深入的东西略了,sorry

版权声明:本文为博主原创文章,未经博主允许不得转载。

【持久层】数据库事务基础——事务的隔离级别

标签:数据库   事务   隔离级别   

原文地址:http://blog.csdn.net/reliveit/article/details/46978113

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!