C#事务
看了很多关于事务的概念,还是觉得维基百科上说的最好:
数据库事务(简称:事务)是数据库管理系统执行过程中的一个逻辑单位,由一个有限的数据库操作序列构成。
一个数据库事务通常包含了一个序列的对数据库的读/写操作。它的存在包含有以下两个目的:
- 为数据库操作序列提供了一个从失败中恢复到正常状态的方法,同时提供了数据库即使在异常状态下仍能保持一致性的方法。
- 当多个应用程序在并发访问数据库时,可以在这些应用程序之间提供一个隔离方法,以防止彼此的操作互相干扰
从以上可以看出,事务主要的作用有两个:失败回滚和并发访问。事务处理技术主要包括数据库恢复技术和并发控制技术。
- 在sql中
事务的开始和结束可以有用户显示定义,若用户未定义,则由DBMS按缺省规定自动划分事务。在批量修改数据库时,建议显示定义事务,这样发生错误可以将恢复至未修改之前的状态。
SQL定义事务的语句:
-BEGIN TRANSACTION 事务开始
-COMMIT 提交事务,即将事务中所有对数据库的操作更新至磁盘的物理数据库中
-ROLLBACK 事务回滚,事务运行中发生故障,需要撤销已完成的所有操作,回到原始状态
**事务的四特性,简称ACID:
-原子性和一致性:事务操作要么都做,要么都不做;结果要么都成功。
-隔离性:一个事务的执行不可以被其他事务干扰。
-持续性:也称永久性,即事务一旦提交,对数据库的改变就是永久的。
事务ACID可能遭受破坏的因素:
-多个事务并行运行,不同事务的操作交叉执行;
-事务在运行过程中被强行停止。
这些就是恢复机制和并发控制机制的责任。
- 使用OdbcTransaction(OleDbTransaction、SqlTransaction、DbTransaction...)
using (OdbcConnection connection = new OdbcConnection(connectionString)) { connection.Open(); OdbcCommand command = connection.CreateCommand(); //启动事务 OdbcTransaction transaction = connection.BeginTransaction(); //设定事务和连接对象 command.Connection = connection; command.Transaction = transaction; try { command.CommandText = "Insert into ..."; command.ExecuteNonQuery(); // 完成提交 transaction.Commit(); } catch (Exception ex) { //数据回滚 transaction.Rollback(); } }
在建立事务的时候,可以设置事务的锁定级别:(MSDN事务锁定参考)
OdbcTransaction transaction = connection.BeginTransaction(IsolationLevel.ReadCommitted);//IsolationLevel指定连接的锁定行为
所有级别(事务并发控制详细说明请参照《数据库系统概论》并发控制-章节),以下为整理的说明:
Chaos-对于更高隔离级别事务中未进行的修改,不可以重写。
ReadCommitted-提交读。共享锁可以避免脏读,但在事务结束之前如果数据被修改的话,会导致不可重复读或幻影数据。由于不是范围锁,单次查询结束后就被释放,这时如果记录被修改,则可能造成不可重复读;若插入新记录,则可能造成幻影读;
ReadUncommitted-未提交读。未提交读(READ UNCOMMITTED)是最低的隔离级别。允许脏读(dirty reads),事务可以看到其他事务“尚未提交”的修改。通过比低一级的隔离级别要求更多的限制,高一级的级别提供更强的隔离性。标准允许事务运行在更强的事务隔离级别上。(如在可重复读(REPEATABLE READS)隔离级别上执行提交读(READ COMMITTED)的事务是没有问题的)
RepeatableRead-可重复读。在可重复读(REPEATABLE READS)隔离级别中,基于锁机制并发控制的DBMS需要对选定对象的读锁(read locks)和写锁(write locks)一直保持到事务结束,但不要求“范围锁(range-locks)”,因此可能会发生“幻影读(phantom reads)”。
Serializable-可串行化(可序列化)。最高的隔离级别。直接对数据库进行加锁,阻止其他用户更新或插入数据,直到事务提交;
Snapshot-通过存储数据副本,达到数据读取不受其他修改影响的效果,减少阻塞。即使重新查询,另一事务所做的修改也不会对现在的事务造成影响。
Unspecified-正在使用与指定隔离级别不同的隔离级别,但是无法确定该级别。
下面是dll中的解释:
Unspecified | 正在使用与指定隔离级别不同的隔离级别,但是无法确定该级别。 |
Chaos | 无法覆盖隔离级别更高的事务中的挂起的更改。 |
ReadUncommitted | 可以进行脏读,意思是说,不发布共享锁,也不接受独占锁。 |
ReadCommitted | 在正在读取数据时保持共享锁,以避免脏读,但是在事务结束之前可以更改数据,从而导致不可重复的读取或幻像数据。 |
RepeatableRead | 在查询中使用的所有数据上放置锁,以防止其他用户更新这些数据。防止不可重复的读取,但是仍可以有幻像行。 |
Serializable | 在 System.Data.DataSet 上放置范围锁,以防止在事务完成之前由其他用户更新行或向数据集中插入行。 |
Snapshot | 通过在一个应用程序正在修改数据时存储另一个应用程序可以读取的相同数据版本来减少阻止。表示您无法从一个事务中看到在其他事务中进行的更改,即便重新查询也是如此。 |
- 使用TransactionScope
using (System.Transactions.TransactionScope scope = new System.Transactions.TransactionScope(System.Transactions.TransactionScopeOption.Required)) { using (OdbcConnection connection = new OdbcConnection(connectionString)) { connection.Open(); OdbcCommand command = connection.CreateCommand(); command.Connection = connection; command.CommandText = "Insert into ..."; command.ExecuteNonQuery(); //... //若前面发生错误而为执行Complete,事务将自动回滚 scope.Complete(); } }