事务的属性、隔离级别及隔离级别设置方法介绍
原子性(Atomicity):指事务如原子一样,是一个整体,不可再分,要么完成全部工作,要么什么工作也不做。
一致性(Consiitency):指事务能保证数据的一致性,即使当事务在处理的过程中发生了任何问题都能保证数据是正确的。
隔离性(Isolation):指事务和事务间是相互隔离的,不能相互访问。
持续性(Durability):指系统如果发生故障,日志文件能使程序完成没有完成的工作,保证计算机中数据与现实相一致。在处理显示中的数据时,如果需求与事务相同,那么事务可是工作变得简单而有效。
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; using System.Data.SqlClient; namespace 事物 { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { SqlConnection conn = new SqlConnection(); string strConn = @"Data Source=DESKTOP-UJ5IEQK\THIRTEEN;Initial Catalog=myDB;Integrated Security=true"; conn.ConnectionString = strConn; SqlCommand cmd = new SqlCommand(); cmd.Connection = conn; cmd.Parameters.AddWithValue("@sno", textBox1.Text); //插入数据参数 cmd.Parameters.AddWithValue("@cno", textBox2.Text); cmd.Parameters.AddWithValue("@grade", textBox3.Text); conn.Open(); SqlTransaction trans = conn.BeginTransaction(); //下面的内容应在conn.Open()之后 cmd.Transaction = trans; //给cmd.Transaction赋值,关联起来 try { cmd.CommandText = "update course set snumber = snumber + 1 where cno=@cno"; cmd.ExecuteNonQuery(); cmd.CommandText = "insert into sc values(@sno, @cno, @grade)"; cmd.ExecuteNonQuery(); trans.Commit(); //提交事物 MessageBox.Show("添加成功!"); } catch (Exception ex) { trans.Rollback(); //回滚事物 MessageBox.Show(ex.Message); } //用数据库中的事物 //cmd.CommandText = "sw"; //cmd.CommandType = CommandType.StoredProcedure; //cmd.Parameters.AddWithValue("@sno",textBox1.Text); //cmd.Parameters.AddWithValue("@cno", textBox2.Text); //cmd.Parameters.AddWithValue("@grade", textBox3.Text); //conn.Open(); //try //{ // int i = cmd.ExecuteNonQuery(); //} //catch (Exception ex) //{ // MessageBox.Show(ex.Message); //} //finally { // conn.Close(); //} } } } //sw存储过程的内容 //CREATE PROCEDURE[dbo].[sw] //@sno varchar(10), //@cno varchar(10), //@grade tinyint //AS //BEGIN // declare @err int // set @err=0 // begin tran --表示事物的开始,从此处开始后的语句到事务的提交处都是事务的一部分。这一部分满足原子性 // update course // set snumber = snumber + 1 // where cno = @cno // SET @err = @err +@@ERROR // insert into sc // values(@sno, @cno, @grade) // set @err = @err +@@ERROR // if @err=0 // commit tran --表示事物的提交,从Begin Tran到Commit Tran中的语句即为事务的部分 // else // rollback tran --事务的回滚(撤销)。将事务回滚到开始或制定的地方 //END
隔离级别指明当有多个 事务访问同一数据是所引起的并非性问题的解决方案,数据库系统根据所选择的隔离级别来决定发生并发性问题时应如何处理。
当有几个事务在访问同一数据时,可能发生的并发性错误的情况有:
1. 脏读 :脏读就是指当一个事务正在访问数据,并且对数据进行了修改,而这种修改还没有提交到数据库中,这时,另外一个事务也访问这个数据,然后使用了这个数据。
e.g.
1.Mary的原工资为1000, 财务人员将Mary的工资改为了8000(但未提交事务)
2.Mary读取自己的工资 ,发现自己的工资变为了8000,欢天喜地!
3.而财务发现操作有误,回滚了事务,Mary的工资又变为了1000
像这样,Mary记取的工资数8000是一个脏数据。
2. 不可重复读 :是指在一个事务内,多次读同一数据。在这个事务还没有结束时,另外一个事务也访问该同一数据。那么,在第一个事务中的两次读数据之间,由于第二个事务的修改,那么第一个事务两次读到的的数据可能是不一样的。这样在一个事务内两次读到的数据是不一样的,因此称为是不可重复读。
e.g.
1.在事务1中,Mary 读取了自己的工资为1000,操作并没有完成
2.在事务2中,这时财务人员修改了Mary的工资为2000,并提交了事务.
3.在事务1中,Mary 再次读取自己的工资时,工资变为了2000
解决办法:如果只有在修改事务完全提交之后才可以读取数据,则可以避免该问题。
3. 幻读 : 是指当事务不是独立执行时发生的一种现象,例如第一个事务对一个表中的数据进行了修改,这种修改涉及到表中的全部数据行。同时,第二个事务也修改这个表中的数据,这种修改是向表中插入一行新数据。那么,以后就会发生操作第一个事务的用户发现表中还有没有修改的数据行,就好象发生了幻觉一样。
e.g.
目前工资为1000的员工有10人。
1.事务1,读取所有工资为1000的员工。
2.这时事务2向employee表插入了一条员工记录,工资也为1000
3.事务1再次读取所有工资为1000的员工 共读取到了11条记录,
解决办法:如果在操作事务完成数据处理之前,任何其他事务都不可以添加新数据,则可避免该问题
SqlTransaction trans = conn.BeginTransaction(IsolationLevel.ReadCommitted);//声明时设置
//IsolationLevel的值默认是ReadCommitted
隔离级别 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
未提交读(ReadUncommitted) | 是 | 是 | 是 |
提交读(ReadCommitted) | 否 | 是 | 是 |
可重复读(RepeatableRead) | 否 | 否 | 是 |
可串行读(Serializable) | 否 | 否 | 否 |
若数据库不允许脏读,则即便IsolationLevel的值为ReadUncommitted也不可脏读。 <