ExecuteReader 要求已打开且可用的连接。连接的当前状态为已关闭。
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ExecuteReader 要求已打开且可用的连接。连接的当前状态为已关闭。相关的知识,希望对你有一定的参考价值。
string sql = "select TypeName from RoomType where TypeId='" + TypeId + "'";
con.getCon().Open();
SqlCommand scm = new SqlCommand(sql, con.getCon());
SqlDataReader sdr = scm.ExecuteReader();
string typename = string.Empty;
while (sdr.Read())
typename = (string)sdr["TypeName"];
return typename;
sdr.Close();
public class DBHelper
public SqlConnection getCon()
string connectionstring = "server=.;trusted_connection=true;database=HotelManage";
SqlConnection con = new SqlConnection(connectionstring);
return con;
上面是我的连接字符串,应该没有问题的
在getCon()这个函数中,有一行代码是:
SqlConnection con = new SqlConnection(connectionstring);
也就是说,每调用一个这个函数,都会产生一个新的SqlConnection对象.
所以你下面的代码:
con.getCon().Open();
SqlCommand scm = new SqlCommand(sql, con.getCon());
两次getCon()得到的是不同的连接,第一个连接Open了.但是和SqlCommand绑定的连接没有Open.
修改成:
SqlConnection conn = con.getCon();
conn.Open();
SqlCommand scm = new SqlCommand(sql, conn); 参考技术A 哎。你的using语句怎么不写大括号呢,不写的话下面这句话 conn.Open();一旦执行完,using就会释放你的conn资源啊,当然会被关闭了。你在这句话下面打个断点,看看conn是不是为null。大括号从conn.open()开始,一直到sdr.Close();结束。 参考技术B 回答
您好,首先在实例化Connection后,加上conn.Open();然后你在while循环里边不要Close, 就是finallycon.Close();删掉;然后在循环外边再Close;
调用Connection.Open()方法;或者添加判断,例如下面的代码: if (MyIni.Gs_con.State != ConnectionState.Closed) OleDbCommand mysc = new OleDbCommand(sqltext, MyIni.Gs_con); //tools.MB(sqltext); result = tools.fieldnullint(mysc.ExecuteScalar()); if (result == 0) return false;
参考技术C return要放在close()后面,不然你都return了,怎么还会close呢;还有就是“con.getCon().Open();”也有问题,Open的应该是实例化对象,而不是你的连接字符串方法 参考技术D string conStr="";链接字符串SqlConnection con=new SqlConnection(conStr);
con.open();
string sql = "select TypeName from RoomType where TypeId='" + TypeId + "'";
SqlCommand scm = new SqlCommand(sql,con);
这样是常规的写法,应该可以
ExecuteReader 需要一个开放且可用的连接。连接的当前状态是 Connecting
【中文标题】ExecuteReader 需要一个开放且可用的连接。连接的当前状态是 Connecting【英文标题】:ExecuteReader requires an open and available Connection. The connection's current state is Connecting 【发布时间】:2012-03-31 03:05:57 【问题描述】:当尝试通过 ASP.NET 在线连接到 MSSQL 数据库时,当两个或更多人同时连接时,我会得到以下信息:
ExecuteReader 需要一个打开且可用的连接。连接的当前状态是 Connecting。
该站点在我的本地主机服务器上运行良好。
这是粗略的代码。
public Promotion retrievePromotion()
int promotionID = 0;
string promotionTitle = "";
string promotionUrl = "";
Promotion promotion = null;
SqlOpenConnection();
SqlCommand sql = SqlCommandConnection();
sql.CommandText = "SELECT TOP 1 PromotionID, PromotionTitle, PromotionURL FROM Promotion";
SqlDataReader dr = sql.ExecuteReader();
while (dr.Read())
promotionID = DB2int(dr["PromotionID"]);
promotionTitle = DB2string(dr["PromotionTitle"]);
promotionUrl = DB2string(dr["PromotionURL"]);
promotion = new Promotion(promotionID, promotionTitle, promotionUrl);
dr.Dispose();
sql.Dispose();
CloseConnection();
return promotion;
我可以知道可能出了什么问题以及如何解决它吗?
编辑:别忘了,我的连接字符串和连接都是静态的。我相信这就是原因。请指教。
public static string conString = ConfigurationManager.ConnectionStrings["dbConnection"].ConnectionString;
public static SqlConnection conn = null;
【问题讨论】:
不要在像 ASP.NET 这样的多线程环境中使用共享/静态连接,因为您正在生成锁或异常(打开的连接过多等)。将您的 DB-Class 扔进垃圾桶,然后在您需要的地方创建、打开、使用、关闭、处置 ado.net 对象。看看 using 语句。 你能给我详细介绍一下 SqlOpenConnection(); 和 sql.ExecuteReader();功能?.. private void SqlOpenConnection() try conn = new SqlConnection(); conn.ConnectionString = conString; conn.Open(); catch (SqlException ex) throw ex; @GuoHongLim:我忘了说即使是静态的conString
也不会增加性能,因为it's cached by default 无论如何(作为当前应用程序的每个配置值)。
...只是让它成为一个已知的未知数:确保您的数据库事务处理/工作单元正确,留给读者作为练习。
【参考方案1】:
很抱歉一开始只发表评论,但我几乎每天都发布类似的评论,因为许多人认为将 ADO.NET 功能封装到 DB-Class 中会很聪明(10 年前我也是) .大多数情况下,他们决定使用静态/共享对象,因为这似乎比为任何操作创建新对象要快。
这在性能和故障安全方面都不是一个好主意。
不要在连接池的领土上偷猎
ADO.NET 在ADO-NET Connection-Pool 中内部管理与 DBMS 的底层连接是有充分理由的:
实际上,大多数应用程序只使用一种或几种不同的 连接配置。这意味着在申请期间 执行时,将重复打开许多相同的连接,并且 关闭。为了最小化打开连接的成本,ADO.NET 使用 称为连接池的优化技术。
连接池减少了新连接的次数 必须打开。池子保持物理的所有权 联系。它通过保持一组活动来管理连接 每个给定连接配置的连接。每当用户 在连接上调用 Open,池化程序会寻找可用的 池中的连接。如果一个池连接可用,它 将其返回给调用者,而不是打开新连接。当。。。的时候 应用程序在连接上调用 Close,pooler 将其返回给 池化的活动连接集,而不是关闭它。一旦 连接被返回到池中,它已准备好在 下一次公开通话。
所以显然没有理由避免创建、打开或关闭连接,因为实际上它们根本没有被创建、打开和关闭。这只是连接池的一个标志,用于知道何时可以重用连接。但这是一个非常重要的标志,因为如果一个连接“正在使用”(连接池假设),一个新的物理连接必须对 DBMS 开放,这是非常昂贵的。
因此,您没有获得任何性能改进,而是相反。如果达到指定的最大池大小(默认值为 100),您甚至会遇到异常(打开的连接太多......)。因此,这不仅会极大地影响性能,还会成为严重错误和(不使用事务)数据转储区域的来源。
如果您甚至使用静态连接,那么您正在为每个试图访问该对象的线程创建一个锁。 ASP.NET 本质上是一个多线程环境。因此,这些锁极有可能导致性能问题。实际上,迟早您会遇到许多不同的异常(例如您的 ExecuteReader 需要一个开放且可用的连接)。
结论:
根本不要重用连接或任何 ADO.NET 对象。 不要将它们设为静态/共享(在 VB.NET 中) 始终创建、打开(在连接的情况下)、使用、关闭并在您需要的地方处置它们(例如在方法中) 使用using-statement
隐式处理和关闭(在连接的情况下)
这不仅适用于连接(尽管最引人注目)。每个实现IDisposable
的对象都应该被释放(最简单的using-statement
),尤其是在System.Data.SqlClient
命名空间中。
以上所有内容都反对封装和重用所有对象的自定义 DB-Class。这就是我评论垃圾的原因。这只是一个问题来源。
编辑:这是您的retrievePromotion
-方法的可能实现:
public Promotion retrievePromotion(int promotionID)
Promotion promo = null;
var connectionString = System.Configuration.ConfigurationManager.ConnectionStrings["MainConnStr"].ConnectionString;
using (SqlConnection connection = new SqlConnection(connectionString))
var queryString = "SELECT PromotionID, PromotionTitle, PromotionURL FROM Promotion WHERE PromotionID=@PromotionID";
using (var da = new SqlDataAdapter(queryString, connection))
// you could also use a SqlDataReader instead
// note that a DataTable does not need to be disposed since it does not implement IDisposable
var tblPromotion = new DataTable();
// avoid SQL-Injection
da.SelectCommand.Parameters.Add("@PromotionID", SqlDbType.Int);
da.SelectCommand.Parameters["@PromotionID"].Value = promotionID;
try
connection.Open(); // not necessarily needed in this case because DataAdapter.Fill does it otherwise
da.Fill(tblPromotion);
if (tblPromotion.Rows.Count != 0)
var promoRow = tblPromotion.Rows[0];
promo = new Promotion()
promotionID = promotionID,
promotionTitle = promoRow.Field<String>("PromotionTitle"),
promotionUrl = promoRow.Field<String>("PromotionURL")
;
catch (Exception ex)
// log this exception or throw it up the StackTrace
// we do not need a finally-block to close the connection since it will be closed implicitely in an using-statement
throw;
return promo;
【讨论】:
这对于提供连接工作范式非常有用。感谢您的解释。 写得好,对许多人偶然发现的东西的解释,我希望更多的人知道这一点。 (+1) 谢谢你,先生,我认为这是我读过的关于这个主题的最好解释,这个主题非常重要,很多新手都犯了错误。我必须赞美你出色的写作能力。 @Tim Schmelter 如何使用您建议的方法让我的查询在不同线程上运行,利用单个事务提交/回滚?【参考方案2】:几天前我发现了这个错误。
在我的情况下,这是因为我在单例上使用了事务。
如上所述,.Net 不适用于 Singleton。
我的解决方案是这样的:
public class DbHelper : DbHelperCore
public DbHelper()
Connection = null;
Transaction = null;
public static DbHelper instance
get
if (HttpContext.Current is null)
return new DbHelper();
else if (HttpContext.Current.Items["dbh"] == null)
HttpContext.Current.Items["dbh"] = new DbHelper();
return (DbHelper)HttpContext.Current.Items["dbh"];
public override void BeginTransaction()
Connection = new SqlConnection(Entity.Connection.getCon);
if (Connection.State == System.Data.ConnectionState.Closed)
Connection.Open();
Transaction = Connection.BeginTransaction();
我为我的实例使用了 HttpContext.Current.Items。这个类 DbHelper 和 DbHelperCore 是我自己的类
【讨论】:
以上是关于ExecuteReader 要求已打开且可用的连接。连接的当前状态为已关闭。的主要内容,如果未能解决你的问题,请参考以下文章
System.InvalidOperationException:ExecuteReader 需要打开且可用的连接。连接的当前状态为关闭
ExecuteReader 需要一个开放且可用的连接 Asp.net
ExecuteReader 需要一个开放且可用的连接。连接的当前状态是 Connecting