您的位置:首页 > 数据库

SqlConnection,SqlTransaction,SqlDataReader解说

2010-07-12 15:08 169 查看
概要集中:

Connection 是由系统管理的,由一个pool提供,一般不会引发问题,但是及时close仍然是好习惯

Transaction和sqlreader是我们必须自己管理的资源,必须保持对称

Transaction begin

Commit/rollback

Reader open-> close

并且要考虑异常的处理,就是有异常时也要保证资源被清理

对reader 用using()

对 transcation 用

Try

Catch

Final—可选

详解:

SQLConnection的运用线程池技术开发

Pooling参数用来说明在连接到数据源时,是否使用连接池,默认是True。当该值为True 时,系统将从适当的池中提取 SQLConnection 对象,或在需要时创建该对象并将其添加到适当的池中。当取值为False时,不使用连接池。

当应用程序连接到数据源或创建连接对象时,系统不仅要开销一定的通信和内存资源,还必须完成诸如建立物理通道(例如套接字或命名管道),与服务器进行初次握手,分析连接字符串信息,由服务器对连接进行身份验证,运行检查以便在当前事务中登记等任务,因此往往成为最为耗时的操作。

实际上,大多数应用程序仅使用一个或几个不同的连接配置。这意味着在执行应用程序期间,许多相同的连接将反复地打开和关闭。为了使打开的连接成本最低,ADO.NET使用称为Pooling(即连接池)的优化方法。

在连接池中,为了提高数据库的连接效率,根据实际情况,预先存放了若干数据库连接对象,这些对象即使在用完后也不会被释放。应用程序不是向数据源申请连接对象,而是向连接池申请数据库的连接对象。另外,连接池中的连接对象数量必须同实际需求相符,空置和满载都对数据库的连接效率不利。

Max Pool Size和Min Pool Size这两个参数分别表示连接池中最大和最小连接数量,默认分别是100和0。根据实际应用适当地取值将提高数据库的连接效率。

典型用法:using (SqlConnection conn = new SqlConnection(GLibrary.ConnectionString)){}

SqlTransaction

要避免在任何情况下都要关闭SqlTransaction, if语句,try catch语句,否则就 会占用资源,阻止下一步数据库的访问:

