數據一致性在工作中顯得非常重要,有時候我們庫中出現臟數據導致程序報錯,但是又很難發現這樣的錯誤,所以為了數據的完整性建議在程序中加入事物。
什么是事物:我們都有團隊合作吧,比喻團隊有3個人,a負責設計,b負責前端,c負責后臺,那么他們三個就是一個整體,哪一個人那里出了問題就要被打回。
第一步:我們開始定義個一個接口
[ServiceContract] public interface IUserInfo { [OperationContract] int AddInfo(); }
第二步當然是實現接口了。這個AddInfo需要添加用戶和文章
//使用隱式事務,并把TransactionFlowOption設置為Allowed打開事務流 [OperationBehavior(TransactionAutoComplete = true, TransactionScopeRequired = true)] [TransactionFlow(TransactionFlowOption.Allowed)] public int AddInfo() { using (TransactionScope transcope = new TransactionScope(TransactionScopeOption.RequiresNew)) { try { if (AddUser()) { if (!AddArticle()) { Transaction.Current.Rollback(); return 0; } else { transcope.Complete(); return 1; } } else { Transaction.Current.Rollback(); } } catch (Exception ep) { Transaction.Current.Rollback(); return 0; } return 0; } } /// <summary> /// 添加用戶 /// </summary> /// <returns></returns> public bool AddUser() { try { string guid = System.Guid.NewGuid().ToString(); string userName = "zhangsan"; string realName = "張三"; DateTime dateTime = DateTime.Now; string sql = "insert into MyUser(Id,UserName,RealName,SysDate)values(@Id,@UserName,@RealName,@SysDate)"; SqlParameter[] param = new SqlParameter[] { new SqlParameter("@Id",guid), new SqlParameter("@UserName",userName), new SqlParameter("@RealName",realName), new SqlParameter("@SysDate",dateTime) }; string Conn = ConfigurationManager.ConnectionStrings["dbLink"].ConnectionString; return SqlHelper.ExecuteNonQuery(Conn, CommandType.Text, sql, param) > 0; } catch (Exception) { return false; } } /// <summary> /// 文獻信息 /// </summary> /// <returns></returns> public bool AddArticle() { try { string guid = System.Guid.NewGuid().ToString(); string Title = null; string Content = "我在測試"; DateTime dateTime = DateTime.Now; string sql = "insert into Info(Id,Title,Content,SysDate)values(@Id,@Title,@Content,@SysDate)"; SqlParameter[] param = new SqlParameter[] { new SqlParameter("@Id",guid), new SqlParameter("@Title",Title), new SqlParameter("@Content",Content), new SqlParameter("@SysDate",dateTime) }; string Conn = ConfigurationManager.ConnectionStrings["dbLink"].ConnectionString; return SqlHelper.ExecuteNonQuery(Conn, CommandType.Text, sql, param) > 0; } catch (Exception ep) { return false; } }
注釋1:TransactionAutoComplete=true的時候表示沒有異常的時候自動完成事物范圍
第三步:顯得方法AddArticle()添加不進去庫,我在數據庫中不準為null,看下單元測試
public void AddInfoTest() { UserInfoClient.UserInfoClient userInfo=new UserInfoClient.UserInfoClient(); int result = userInfo.AddInfo(); Assert.AreEqual(0, result); }
效果:
第四步:說明事物我們實現了,但是很多時候我們都是和別的部門或者調用別人的wcf所以需要如果其中任何一方數據出現錯誤就要需要回滾現在我們開始寫第二個wcf接口
接口同上,現在看下方法
public class User : IUser { //使用隱式事務,并把TransactionFlowOption設置為Allowed打開事務流 [OperationBehavior(TransactionAutoComplete = true, TransactionScopeRequired = true)] [TransactionFlow(TransactionFlowOption.Allowed)] public int AddInfo() { Client.UserInfoClient userInfoClient = new UserInfoClient(); using (TransactionScope transcope = new TransactionScope(TransactionScopeOption.RequiresNew)) { try { if (!AddUser()) { Transaction.Current.Rollback(); return 0; } if (!AddArticle()) { Transaction.Current.Rollback(); return 0; } if (userInfoClient.AddInfo() != 1) { Transaction.Current.Rollback(); return 0; } else { transcope.Complete(); return 1; } } catch (Exception) { Transaction.Current.Rollback(); userInfoClient.Close(); return 0; } }
其中調用的AddUser()和AddArticle()同上面一樣(這里僅僅為了測試)userInfoClient.AddInfo()這是上一個wcf部署以后的方法
現在我們先看都成功都添加成功(此時成功添加數據庫)
[Test] public void AddInfoTwoTest() { Client.UserClient userClient =new UserClient(); Assert.AreEqual(1, userClient.AddInfo()); }
效果:
再看第一個wcf添加失敗第二個回滾的效果
/// <summary> /// 測試回滾 /// </summary> [Test] public void AddInfoFailTest() { Client.UserClient userClient = new UserClient(); Assert.AreEqual(0, userClient.AddInfo()); }
總結:在我們一條數據插入多個表中,或者數據之間有很強的聯系,我們可以考慮用事物老保證數據一致性,但是一定注意記得事物要提交,否則可能會出席死鎖。大家可以動手試試
源碼下載
新聞熱點
疑難解答