zoukankan      html  css  js  c++  java
  • 事务的困惑

    今天在研究petshop的PetShop.SQLProfileDAL.PetShopProfileProvider时有幸看到事务的处理,其实之前在消息队列的时候也有遇到过,

    但那时候忙着整理消息队列,故没怎么去想这个,现在再次遇到就一并记录下来吧,老规矩还是先看下SQLProfileDAL.PetShopProfileProvider

    里的代码吧:

    1 publicvoid SetAccountInfo(int uniqueID, AddressInfo addressInfo) {
    2 string sqlDelete ="DELETE FROM Account WHERE UniqueID = @UniqueID;";
    3 SqlParameter param =new SqlParameter("@UniqueID", SqlDbType.Int);
    4 param.Value = uniqueID;
    5
    6 string sqlInsert ="INSERT INTO Account (UniqueID, Email, FirstName, LastName, Address1, Address2, City, State, Zip, Country, Phone) VALUES (@UniqueID, @Email, @FirstName, @LastName, @Address1, @Address2, @City, @State, @Zip, @Country, @Phone);";
    7
    8 SqlParameter[] parms = {
    9 new SqlParameter("@UniqueID", SqlDbType.Int),
    10 new SqlParameter("@Email", SqlDbType.VarChar, 80),
    11 new SqlParameter("@FirstName", SqlDbType.VarChar, 80),
    12 new SqlParameter("@LastName", SqlDbType.VarChar, 80),
    13 new SqlParameter("@Address1", SqlDbType.VarChar, 80),
    14 new SqlParameter("@Address2", SqlDbType.VarChar, 80),
    15 new SqlParameter("@City", SqlDbType.VarChar, 80),
    16 new SqlParameter("@State", SqlDbType.VarChar, 80),
    17 new SqlParameter("@Zip", SqlDbType.VarChar, 80),
    18 new SqlParameter("@Country", SqlDbType.VarChar, 80),
    19 new SqlParameter("@Phone", SqlDbType.VarChar, 80)};
    20
    21 parms[0].Value = uniqueID;
    22 parms[1].Value = addressInfo.Email;
    23 parms[2].Value = addressInfo.FirstName;
    24 parms[3].Value = addressInfo.LastName;
    25 parms[4].Value = addressInfo.Address1;
    26 parms[5].Value = addressInfo.Address2;
    27 parms[6].Value = addressInfo.City;
    28 parms[7].Value = addressInfo.State;
    29 parms[8].Value = addressInfo.Zip;
    30 parms[9].Value = addressInfo.Country;
    31 parms[10].Value = addressInfo.Phone;
    32
    33 SqlConnection conn =new SqlConnection(SqlHelper.ConnectionStringProfile);
    34 conn.Open();
    35 SqlTransaction trans = conn.BeginTransaction(IsolationLevel.ReadCommitted);
    36
    37 try {
    38 SqlHelper.ExecuteNonQuery(trans, CommandType.Text, sqlDelete, param);
    39 SqlHelper.ExecuteNonQuery(trans, CommandType.Text, sqlInsert, parms);
    40 trans.Commit();
    41 }
    42 catch(Exception e) {
    43 trans.Rollback();
    44 thrownew ApplicationException(e.Message);
    45 }
    46 finally {
    47 conn.Close();
    48 }
    49 }

    其实这是一个Delete和Insert的操作,但都是插入到Account表,但这两个对数据库的操作应该都算是w(修改)操作吧,

    我在MSDN中查了IsolationLevel这个枚举,ReadCommitted的解释是:在正在读取数据时保持共享锁,以避免脏读,

    但是在事务结束之前可以更改数据,从而导致不可重复的读取或幻像数据。

    如果用ReadCommitted导致不可重复读的话,那么就是说,T1、T2在是并发执行的,但没有加锁,从而导致T1两次(或多次)

    读取的数据不一致。但,上面的解释又说避免了脏读,所以呢,如果T1发生错误回滚的话,T2读取的数据不会不一致。

    但是,用ReadCommitted读取数据时保持共享锁根本就不会发生脏读的,根据共享税的规定,其他事务也只能对数据进行读取不能

    修改,那么不能就该怎么导致不可重复读呢?困惑。

    刚刚上面用的的是Transations的显示事务开发的吧,在MSDN中开发者建议用隐示的开发模式,即TransactionScope,因为隐示开发的话

    事务由该基础结构自动管理。下面是OrderProcess中的一个事务:

    1 using (TransactionScope ts =new TransactionScope(TransactionScopeOption.Required, tsTimeout)) {
    2 // Receive the orders from the queue
    3 for (int j =0; j < batchSize; j++) {
    4
    5 try {
    6 //only receive more queued orders if there is enough time
    7 if ((elapsedTime + queueTimeout + transactionTimeout) < tsTimeout.TotalSeconds) {
    8 queueOrders.Add(order.ReceiveFromQueue(queueTimeout));//从BLL.Order.ReceiveFromQueue得到订单队列,并将其放入到ArrayList中
    9 }
    10 else {
    11 j = batchSize; // exit loop
    12 }
    13
    14 //update elapsed time
    15 elapsedTime =new TimeSpan(DateTime.Now.Ticks).TotalSeconds - datetimeStarting.TotalSeconds;
    16 }
    17 catch (TimeoutException) {
    18
    19 //exit loop because no more messages are waiting
    20 j = batchSize;
    21 }
    22 }
    23
    24 //process the queued orders
    25 for (int k =0; k < queueOrders.Count; k++) {
    26 order.Insert((OrderInfo)queueOrders[k]);//再调用BLL.Order.Insert方法吧得到的订单插入到Order和Invertory中
    27 processedItems++;
    28 totalOrdersProcessed++;
    29 }
    30
    31 //batch complete or MSMQ receive timed out
    32 ts.Complete();
    33 }

    在MSDN中有对TransactionScope进行详细的说明,这个类提供了三个构造函数,我们上面那段代码就用到了构造函数,

    其中TransactionScopeOption是一个枚举,Required是表示:该范围需要一个事务。如果已经存在环境事务,则使用该环境事务。否则,在进入范围之前创建新的事务。这是默认值。

    修改:我第一段代码的事务好像理解错了,SqkTransation事务从Begin到commit都算一个事务,很明显我上面理解成为两个事务了,根据事务的原子性和一致性,

    delete和insert操作是要么执行要么不执行的。

  • 相关阅读:
    Win32++ Home Page
    CEGUI Home Page
    迁移DirectX11到VS2015 Win10
    Oracle常用查看表结构命令
    PLSQL常用配置
    PLSQL DEVELOPER
    WeblogicException
    java.nio.Buffer
    spring batch
    vi
  • 原文地址:https://www.cnblogs.com/huaizuo/p/2105133.html
Copyright © 2011-2022 走看看