try
{
using (SqlConnection conn = new SqlConnection(GLibrary.ConnectionString))
{
string sInsert = "", sUpdate = "";
int i = 0;
SqlCommand cmd = null;
SqlParameter pdon, pdoff;

conn.Open();

pciSource = pciSourceCopy.Count > 0 ? pciSourceCopy[0] : pciSourceMove[0];
trans = conn.BeginTransaction();
if (!bNotCreatePC)
{
sInsert = "insert into PlanningCrew (IDPlanLine,IDRank,DueOn,DueOff,IDVessel,Port) " +
" values({0},{1},@DueOn,@DueOff,{2},'{3}'); select max(id) as ID from planningcrew";
sInsert = string.Format(sInsert, pciTarget.PlanLine, pciTarget.RankId, pciTarget.VesselId, pciTarget.Port);
cmd = new SqlCommand(sInsert);
cmd.Connection = conn;
cmd.Transaction = trans;
pdon = new SqlParameter("@DueOn", SqlDbType.DateTime);
pdon.Value = pciTarget.DueOff.AddDays(1.0);
cmd.Parameters.Add(pdon);
pdoff = new SqlParameter("@DueOff", SqlDbType.DateTime);
//pdoff.Value = pciTarget.DueOff.AddDays(pciSource.DueOff.Subtract(pciSource.DueOn).Days + 1);
pdoff.Value = pciTarget.DueOff.AddDays(1.0).AddMonths(iContractLength);
cmd.Parameters.Add(pdoff);
using (SqlDataReader sdr = cmd.ExecuteReader())
{
if (sdr.HasRows)
{
sdr.Read();
iNewPCID = sdr.IsDBNull(sdr.GetOrdinal("ID")) ? 0 : sdr.GetInt32(sdr.GetOrdinal("ID"));
//sdr.Close();
fpbd = new FPBackData();
fpbd.Warning = enumFPWarning.None;
fpbd.PlanCrewID = iNewPCID;
backList.Add(fpbd);
}
}
}

for (i = 0; i < pciSourceMove.Count; i++)
{
pciSource = pciSourceMove[i];
if (pciSource.Status == 15)
{
fpbd = new FPBackData();
fpbd.PlanCrewID = pciSource.PlanningCrewID;
fpbd.Warning = enumFPWarning.MovingSignedContract;
backList.Add(fpbd);
}
//if (offset < 0 && !bContinueAnyway) return backList;
sUpdate = "update Candidate set IDPlanningCrew={0}, CStatus=5, locked=0, DocChecked=0, CheckOperator=null, CheckDate=null, CheckRemarks=null, ForceCheckRemarks=null where IDPlanningCrew={1} and IDEmployee={2}";
sUpdate = string.Format(sUpdate, iNewPCID, pciSource.PlanningCrewID, pciSource.EmployeeID);
SqlCommand cmd2 = new SqlCommand(sUpdate);
cmd2.Connection = conn;
cmd2.Transaction = trans;
cmd2.ExecuteNonQuery();

//trans.Commit(); //  注意不要在代码可能走不到的地方去 commit trans
}

for (i = 0; i < pciSourceCopy.Count; i++)
{
pciSource = pciSourceCopy[i];
sInsert = "insert into Candidate (IDPlanningCrew,IDEmployee,CStatus,IDAgency,IDContract,Locked,DocChecked) " +
" values({0},{1},{2},{3},{4},{5},{6})";
sInsert = string.Format(sInsert, iNewPCID, pciSource.EmployeeID, 5, pciSource.AgencyID, 0, 0, 0);
SqlCommand cmd3 = new SqlCommand(sInsert);
cmd3.Connection = conn;
cmd3.Transaction = trans;
cmd3.ExecuteNonQuery();

//trans.Commit(); //  注意不要在代码可能走不到的地方去 commit trans
}
trans.Commit(); // 在这里commit
}
}
catch (Exception exp)
{
trans.Rollback();
errorMessage = exp.Message;
}


提示错误:

The SqlTransaction has completed; it is no longer usable

当你在提交SqlTransaction之前,关闭了connection,可能出现错误。

3. SqlDataReader

使用SqlDataReader注意的几点

1、当SqlDataReader没有关闭之前,数据库连接会一直保持open状态,所以在使用SqlDataReader时,使用完毕应该马上调用SqlDataReader.Close()关闭它。

2、一个连接只能被一个SqlDataReader使用,这也是为什么要尽早关闭SqlDataReader的原因。

3、使用完SqlDataReader后,你可以在程序中显示的调用数据库连接对象的Close方法关闭连接,也可以在调用Command对象的ExecuteReader方法时传递CommandBehavior.CloseConnection 这个枚举变量,这样在调用SqlDataReader的Close方法时会自动关闭数据库连接。

4、使用SqlDataReader时尽量使用和数据库字段类型匹配的方法来取得相应的值,比如对于整形的字段使用GetInt32,对字符类型的字段使用GetString。这样会减少因为类型不一致而额外增加的类型转换操作。

5、使用SqlDataReader获取多条记录时,如果没有访问到取出记录的末尾时想要关闭SqlDataReader,应该先调用Command对象的Cancel方法,然后再调用SqlDataReader的Close方法。Command对象的Cancel方法使得数据库不再把SqlDataReader中未访问的数据发送到调用端,如果不调用此方法直接关闭SqlDataReader,数据库会发送和SqlDataReader未访问数据等长的空数据流到调用端。

6、如果想通过SqlCommand的ExecuteReader方法获取存储过程的返回值或者输出参数,必须先调用SqlDataReader的Close方法后,才能获取输出参数的值或者返回值。

7、如果使用SqlDataReader只返回一条记录,那么在调用Command的ExecuteReader方法时,指定

CommandBehavior.SingleRow参数,这个参数的是否使用对SQL Server .NET Data Provider没有什么影响,但是当你使用OLE DB .NET Data Provider时,指定这个参数后,DataPrivider内部将使用IRow接口,而不是使用相对来说耗费资源的IRowSet接口。

源文档 </article/5566087.html>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: