C# SQL Server 2005上的ADO.NET 2.0事务是否在异常时自动回滚?
如果我们开始一个事务,然后执行一些db操作,比如insert,然后发生异常,如果我不调用catch/exception处理程序中的transaction.rollback(),该事务是否会自动回滚 即使事务被回滚,是否会导致内存泄漏,即事务对象和连接对象以其原始状态挂起在内存中,直到垃圾收集器启动C# SQL Server 2005上的ADO.NET 2.0事务是否在异常时自动回滚?,c#,ado.net,transactions,C#,Ado.net,Transactions,如果我们开始一个事务,然后执行一些db操作,比如insert,然后发生异常,如果我不调用catch/exception处理程序中的transaction.rollback(),该事务是否会自动回滚 即使事务被回滚,是否会导致内存泄漏,即事务对象和连接对象以其原始状态挂起在内存中,直到垃圾收集器启动 客户: namespace Client { class Program { static void Main(string[] args) {
客户:
namespace Client
{
class Program
{
static void Main(string[] args)
{
DaContract Impl = new Impl();
Impl.AddFriend(new Friend("Someone", "100"));
Impl.AddFriend(new Friend("Someone else"));
Console.ReadLine();
}
}
}
服务器:
using System;
using MyLib.DataAccess;
using System.Data;
namespace TestTransactionAndConnectionStateOnException
{
public class Friend
{
public string FullName;
public string Phone;
public Friend(string fullName): this(fullName, null) {}
public Friend(string fullName, string phone)
{
this.FullName = fullName;
this.Phone = phone;
}
}
public interface DaContract
{
int AddFriend( Friend f );
int UpdatePhone(string fullName, string phone);
}
public class Impl: DaContract
{
Mediator _m;
public Impl() { this._m = new Mediator(); }
public int AddFriend( Friend f )
{
int ret = 0;
try
{
ret = this._m.AddFriend( f );
}
catch(Exception ex)
{
HandleException(ex);
}
return ret;
}
public int UpdatePhone(string fullName, string phone)
{
int ret = 0;
try
{
ret = this._m.UpdatePhone(fullName, phone);
}
catch(Exception ex)
{
HandleException(ex);
}
return ret;
}
public void HandleException(Exception ex)
{
/* see the transaction state */
/* see connection state */
/* do nothing and let the client call another method to initiate a new
* transaction and a new connection */
}
}
public class Mediator
{
private string _connectionString = "Data Source=localhost;Integrated Security=SSPI;Initial Catalog=MyFriends";
private Manager _m = new Manager();
public int AddFriend( Friend f )
{
int ret = 0;
using (ISession session = SessionFactory.Create(SessionType.Ado, this._connectionString))
{
session.BeginTransaction();
ret = this._m.AddFriend(f, session);
session.CommitTransaction();
}
return ret;
}
public int UpdatePhone(string fullName, string phone)
{
int ret = 0;
using (ISession session = SessionFactory.Create(SessionType.Ado, this._connectionString))
{
session.BeginTransaction();
ret = this._m.UpdateFriend(fullName, phone, session);
session.CommitTransaction();
}
return ret;
}
}
public class Manager
{
public int AddFriend(Friend f, ISession session) { return Handler.Instance.AddFriend(f, session); }
public int UpdateFriend(string fullName, string phone, ISession session) { return Handler.Instance.UpdatePhone(fullName, phone, session); }
}
public class Handler
{
private static Handler _handler = null;
private Handler() {}
public static Handler Instance
{
get
{
if (_handler == null)
_handler = new Handler();
return _handler;
}
}
public int AddFriend( Friend f, ISession session )
{
/* check session, transaction and connection states here */
Console.WriteLine(session.Connection.State.ToString());
int ret = 0;
/* Add the friend */
IDbCommand command = session.CreateCommand();
command.CommandType = CommandType.Text;
command.CommandText = string.Format("INSERT INTO Friend(FullName, Phone) values('{0}', '{1}')", f.FullName, f.Phone);
ret = command.ExecuteNonQuery();
/* throw an exception just for the heck of it (don't dispose off ISession yet) */
if (string.Compare(f.FullName, "Someone", true) == 0)
throw new Exception("Fake exception. Friend value can't be 'Someone'");
return ret;
}
public int UpdatePhone(string fullName, string phone, ISession session )
{
return 0;
}
}
}
我无法在评论部分发布代码,原因是字数限制,而且它破坏了所有格式。如果在未提交的情况下处理事务,则事务将回滚。因此,只要您使用using()开始事务,或者有一个调用Dispose()的finally块,它就会在出现异常时自动回滚
如果不处理事务/连接,它最终将被垃圾回收器回收,但在此之前将一直挂在内存中。(事实上,托管SqlTransaction对象将一直挂在内存中,直到GC启动为止;但Disposition可确保尽早清理非托管事务/连接资源,释放服务器端资源并释放连接以供重用。)如果在未提交的情况下处理事务,则事务将回滚。因此,只要您使用using()开始事务,或者有一个调用Dispose()的finally块,它就会在出现异常时自动回滚 如果不处理事务/连接,它最终将被垃圾回收器回收,但在此之前将一直挂在内存中。(事实上,托管SqlTransaction对象将一直挂在内存中,直到GC启动为止;但Disposition可确保尽早清理非托管事务/连接资源,释放服务器端资源并释放连接以供重用。) 客户 服务器 我无法在评论部分发布代码,因为字数限制,而且它搞砸了所有的格式 客户 服务器
由于字数限制和格式错误,我无法在评论部分发布代码。谢谢,itowlson。我想你几乎解决了我真正关心的问题。我只是尝试了一个以我当前的设计为模型的示例应用程序来复制我的问题。这是我的。TABLE------创建TABLE[Friend]([ID][int]IDENTITY(1,1)NOT NULL,[FullName][varchar](50)NOT NULL,[Phone][varchar](50)NULL,)在下面的评论中发送其余内容我不太确定后续问题是什么(抱歉,如果我是哑巴),但在您发布的代码中,尚不清楚Mediator.AddFriend和Mediator.UpdatePhone是否正在处理它们创建的事务。但是,您保证会处理ISession,因此如果ISession.dispose正在对包含的事务和连接对象调用dispose,那么您应该不会有问题(如果我正确识别了您的问题;如果没有,请留下另一条评论)。谢谢,itowlson。我想你几乎解决了我真正关心的问题。我只是尝试了一个以我当前的设计为模型的示例应用程序来复制我的问题。这是我的。TABLE------创建TABLE[Friend]([ID][int]IDENTITY(1,1)NOT NULL,[FullName][varchar](50)NOT NULL,[Phone][varchar](50)NULL,)在下面的评论中发送其余内容我不太确定后续问题是什么(抱歉,如果我是哑巴),但在您发布的代码中,尚不清楚Mediator.AddFriend和Mediator.UpdatePhone是否正在处理它们创建的事务。但是,您保证会处理ISession,因此如果ISession.dispose正在对包含的事务和连接对象调用dispose,那么您应该不会有问题(如果我正确识别了您的问题;如果没有,请留下另一条评论)。
using System;
using MyLib.DataAccess;
using System.Data;
namespace TestTransactionAndConnectionStateOnException
{
public class Friend
{
public string FullName;
public string Phone;
public Friend(string fullName): this(fullName, null) {}
public Friend(string fullName, string phone)
{
this.FullName = fullName;
this.Phone = phone;
}
}
public interface DaContract
{
int AddFriend( Friend f );
int UpdatePhone(string fullName, string phone);
}
public class Impl: DaContract
{
Mediator _m;
public Impl() { this._m = new Mediator(); }
public int AddFriend( Friend f )
{
int ret = 0;
try
{
ret = this._m.AddFriend( f );
}
catch(Exception ex)
{
HandleException(ex);
}
return ret;
}
public int UpdatePhone(string fullName, string phone)
{
int ret = 0;
try
{
ret = this._m.UpdatePhone(fullName, phone);
}
catch(Exception ex)
{
HandleException(ex);
}
return ret;
}
public void HandleException(Exception ex)
{
/* see the transaction state */
/* see connection state */
/* do nothing and let the client call another method to initiate a new
* transaction and a new connection */
}
}
public class Mediator
{
private string _connectionString = "Data Source=localhost;Integrated Security=SSPI;Initial Catalog=MyFriends";
private Manager _m = new Manager();
public int AddFriend( Friend f )
{
int ret = 0;
using (ISession session = SessionFactory.Create(SessionType.Ado, this._connectionString))
{
session.BeginTransaction();
ret = this._m.AddFriend(f, session);
session.CommitTransaction();
}
return ret;
}
public int UpdatePhone(string fullName, string phone)
{
int ret = 0;
using (ISession session = SessionFactory.Create(SessionType.Ado, this._connectionString))
{
session.BeginTransaction();
ret = this._m.UpdateFriend(fullName, phone, session);
session.CommitTransaction();
}
return ret;
}
}
public class Manager
{
public int AddFriend(Friend f, ISession session) { return Handler.Instance.AddFriend(f, session); }
public int UpdateFriend(string fullName, string phone, ISession session) { return Handler.Instance.UpdatePhone(fullName, phone, session); }
}
public class Handler
{
private static Handler _handler = null;
private Handler() {}
public static Handler Instance
{
get
{
if (_handler == null)
_handler = new Handler();
return _handler;
}
}
public int AddFriend( Friend f, ISession session )
{
/* check session, transaction and connection states here */
Console.WriteLine(session.Connection.State.ToString());
int ret = 0;
/* Add the friend */
IDbCommand command = session.CreateCommand();
command.CommandType = CommandType.Text;
command.CommandText = string.Format("INSERT INTO Friend(FullName, Phone) values('{0}', '{1}')", f.FullName, f.Phone);
ret = command.ExecuteNonQuery();
/* throw an exception just for the heck of it (don't dispose off ISession yet) */
if (string.Compare(f.FullName, "Someone", true) == 0)
throw new Exception("Fake exception. Friend value can't be 'Someone'");
return ret;
}
public int UpdatePhone(string fullName, string phone, ISession session )
{
return 0;
}
}
}
CREATE TABLE [Friend]
(
[ID] [int] IDENTITY(1,1) NOT NULL,
[FullName] [varchar](50) NOT NULL,
[Phone] [varchar](50) NULL,
)
namespace Client
{
class Program
{
static void Main(string[] args)
{
DaContract Impl = new Impl();
Impl.AddFriend(new Friend("Someone", "100"));
Impl.AddFriend(new Friend("Someone else"));
Console.ReadLine();
}
}
}
using System;
using MyLib.DataAccess;
using System.Data;
namespace TestTransactionAndConnectionStateOnException
{
public class Friend
{
public string FullName;
public string Phone;
public Friend(string fullName): this(fullName, null) {}
public Friend(string fullName, string phone)
{
this.FullName = fullName;
this.Phone = phone;
}
}
public interface DaContract
{
int AddFriend( Friend f );
int UpdatePhone(string fullName, string phone);
}
public class Impl: DaContract
{
Mediator _m;
public Impl() { this._m = new Mediator(); }
public int AddFriend( Friend f )
{
int ret = 0;
try
{
ret = this._m.AddFriend( f );
}
catch(Exception ex)
{
HandleException(ex);
}
return ret;
}
public int UpdatePhone(string fullName, string phone)
{
int ret = 0;
try
{
ret = this._m.UpdatePhone(fullName, phone);
}
catch(Exception ex)
{
HandleException(ex);
}
return ret;
}
public void HandleException(Exception ex)
{
/* see the transaction state */
/* see connection state */
/* do nothing and let the client call another method to initiate a new
* transaction and a new connection */
}
}
public class Mediator
{
private string _connectionString = "Data Source=localhost;Integrated Security=SSPI;Initial Catalog=MyFriends";
private Manager _m = new Manager();
public int AddFriend( Friend f )
{
int ret = 0;
using (ISession session = SessionFactory.Create(SessionType.Ado, this._connectionString))
{
session.BeginTransaction();
ret = this._m.AddFriend(f, session);
session.CommitTransaction();
}
return ret;
}
public int UpdatePhone(string fullName, string phone)
{
int ret = 0;
using (ISession session = SessionFactory.Create(SessionType.Ado, this._connectionString))
{
session.BeginTransaction();
ret = this._m.UpdateFriend(fullName, phone, session);
session.CommitTransaction();
}
return ret;
}
}
public class Manager
{
public int AddFriend(Friend f, ISession session) { return Handler.Instance.AddFriend(f, session); }
public int UpdateFriend(string fullName, string phone, ISession session) { return Handler.Instance.UpdatePhone(fullName, phone, session); }
}
public class Handler
{
private static Handler _handler = null;
private Handler() {}
public static Handler Instance
{
get
{
if (_handler == null)
_handler = new Handler();
return _handler;
}
}
public int AddFriend( Friend f, ISession session )
{
/* check session, transaction and connection states here */
Console.WriteLine(session.Connection.State.ToString());
int ret = 0;
/* Add the friend */
IDbCommand command = session.CreateCommand();
command.CommandType = CommandType.Text;
command.CommandText = string.Format("INSERT INTO Friend(FullName, Phone) values('{0}', '{1}')", f.FullName, f.Phone);
ret = command.ExecuteNonQuery();
/* throw an exception just for the heck of it (don't dispose off ISession yet) */
if (string.Compare(f.FullName, "Someone", true) == 0)
throw new Exception("Fake exception. Friend value can't be 'Someone'");
return ret;
}
public int UpdatePhone(string fullName, string phone, ISession session )
{
return 0;
}
}
}