zoukankan      html  css  js  c++  java
  • [转载]C#中使用ADO.NET连接SQL Server数据库,自动增长字段用作主键,处理事务时的基本方法

    问题描述:

    假设在数据库中存在以下两张数据表:

    User表,存放用户的基本信息,基本结构如下所示:

      类型 说明
    ID_User int 自动增长字段,用作该表的主键
    UserName varchar  

    UserDepart表,存放用户所拥有的部门(我们假设一个用户拥有多个部门,虽然听起来有点别扭,此处仅作示例,可以理解为一个用户拥有多个职位等等),该表的基本结构如下所示:

      类型 说明
    ID_UserDepart int 自动增长字段,用作该表的主键
    ID_User int 用户编号
    ID_Depart int 部门编号

    向数据库中插入一条用户信息的时候,为了保证数据的一致性,必须使用事务的方式“同时”操作User表和UserDepart表。先将用户姓名写入User表中,再将其所拥有的部门写入UserDepart表中,使用事务机制保证这两步操作要么同时成功,要么同时失败。问题就出在:第一步操作完成后,我们并不知道该向第二步操作写入的ID_User的值是多少,因为这个值是SQL Server自动生成的。

    解决思路:

    可以借助 SELECT IDENT_CURRENT('User') AS ‘NewInsertID’ 来查询最近一次插入User表的数据的自动编号的值。

    程序实现:

     1 public struct Chaos_TranSQLCmd
     2         {
     3             /// <summary>
     4             /// 一条SQL语句
     5             /// </summary>
     6             public string strSQL;
     7 
     8             /// <summary>
     9             /// 标记该条SQL语句是否需要连接ID_User
    10             /// </summary>
    11             public bool bNeedID;
    12         }
    13 
    14 
    15         public void Chaos_ExecuteSqlTran(List<Chaos_TranSQLCmd> listTranSQLCmd,string strInsertID_SQL)
    16         {
    17             using (SqlConnection ChaosSqlConn = new SqlConnection(strSqlConnString))
    18             {
    19                 SqlCommand ChaosSqlCmd = new SqlCommand();
    20                 ChaosSqlCmd.Connection = ChaosSqlConn;
    21                 ChaosSqlConn.Open();
    22                 SqlTransaction ChaosSqlTran = ChaosSqlConn.BeginTransaction();
    23                 ChaosSqlCmd.Transaction = ChaosSqlTran;
    24 
    25                 try
    26                 {
    27                     string mID_User = "";
    28 
    29                     //先将数据插入User
    30                     ChaosSqlCmd.CommandText = strInsertID_SQL;
    31                     ChaosSqlCmd.ExecuteNonQuery();
    32 
    33                     //再获取ID_User
    34                     DataSet ds = this.ExecAdapter("select IDENT_CURRENT('PT_User') as 'ID'", "T");
    35                     DataTable dt = ds.Tables["T"];
    36                     if (dt.Rows.Count>0)
    37                     {
    38                         mID_User = dt.Rows[0]["ID"].ToString();    
    39                     }
    40                     
    41                     for (int i = 0; i < listTranSQLCmd.Count; i++)
    42                     {
    43                         //如果队列中的语句需要连接ID,则处理SQL语句后再执行
    44                         string strSQL = "";
    45                         if (listTranSQLCmd[i].bNeedID==true)
    46                         {
    47                             strSQL = string.Format(listTranSQLCmd[i].strSQL, mID_User);
    48                         }
    49                         else
    50                         {
    51                             strSQL = listTranSQLCmd[i].strSQL;
    52                         }
    53 
    54                         ChaosSqlCmd.CommandText = strSQL;
    55                         ChaosSqlCmd.ExecuteNonQuery();
    56                     }
    57 
    58                     //全部成功执行则提交
    59                     ChaosSqlTran.Commit();
    60                 }
    61                 catch (System.Data.SqlClient.SqlException Ex)
    62                 {
    63                     //发生问题则回滚
    64                     ChaosSqlTran.Rollback();
    65                     throw new Exception(Ex.Message);
    66                 }
    67             }
    68         }
    复制代码

    测试代码如下:

    复制代码
     1 static void Main(string[] args)
     2         {
     3             try
     4             {
     5                 List<DB_Operation.ChaosDbOprt.Chaos_TranSQLCmd> Chaos_SQLCmdList = new List<DB_Operation.ChaosDbOprt.Chaos_TranSQLCmd>();
     6 
     7                 //构造SQL语句向User表中写入数据
     8                 string strSQL = "insert into PT_User (UserName) values ('Lee')";
     9 
    10                 //构造SQL语句向UserDepart表写入数据
    11                 for (int i = 0; i < 10; i++)
    12                 {
    13                     DB_Operation.ChaosDbOprt.Chaos_TranSQLCmd nCmd = new DB_Operation.ChaosDbOprt.Chaos_TranSQLCmd();
    14                     if (i==6)
    15                     {
    16                         //构造错误SQL语句,使写入数据库的操作不能成功执行
    17                         nCmd.strSQL = "insert into PT_UserDepart (ID_User,ID_Depart) values ({0}," + "A String which can't be inserted as ID_Depart)";
    18                     }
    19                     else
    20                     {
    21                         //正常SQL语句
    22                         nCmd.strSQL = "insert into PT_UserDepart (ID_User,ID_Depart) values ({0}," + i.ToString() + ")";
    23                     }
    24                     nCmd.bNeedID = true;
    25                     Chaos_SQLCmdList.Add(nCmd);
    26                 }
    27 
    28                 DB_Operation.ChaosDbOprt CDO = new DB_Operation.ChaosDbOprt();
    29                 CDO.Chaos_ExecuteSqlTran(Chaos_SQLCmdList, strSQL);
    30 
    31                 Console.WriteLine("数据写入成功!");
    32                 Console.ReadLine();
    33             }
    34             catch (Exception ex)
    35             {
    36                 Console.WriteLine("Error:
    "+ex.Message);
    37                 Console.ReadLine();
    38             }            
    39         }
    复制代码

    规范化代码如下:

    复制代码
     1 #region 实现数据库事务的方法,实现以事务的方式将多条SQL语句同时写入数据库(其中某些语句依赖于第一条语句插入数据库后自动生成的ID)
     2 
     3         public struct Chaos_TranSQLCmd
     4         {
     5             /// <summary>
     6             /// 一条SQL语句,在需要添加ID的地方用"{0}"来代替
     7             /// 如:INSERT INTO PT_FeeItemDetails(ID_FeeItem,ID_ExamItem) VALUES ({0},005)等
     8             /// </summary>
     9             public string strSQL;
    10 
    11             /// <summary>
    12             /// 标记该条SQL语句是否需要连接ID
    13             /// </summary>
    14             public bool bNeedID;
    15         }
    16         /// <summary>
    17         /// 该函数用于实现以事务的方式将多条SQL语句同时写入数据库(其中某些语句依赖于第一条语句插入数据库后自动生成的ID)
    18         /// </summary>
    19         /// <param name="strInsertID_SQL">需要先插入数据库中以产生ID的SQL语句</param>
    20         /// <param name="strTableName">需要首先插入数据库中以产生ID的数据表的名称,如"PT_FeeItem"等</param>
    21         /// <param name="listTranSQLCmd">需要连接ID的SQL语句的列表</param>  
    22         public void Chaos_ExecuteSqlTran_InsertID(string strInsertID_SQL,string strTableName, List<Chaos_TranSQLCmd> listTranSQLCmd)
    23         {
    24             using (SqlConnection ChaosSqlConn = new SqlConnection(strSqlConnString))
    25             {
    26                 SqlCommand ChaosSqlCmd = new SqlCommand();
    27                 ChaosSqlCmd.Connection = ChaosSqlConn;
    28                 ChaosSqlConn.Open();
    29                 SqlTransaction ChaosSqlTran = ChaosSqlConn.BeginTransaction();
    30                 ChaosSqlCmd.Transaction = ChaosSqlTran;
    31 
    32                 try
    33                 {
    34                     string m_strID = "";
    35 
    36                     //先将数据插入User
    37                     ChaosSqlCmd.CommandText = strInsertID_SQL;
    38                     ChaosSqlCmd.ExecuteNonQuery();
    39 
    40                     string strSQL_Tmp = string.Format("SELECT IDENT_CURRENT('{0}') as 'ID'",strTableName);
    41                     //再获取ID
    42                     DataSet ds = this.ExecAdapter(strSQL_Tmp, "T");
    43                     DataTable dt = ds.Tables["T"];
    44                     if (dt.Rows.Count>0)
    45                     {
    46                         m_strID = dt.Rows[0]["ID"].ToString();
    47 
    48                         for (int i = 0; i < listTranSQLCmd.Count; i++)
    49                         {
    50                             //如果队列中的语句需要连接ID,则处理SQL语句后再执行
    51                             string strSQL = "";
    52                             if (listTranSQLCmd[i].bNeedID == true)
    53                             {
    54                                 strSQL = string.Format(listTranSQLCmd[i].strSQL, m_strID);
    55                             }
    56                             else
    57                             {
    58                                 strSQL = listTranSQLCmd[i].strSQL;
    59                             }
    60 
    61                             ChaosSqlCmd.CommandText = strSQL;
    62                             ChaosSqlCmd.ExecuteNonQuery();
    63                         }
    64                     }
    65                     else
    66                     {
    67                         //如果没有正确获取首先插入语句的ID,则回滚
    68                         ChaosSqlTran.Rollback();
    69                         throw new Exception("产生ID语句没有成功执行,后续语句无法继续执行,已回滚!
    ");
    70                     }                    
    71                     
    72 
    73                     //全部成功执行则提交
    74                     ChaosSqlTran.Commit();
    75                 }
    76                 catch (System.Data.SqlClient.SqlException Ex)
    77                 {
    78                     //发生问题则回滚
    79                     ChaosSqlTran.Rollback();
    80                     throw new Exception(Ex.Message);
    81                 }
    82             }
    83         }
    84         #endregion
  • 相关阅读:
    解释DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci
    MySQL性能优化
    MySQL中的binlog相关命令和恢复技巧
    保障MySQL安全的14个最佳方法
    MySQL忘记root密码的解决方案
    MySQL利用binlog来恢复数据库
    MySQL命令mysqldump参数大全
    MySQL REPLACE替换输出
    MySQL -A不预读数据库信息(use dbname 更快)
    MySQL 慢查询配置
  • 原文地址:https://www.cnblogs.com/joeymary/p/4758805.html
Copyright © 2011-2022 走看看