TransactionScope事务问题.总是不能回滚

wangping_li 2009-02-25 11:53:46
下面是我底层类

public virtual D Update(D t)
{
D local2;
using (IDbConnection connection = this.getDbConnection())
{
if (connection.State != ConnectionState.Open)
{
connection.Open();
}
D local = this.Update(t, connection);

connection.Close();
local2 = local;
}
return local2;
}

private D Update(D d, IDbConnection conn)
{
this.OnUpdating(d);
d.Meta = this.Update<E>(conn, d.Meta);
d.setUnchange();
this.OnUpdated(d);
return d;
}

界面使用时:


TransactionOptions options = new TransactionOptions();
options.IsolationLevel = System.Transactions.IsolationLevel.ReadCommitted;
using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required, options))
{
try
{
foreach(类型 var in 类型集合)
{
//一些条件判断
getProxy().Update(类型);//如果更新三条记录,第一条满足条件,后面的不满足,我第一次执行这里后数据库已变了,后面两条件在前面的判断条件就通不过.第一条变掉的值也没有回滚.这样写哪里错了?谢谢
}
MessageBox.Show("保存成功!");
scope.Complete();//不是在这里再整体提交的吗?
}
catch(Exception)
{
//...
}

}
...全文
2150 34 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
34 条回复
切换为时间正序
请发表友善的回复…
发表回复
carroll0911 2010-09-08
  • 打赏
  • 举报
回复
[Quote=引用 23 楼 wangping_li 的回复:]
我只是执行过 D local = this.Update(t, connection);这一步后数据库就已经变了,而且是可以在查询分析器查看的
这时应该查不到才对.而这时using也结束,collection.Close()也还没执行.所以应该和数据库关闭没关系吧
[/Quote]

能查到 这是你数据库隔离级别的问题吧.....
863922230 2009-09-24
  • 打赏
  • 举报
回复
估计是你的链接关闭的太早了,要最后在关闭连接,估计就没有事情的。
Garnett_KG 2009-02-26
  • 打赏
  • 举报
回复
[Quote=引用 31 楼 wangping_li 的回复:]
类似于下面这样的,我随便写了一个主从表保存的,第一次值对两个都能保存,第二次的时候我故意搞主外键约束错误,结果抛错,但是也不回滚,第一次的还是保存了,都是在一个TransactionScope 里啊

C# code
private void button1_Click(object sender, EventArgs e)
{
try
{
using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required))

[/Quote]

这个很容易理解啊.
你的异常是在Add 这个Method中发生,可是你只是MessageBox,并没有重新throw出来,所以button1_click中就
执行了scope.complete()了


改一下Add



void Add(Guid id, Guid pid)
{
SqlConnection conn;
SqlCommand cmd = new SqlCommand();
String str = "server=VARSETUP;uid=sa;pwd=sa;database=SS";
conn = new SqlConnection(str);

try
{
using (conn = new SqlConnection(str))
{
conn.Open();
String CommandText = "insert into Product (id,Name) values ('" + id + "','Hello')";
String CommandText2 = "insert into Type (id,pid,type) values ('" + Guid.NewGuid() + "','" + pid + "','dddd')";
cmd = new SqlCommand(CommandText, conn);
cmd.ExecuteNonQuery();
cmd = new SqlCommand(CommandText2, conn);
cmd.ExecuteNonQuery();
conn.Close();
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
throw ex; //重新throw error
}

}


wangping_li 2009-02-26
  • 打赏
  • 举报
回复
类似于下面这样的,我随便写了一个主从表保存的,第一次值对两个都能保存,第二次的时候我故意搞主外键约束错误,结果抛错,但是也不回滚,第一次的还是保存了,都是在一个TransactionScope 里啊

private void button1_Click(object sender, EventArgs e)
{
try
{
using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required))
{
Guid id = Guid.NewGuid();
Guid pid = Guid.Empty;
for (int i = 0; i < 2; i++)
{
if (i == 0)
pid = id;
else
pid = Guid.NewGuid();
Add(id, pid);
}
scope.Complete();
MessageBox.Show("OK");
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}

}

void Add(Guid id,Guid pid)
{
SqlConnection conn;
SqlCommand cmd = new SqlCommand();
String str = "server=(local);uid=sa;pwd=123;database=Demo";
conn = new SqlConnection(str);

try
{
using (conn = new SqlConnection(str))
{
conn.Open();
String CommandText = "insert into Product (id,Name) values ('" + id + "','Hello')";
String CommandText2 = "insert into Type (id,pid,producttype) values ('" + Guid.NewGuid() + "','" + pid + "','dddd')";
cmd = new SqlCommand(CommandText, conn);
cmd.ExecuteNonQuery();
cmd = new SqlCommand(CommandText2, conn);
cmd.ExecuteNonQuery();

}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}

}
wuyq11 2009-02-25
  • 打赏
  • 举报
回复
与底层数据操作有关,不要调用函数,使用TransactionScope 进行修改,看是否有问题。
哈哈潜伏哥 2009-02-25
  • 打赏
  • 举报
