最近面试遇到过数据库中隔离级别的问题。那么隔离级别究竟是什么呢?
隔离级别用于事务,可以解决一些数据库并发问题,如脏读,不可重复读,与幻读(又叫虚读),覆盖更新,丢失更新。
脏读:当你访问查询数据的时候,你看到的数据是别的事务还没提交的数据,数据各种乱七八糟,简直脏的可以。
不可重复读:事务1查询数据之后,事务2更新了同数据,事务1再查的时候,发现数据居然变了。这在同一个事务拥有两次查询处理才会发现的问题,会有隐秘性。比如权限表里面有个权限等级,等级最高的话就只允许管理员访问。现在是8:00定时抢货的时间。事务1会将权限降到最低,让广大客户可以开始抢货。但是数据却出问题了,管理员需要进行维护,需要暂时限制表的访问,这个是事务2。然后阴差阳错的,事务1查询了一下权限,现在是准备开枪的状态,OK,我要更新成可开枪状态了。事务2同一时间进来了,它在事务准备更新为开枪状态前进行了更新,将状态更新成不可开枪。事务1之后马上又更新了状态为可开枪状态。结果,客户们使用着有问题的数据,而管理员看着不停变动的数据正在感叹数据库是不是正在被黑中。。。。这种就是不可重复读的一种特例,叫覆盖更新。
幻读:事务1在多次重复查询过程中查询到事务2提交的新增或者删除的数据。你查询工资,看到你现在的工资,然后去打本子的时候,刚好公司的奖金到了,你一打印出来,发现多了1分钱,你会怀疑自己是不是产生幻觉了。
PS:不可重复读针对更新,而幻读针对插入和删除。
丢失更新:撤销事务时,把之前另一个事务的更新数据覆盖了,导致数据丢失。比如事务1和事务2都更新A字段,事务1更新结束之后,事务2紧接着更新A字段,但是事务2出问题,要回滚。这时候回滚会直接回滚到事务1更新前的状态。
PS:然后说明一下,貌似这个丢失更新在所有的事务隔离级别中都是不会发生的。只是查询资料的时候发现了这个,拿出来说一下而已。如果有同志真的看到过丢失更新的情况的话,请在评论里指出,以免我这里误导了别人。
然后是隔离级别介绍,这是在网上抄下来的:
A.Serializable(串行化):一个事务在执行过程中完全看不到其他事务对数据库所做的更新(事务执行的时候不允许别的事务并发执行。事务串行化执行,事务只能一个接着一个地执行,而不能并发执行。)。
B.Repeatable Read(可重复读):一个事务在执行过程中可以看到其他事务已经提交的新插入的记录,但是不能看到其他其他事务对已有记录的更新。
C.Read Commited(读已提交数据):一个事务在执行过程中可以看到其他事务已经提交的新插入的记录,而且能看到其他事务已经提交的对已有记录的更新。
D.Read Uncommitted(读未提交数据):一个事务在执行过程中可以看到其他事务没有提交的新插入的记录,而且能看到其他事务没有提交的对已有记录的更新。
丢失更新 | 脏读 | 非重复读 | 覆盖更新 | 幻像读 | |
---|---|---|---|---|---|
未提交读 | N | Y | Y | Y | Y |
已提交读 | N | N | Y | Y | Y |
可重复读 | N | N | N | N | Y |
串行化 | N | N | N | N | N |
如何设置隔离级别:
可以使用 Transact-SQL 或通过数据库 API 来设置事务隔离级别。
Transact-SQL
Transact-SQL 脚本使用 SET TRANSACTION ISOLATION LEVEL 语句。
ADO
ADO 应用程序将 Connection 对象的 IsolationLevel 属性设置为 adXactReadUncommitted、adXactReadCommitted、adXactRepeatableRead 或 adXactReadSerializable。
ADO.NET
使用 System.Data.SqlClient 托管命名空间的 ADO.NET 应用程序可以调用 SqlConnection.BeginTransaction 方法并将 IsolationLevel 选项设置为 Unspecified、Chaos、ReadUncommitted、ReadCommitted、RepeatableRead、Serializable 或 Snapshot。
OLE DB
开始事务时,使用 OLE DB 的应用程序调用 ITransactionLocal::StartTransaction,其中 isoLevel 设置为 ISOLATIONLEVEL_READUNCOMMITTED、ISOLATIONLEVEL_READCOMMITTED、ISOLATIONLEVEL_REPEATABLEREAD、ISOLATIONLEVEL_SNAPSHOT 或 ISOLATIONLEVEL_SERIALIZABLE。
在自动提交模式下指定事务隔离级别时,OLE DB 应用程序可以将 DBPROPSET_SESSION 属性 DBPROP_SESS_AUTOCOMMITISOLEVELS 设置为 DBPROPVAL_TI_CHAOS、DBPROPVAL_TI_READUNCOMMITTED、DBPROPVAL_TI_BROWSE、DBPROPVAL_TI_CURSORSTABILITY、DBPROPVAL_TI_READCOMMITTED、DBPROPVAL_TI_REPEATABLEREAD、DBPROPVAL_TI_SERIALIZABLE、DBPROPVAL_TI_ISOLATED 或 DBPROPVAL_TI_SNAPSHOT。
ODBC
ODBC 应用程序调用 SQLSetConnectAttr,其中 Attribute 设置为 SQL_ATTR_TXN_ISOLATION,ValuePtr 设置为 SQL_TXN_READ_UNCOMMITTED、SQL_TXN_READ_COMMITTED、SQL_TXN_REPEATABLE_READ 或 SQL_TXN_SERIALIZABLE。
对于快照事务,应用程序调用 SQLSetConnectAttr,其中 Attribute 设置为 SQL_COPT_SS_TXN_ISOLATION,ValuePtr 设置为 SQL_TXN_SS_SNAPSHOT。可以使用 SQL_COPT_SS_TXN_ISOLATION 或 SQL_ATTR_TXN_ISOLATION 检索快照事务。
注意!隔离级别虽然越高对数据越安全,但是却会导致并发效率的下降,严重还会导致死锁。所以隔离级别的设置要小心为上。