关于TransactionOptions事务的应用,具体应该怎么用和注意事项
最近做项目,碰到一个问题,就是多个用户预约同一条信息,然后其中一个预约成功,但另一个没预约成功,但是都同时把数据保存到连个表当中了。就是并发状态导致数据不统一,然后考虑到用事务来处理,当时第一个想到的是在数据库上应用数据库的事务处理,但是现在的项目是用三层架构来写的,各个表都有各自的连接数据库的方法和业务逻辑,在数据库上用事务的话,需要连接数据库的时候放在一起才能用事务,所以就在网上查找到.net有单独的事务处理类,就是TransactionOptions类,在网上查找了些资料,我也照着用在了我的项目里,但是我放在事务里的是一个一个的方法,就是预约要处理的代码,就是这样
public void Update()
{
//设置事务范围
TransactionOptions transactionOption = new TransactionOptions();
//设置事务隔离级别
transactionOption.IsolationLevel = System.Transactions.IsolationLevel.ReadCommitted; //不可以在事务期间读取可变数据,但是可以修改它
//RepeatableRead 可以在事务期间读取可变数据,但是不可以修改。 可以在事务期间添加新数据。
// 设置事务超时时间为60秒
// transactionOption.Timeout = new TimeSpan(0, 0, 60);
using (TransactionScope transaction = new TransactionScope(TransactionScopeOption.Required))
{
try
{
//dalPractice oDal = new dalPractice();
SqlDataAdapter DA = oDal.PracticeUpdateAdapter(nPracticeID);
SqlCommandBuilder oBulider = new SqlCommandBuilder(DA);
DataSet DS = new DataSet();
DA.Fill(DS);
if (DS == null) return;
DataRow DR = null;
string strOldTimes = oDal.PracticeTimeString(nPracticeID);
bool isTimesChanged = oDal.CompareTimes(strOldTimes, strTimeCheckValue);
bool blAdd = false;
if (DS.Tables[0].Rows.Count > 0)
{
DR = DS.Tables[0].Rows[0];
DR.BeginEdit();
//修改日志
string strLogs = oAdmin.AdminInfo("AdminName") + "(" + oAdmin.AdminID + ")修改:(" + DateTime.Now.ToString("yyyy-MM-dd hh:mm") + "); " +
lg.EditRecord("学员名称", DR["PracticeName"], strPracticeName) +
lg.EditRecord("手机", DR["Mobile"], strMobile) +
lg.EditRecord("固定电话", DR["QQ"], strQQ) +
lg.EditRecord("E-mail", DR["Email"], strEmail) +
//lg.EditRecord("练车日期", DR["PracticeDate"], strPracticeDate) +
//lg.EditRecord("车型", DR["CarNo"], strCarNo) +
lg.EditRecord("教练", DR["CoachName"], strCoachName) +
lg.EditRecord("报考类型", DR["Driver_Type"], strDriverType) +
lg.EditRecord("学员状态", DR["PracticeStatus"], nPracticeStatus) +
lg.EditRecord("确认方式", DR["ConfirmType"], strConfirmType) +
//lg.EditRecord("训练科目", DR["LessonName"], strLessonName) +
lg.EditRecord("备注", DR["Remark"], strRemark);
if (!isTimesChanged) strLogs += lg.EditRecord("时间段选择", strOldTimes, strTimeCheckValue);
DR["Logs"] = Convert.ToString(DR["Logs"]) + strLogs + Convert.ToChar(13);
//strSNO = Convert.ToString(DR["SNO"]);
//----------------------------------------------
//if (DR["CateID"] != gnCateID){blCateChanged = true
// if (not DR["ImgFlag"]){DR["Image"] = strImage
}
else
{
blAdd = true;
DR = DS.Tables[0].NewRow();
DR.BeginEdit();
nPracticeID = oAccess.GetMaxID("School_Practice", "PracticeID"); //因为倒数据的导致自动编号错乱,只能用程序方式添加PracticeID了
tbPracticeID.Text = nPracticeID.ToString();
DR["PracticeID"] = nPracticeID;
DR["AdminID"] = oAdmin.AdminID;
// DataTable dtPraStudent = oStudent.StudentInfo(nStudentID);
if (dtPraStudent != null && dtPraStudent.Rows.Count > 0)
{
DR["UserID"] = Convert.ToString(dtPraStudent.Rows[0]["UserID"]);
}
DR["AddTime"] = DateTime.Now;
//strSNO = Guid.NewGuid().ToString();
//DR["SNO"] = strSNO;
}
DR["StudentID"] = nStudentID;
DR["PracticeName"] = strPracticeName;
DR["Mobile"] = strMobile;
DR["QQ"] = strQQ;
DR["Email"] = strEmail;
if (lg.IsValidDate(strPracticeDate)) DR["PracticeDate"] = strPracticeDate;
DR["Driver_Type"] = strDriverType;
DR["CarNo"] = strCarNo;
DR["CoachName"] = strCoachName;
DR["LessonName"] = strLessonName;
DR["ConfirmType"] = strConfirmType;
DR["PracticeStatus"] = nPracticeStatus;
DR["Remark"] = strRemark;
DR.EndEdit();
if (DR.RowState == DataRowState.Detached)
{
//nPracticeID = oAccess.GetMaxID("School_Practice", "PracticeID"); //先获取最新ID,用于跳转到显示页面
DS.Tables[0].Rows.Add(DR);
DA.Update(DS);
// nPracticeID = oAccess.GetMaxID("School_Practice", "PracticeID") - 1; //为了避免删除后获得的不是最新的id号,等添加了后再重新获取最新id号
}
else if (DR.RowState == DataRowState.Modified)
{
//DS.Tables[0].AcceptChanges();
DA.Update(DS);
}
// System.Transactions.Transaction tr=System.Transactions.Transaction.Current;
DS.Dispose();
DA.Dispose();
oBulider.Dispose();
UpdateHadPracticeHours(nStudentID, blAdd, strTimeCheckValue, strOldTimes); //更新预约时长 注意 先更新时长再更新预约时间
oDal.PracticeTimeUpdate(nPracticeID, strTimeCheckValue);
//发送短信并记录发送结果
if (chkMobileSms.Checked)
{
DataTable dt = oDal.PracticeTimeList(nPracticeID);
jx.Models.Mobile.vxSms oSms = new Models.Mobile.vxSms();
if (dt != null)
{
for (int i = 0; i < dt.Rows.Count; i++)
{
DataRow dr = dt.Rows[i];
string strSms = Str(dr["PracticeName"]) + ",您好!您预约了" + Str(dr["CoachName"]) + "教练于" + Convert.ToDateTime(dr["PracticeDate2"]).ToString("M月d日") + " " + Str(dr["TimeBeg2"]) + "在金盘场地进行练习,请提前半小时到场报到,逾期自误。";
string strSNO = "";
bool Success = oSms.Send("", lg.ToInt(dr["StudentID"]), Str(dr["Mobile"]), strSms, ref strSNO);
oDal.SmsUpdate(nPracticeID, Convert.ToDateTime(GetDate(dr["PracticeDate2"])), Str(dr["TimeBeg2"]), strSNO);
}
}
}
oDal.oAccess.connectionClose();
transaction.Complete();
}
catch (Exception ex)
{
ScriptManager.RegisterClientScriptBlock(UpdatePanel1, this.GetType(), "", "很抱歉,学员没有预约成功!", true);
throw new Exception("发送信息异常,原因:" +ex.Message);
}
finally
{
transaction.Dispose();
}
}
}
但是调试运行时却提示事务超时。我就很郁闷了,难道这个事务要处理的代码太多了就不起作用了吗?
现在我想问问各位大侠,有谁用过这个TransactionOptions处理事务的,要怎么用,还要注意些什么,还有在什么情况下使用才好,用了后会是程序变慢吗?
现在急需解决,查了很多资料 都是讲基本怎么用,但是没讲会遇到哪些问题,或者遇到了会怎样解决,我都不知道我写了,但到底是不是起到事务的作用了没? 很困惑啊!! c# 事务 c# TransactionOptions 事务 --------------------编程问答-------------------- 我按照上面那样写的话,就会提示:Sys.WebForms.PageRequestManagerServerErrorException: 发送信息异常,原因:Timeout 时间已到。在操作完成之前超时时间已过或服务器未响应。
语句已终止。 --------------------编程问答-------------------- 然后我就把事务的作用范围缩小,代码这样写
//设置事务范围
TransactionOptions transactionOption = new TransactionOptions();
//设置事务隔离级别
transactionOption.IsolationLevel = System.Transactions.IsolationLevel.ReadCommitted; //不可以在事务期间读取可变数据,但是可以修改它
//RepeatableRead 可以在事务期间读取可变数据,但是不可以修改。 可以在事务期间添加新数据。
// 设置事务超时时间为60秒
// transactionOption.Timeout = new TimeSpan(0, 0, 60);
using (TransactionScope transaction = new TransactionScope(TransactionScopeOption.Required))
{
try
{
if (DR.RowState == DataRowState.Detached)
{
//nPracticeID = oAccess.GetMaxID("School_Practice", "PracticeID"); //先获取最新ID,用于跳转到显示页面
DS.Tables[0].Rows.Add(DR);
DA.Update(DS);
// nPracticeID = oAccess.GetMaxID("School_Practice", "PracticeID") - 1; //为了避免删除后获得的不是最新的id号,等添加了后再重新获取最新id号
}
else if (DR.RowState == DataRowState.Modified)
{
//DS.Tables[0].AcceptChanges();
DA.Update(DS);
}
// System.Transactions.Transaction tr=System.Transactions.Transaction.Current;
DS.Dispose();
DA.Dispose();
oBulider.Dispose();
UpdateHadPracticeHours(nStudentID, blAdd, strTimeCheckValue, strOldTimes); //更新预约时长 注意 先更新时长再更新预约时间
oDal.PracticeTimeUpdate(nPracticeID, strTimeCheckValue);
//发送短信并记录发送结果
if (chkMobileSms.Checked)
{
DataTable dt = oDal.PracticeTimeList(nPracticeID);
jx.Models.Mobile.vxSms oSms = new Models.Mobile.vxSms();
if (dt != null)
{
for (int i = 0; i < dt.Rows.Count; i++)
{
DataRow dr = dt.Rows[i];
string strSms = Str(dr["PracticeName"]) + ",您好!您预约了" + Str(dr["CoachName"]) + "教练于" + Convert.ToDateTime(dr["PracticeDate2"]).ToString("M月d日") + " " + Str(dr["TimeBeg2"]) + "在金盘场地进行练习,请提前半小时到场报到,逾期自误。";
string strSNO = "";
bool Success = oSms.Send("", lg.ToInt(dr["StudentID"]), Str(dr["Mobile"]), strSms, ref strSNO);
oDal.SmsUpdate(nPracticeID, Convert.ToDateTime(GetDate(dr["PracticeDate2"])), Str(dr["TimeBeg2"]), strSNO);
}
}
}
oDal.oAccess.connectionClose();
transaction.Complete();
}
catch (Exception ex)
{
ScriptManager.RegisterClientScriptBlock(UpdatePanel1, this.GetType(), "", "很抱歉,学员没有预约成功!", true);
throw new Exception("发送信息异常,原因:" +ex.Message);
}
finally
{
transaction.Dispose();
}
}
可以执行,但是好像中间执行错误的,还是照样进行下去,并没有回滚。感觉好像并没有执行事务的用法 --------------------编程问答-------------------- 为什么没有人啊?? 伤心。。。。
补充:.NET技术 , ASP.NET