回复
我也进来学习了。
Garnett_KG 2009-02-25
  • 打赏
  • 举报
回复
也许是因为你的底层类中Connection有关闭的原因?
wangping_li 2009-02-25
  • 打赏
  • 举报
回复
TO:lovefootball
我看过了MSDN的解释,实在找不到问题所在,逻辑上来讲是对的,可是执行到Update的时候这时数据库的值就已经变了,不理解啊
lovefootball 2009-02-25
  • 打赏
  • 举报
回复
TransactionScope 我用的比较少
但是我理解
如果没调用Complete的话
按道理来说是不可能提交到数据库的
你好好看看MSDN中关于TransactionScopeOption以及TransactionOptions 的解释

我一般用TransactionScopeOption.RequiresNew
是没问题的
wangping_li 2009-02-25
  • 打赏
  • 举报
回复
感谢;Garnett_KG
但是我Update是在using(TrasactionScope..)中执行的.也就是说在事务范围内打开的数据库连接
这样子的话应该能登记上的啊
Garnett_KG 2009-02-25
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 wangping_li 的回复:]
非常感谢LS回复
可是第一次我调用Update的时候,根本没有执行到scope.Complete(),这时数据库的值就已经提交了,后面执异常也不回滚
[/Quote]

像是Connection.Open()时,并没有建在TrasactionScope中。
可以在TrasactionScope直接建个Connection,然後去执行更新,看能否rollback,
这样好排除是不是你的底层类的问题。
stonehy520 2009-02-25
  • 打赏
  • 举报
回复
学习一下
king19840811 2009-02-25
  • 打赏
  • 举报
回复
up学习
wangping_li 2009-02-25
  • 打赏
  • 举报
回复
非常感谢LS回复
可是第一次我调用Update的时候,根本没有执行到scope.Complete(),这时数据库的值就已经提交了,后面执异常也不回滚
lovefootball 2009-02-25
  • 打赏
  • 举报
回复
如果你想让他回滚的话,你不能执行Complete

using (TransactionScope scope = new TransactionScope(TransactionScopeOption.RequiresNew))
{
bool isComplete = true;
foreach(...)
{
if (XXX)
{
getProxy().Update(类型);
}
else
{
isComplete = false;
break;
}
}
if (isComplete) scope.Complete();
}

这样就可以了吧~~~
wangping_li 2009-02-25
  • 打赏
  • 举报
回复
private D Update(D d, IDbConnection conn)
{
this.OnUpdating(d);
d.Meta = this.Update<E>(conn, d.Meta);//这里的this.Update是调用接口定义的方法
d.setUnchange();
this.OnUpdated(d);
return d;
}
Garnett_KG 2009-02-25
  • 打赏
  • 举报
回复
http://blog.csdn.net/greystar/archive/2006/11/01/1359960.aspx
wangping_li 2009-02-25
  • 打赏
  • 举报
回复
非常谢谢天马兄的回答,我也看了transactionscope是不会受close影响的.两台机器的msdtc都开了的,配置这些都没问题
如果我写成如下格式都可以的:


[E2EOperation("添加", E2ETransactionScopeOption.Required)]
public virtual D Add(D t)
{
D local2;
//这里我把事务控件写到里面
using (TransactionScope scope = new TransactionScope())
{
using (IDbConnection connection = this.getDbConnection())
{
if (connection.State != ConnectionState.Open)
{
connection.Open();
}
D local = this.Add(t, connection);
connection.Close();
scope.Complete();
local2 = local;
}
}
return local2;
}

public object Add(object t)
{
if (!(t is D))
{
throw new E2EException("数据格式不正确");
}
return this.Add((D) t);
}

private D Add(D d, IDbConnection conn)
{

this.OnAdding(d);//调用新增的时候可以执行一个OnAdding方法内容
d.Meta = this.Add<E>(conn, d.Meta);
d.setUnchange();
this.OnAdded(d);
return d;
}

//在客户端使用时
override OnAdding(D d)
{
//这里面执行对B表的新增,同样B表也是调用上面的Add方法,也是有事务,这样子如果A表新增成功,B表不成功就会回滚,但是我撤在外面写就想不通为什么不行,我做一个测试,看看是不是底层操作类出了问题,非常感谢天马兄及LS各位兄弟回答
}
protected virtual void OnAdding(D d)
{
}

  • 打赏
  • 举报
回复
Pending transactions started using Transact-SQL or BeginTransaction are automatically rolled back. Transactions started through System.Transactions are controlled through the System.Transactions infrastructure, and are not affected by SqlConnection.Close.

-------------------
我刚刚查了下资料,如果使用transactionscope,即使close了,是不会不会提交事务
  • 打赏
  • 举报
回复
如果执行完ExecuteNonQuery就更新了数据,那不是我说的问题了。
我看你都是使用的IDb...,是自定义的数据库连接类吗,如果是,对于事务这块有没有bug,直接用begintran来操作可以不?使用的是什么数据库?两台服务器的msdtc都开了,配置是否正确。
加载更多回复(14)

111,092

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • AIGC Browser
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