zoukankan      html  css  js  c++  java
  • SqlTransaction——事务详解

    事务处理基本原理      
          事务是将一系列操作作为一个单元执行,要么成功,要么失败,回滚到最初状态。在事务处理术语中,事务要么提交,要么中止。若要提交事务,所有参与者都必须保证对数据的任何更改是永久的。不论系统崩溃或是发生其他无法预料的事件,更改都必须是持久的。只要有一个参与者无法做出此保证,整个事务就会失败。事务范围内的所有数据更改将回滚到特定设置点。  

               
          事务将多个操作紧密联系到一起,这样就能保证有联系的两种操作的一致性、以及数据的完整性。举个简单例子:公司的员工信息管理系统,现在要录入数据,员工信息系统假设只有部门、员工信息两张表,其中员工信息表中有标识部门的字段。在你录入信息的时候首先你得录入部门信息,再录入员工信息。具体实现代码: 

    复制代码
            private static void ExecuteSqlTransaction(string connectionString)
            
    {
                
    using (SqlConnection connection = new SqlConnection(connectionString))
                
    {
                    connection.Open();
                    SqlCommand command 
    = connection.CreateCommand();
                    SqlTransaction transaction;  
                    transaction 
    = connection.BeginTransaction("SampleTransaction");
                    command.Connection 
    = connection;
                    command.Transaction 
    = transaction;
                    
    try
                    
    {
                        command.CommandText 
    =
                            
    "Insert into Department (ID, Name) VALUES (1, '工程部')";
                        command.ExecuteNonQuery();
                        command.CommandText 
    =
                            
    "Insert into Users(ID, Name,DepartmentID) VALUES (1, 'xyz',1)";
                        command.ExecuteNonQuery();
                        transaction.Commit();
                    }

                    
    catch (Exception ex)
                    
    {
                       transaction.Rollback();
                    }

                }

            }
    复制代码

     事务的误区

          事务有很多优点【原理中已经阐述】,由于它的要求比较高,所以注意事务不能滥用,如果用不好就会造成很大的麻烦。

          事务有一个开头和一个结尾,它们指定了事务的边界,事务在其边界之内可以跨越进程和计算机。事务边界内的所有资源都参与同一个事务。要维护事务边界内资源间的一致性,事务必须具备 ACID 属性,即原子性、一致性、隔离性和持续性。这是MSDN的权威说明。

          也许针对一般的小逻辑、小数据事务应用非常的高效、可靠。但如果数据量很大,在单个事务中集合的操作繁多而且复杂,事务的致命伤就会暴露出来。一个事务进行时,必须保证边界资源的原子性、一致性、隔离性和持续性。

          我曾经设计了一个测试用例,测试事务在执行时对资源的利用情况。测试结果很令人惊讶:在事务执行时,独占事务涉及到的数据表,造成其它操作词表的功能,因等待时间过长,而暴跳“获得数据连接超时”的警告。

          具体的测试用例:       


        public class TestTransaction
        
    {
            
    /// <summary>
            
    /// 插入新用户
            
    /// </summary>
            
    /// <param name="tran"></param>
            
    /// <returns></returns>

            private static bool InsertIntoUser(SqlTransaction tran)
            
    {
                
    string strSql = @"INSERT INTO [T_User]
                                               ([F_Name])
                                         VALUES
                                               (@F_Name)
    ";
                SqlParameter[] Params 
    =new SqlParameter("@F_Name", SqlDbType.VarChar, 20) };
                Params[
    0].Value="Test1001";
                
    int count= SqlHelper.ExecuteNonQuery(strSql,Params,tran);
                
    if (count > 0)
                
    {
                    
    return true;
                }

                
    else
                
    {
                    
    return false;
                }

            }

            
    /// <summary>
            
    /// 插入title
            
    /// </summary>
            
    /// <returns></returns>

            private static bool InsertIntoTitle(SqlTransaction tran)
            
    {
                
    string strSql = @"INSERT INTO [T_User_Title]
                                           ([F_TitleName],
                                            [F_Remark],
                                            [F_Status],
                                            [F_EditTime])
                                     VALUES
                                           (@F_TitleName,
                                            @F_Remark,
                                            @F_Status,
                                            @F_EditTime)
    ";
                SqlParameter[] Params 
    = 
                    
    new SqlParameter("@F_TitleName",SqlDbType.VarChar, 50), 
                    
    new SqlParameter("@F_Remark", SqlDbType.VarChar, 200), 
                    
    new SqlParameter("@F_Status", SqlDbType.Int, 1), 
                    
    new SqlParameter("@F_EditTime", SqlDbType.DateTime, 8) }
    ;
                Params[
    0].Value = "TestUser1001";
                Params[
    1].Value = "这是第一次测试";
                Params[
    2].Value = 1;
                Params[
    3].Value = DateTime.Now;
                
    int count = SqlHelper.ExecuteNonQuery(strSql,Params,tran);
                
    if (count > 0)
                
    {
                    
    return true;
                }

                
    else
                
    {
                    
    return false;
                }

            }

            
    /// <summary>
            
    /// 检测Transaction
            
    /// </summary>
            
    /// <returns></returns>

            public static bool InsertWithTran()
            
    {
                
    bool success = false;
                
    string connectionString=System.Configuration.ConfigurationSettings.AppSettings["SqlConStr"].ToString();
                
    using (SqlConnection con = new SqlConnection(connectionString))
                
    {
                    con.Open();
                    SqlTransaction tran 
    = con.BeginTransaction();
                    
    try
                    
    {  
                        
    if (tran == null)
                        
    {
                            
    throw new Exception("Transaction is null");
                        }

                        
    if (InsertIntoUser(tran))
                        
    {
                            
    if (InsertIntoTitle(tran))
                            
    {
                                tran.Commit();
                                success 
    = true;
                            }

                        }

                    }

                    
    catch
                    
    {
                        tran.Rollback();
                        success 
    = false;
                    }

                    
    finally
                    
    {
                        tran.Dispose();
                        con.Close();
                    }

                }

                
    return success;

            }

        }

           


        protected void Button1_Click(object sender, EventArgs e)
        
    {
            
    bool success = TestTransaction.InsertWithTran();
            
    if (success)
            
    {
                Bmc.CLUtility.ShowMessage(
    this.Page, "插入成功");            
            }

            
    else
            
    {
                Bmc.CLUtility.ShowMessage(
    this.Page, "插入失败");
            }

        }

     


    <1>运行程序
    <2>将运行的地址,发给在同一个网段的同事,通过适当修改也能够看到你运行的程序
    <3>两人都点击按钮,并查询数据库,看事务是否正确执行
    <4>在事务中间创建断点,主机点击按钮,并在断点处中断执行一段时间
    <5>然后你们连接到数据库,分别查询表的数据,发现不能执行查询操作。
    <6>在同事机器点击按钮,查询windows日志,发现了一些警告
    这就证明了,事务在执行过程中,独占资源
  • 相关阅读:
    广域网(ppp协议、HDLC协议)
    0120. Triangle (M)
    0589. N-ary Tree Preorder Traversal (E)
    0377. Combination Sum IV (M)
    1074. Number of Submatrices That Sum to Target (H)
    1209. Remove All Adjacent Duplicates in String II (M)
    0509. Fibonacci Number (E)
    0086. Partition List (M)
    0667. Beautiful Arrangement II (M)
    1302. Deepest Leaves Sum (M)
  • 原文地址:https://www.cnblogs.com/jazzka702/p/2638099.html
Copyright © 2011-2022 走看看