iBatisNet 是通过 SqlMap 实例执行 SQL Statement 的, 一个 SqlMap 实例里封装了数据库连接和事务, 让人难受的是, Cache 竟然也封装在 SqlMap 里。
大家知道, 我们可以通过以下方式获得 SqlMap 实例:
a. SqlMap map = Mapper.Instance(); // 单件模式, 返回唯一实例
b. DomSqlMapBuilder builder = new DomSqlMapBuilder();
SqlMap map = builder.Configure(); // 返回新的 SqlMap 实例
在单线程的环境下, a 没有问题, cache 也工作得很正常, 在多线程环境下, 因为 SqlMap 封装了 Connection, 如果并发调用同一个 SqlMap 实例访问数据库的时候, 会抛出以下异常:
IBatisNet.DataMapper.Exceptions.DataMapperException: SqlMap could not invoke OpenConnection(). A connection is already started. Call CloseConnection first.
在多线程环境下, b 就派上用场了, 可以在每个线程的开始用 b 创建一个 SqlMap 实例, 然后用这个 SqlMap 对数据库进行访问。但问题也就来了, 因为 cache 是封装在 SqlMap 里的, 每个 SqlMap 都会创建一份自己的 cache, 也就是说, iBatisNet 自带的 cache 机制没有用了。
真让人失望, 我现在只好自己用 Hashtable 实现简单的 cache 功能。
]关于返回DataTable的一点问题
对于IBatisnet执行查询返回DataTable,网上有很多代码,下面简单列出一下:
private
IDbCommand GetDbCommand(
string
statementName,
object
paramObject)
![](https://i-blog.csdnimg.cn/blog_migrate/34031c708bfe702fe82d01ff5c6593aa.gif)
{
IStatement statement = sqlMap.GetMappedStatement(statementName).Statement;
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
IMappedStatement mapStatement = sqlMap.GetMappedStatement(statementName);
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
IDalSession session = new SqlMapSession(sqlMap);
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
if (sqlMap.LocalSession != null)
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
{
session = sqlMap.LocalSession;
}
else
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
{
session = sqlMap.OpenConnection();
}
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
RequestScope request = statement.Sql.GetRequestScope(mapStatement, paramObject, session);
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
mapStatement.PreparedCommand.Create(request, session, statement, paramObject);
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
return request.IDbCommand;
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
}
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/34031c708bfe702fe82d01ff5c6593aa.gif)
/**/
/// <summary>
/// 通用的以DataTable的方式得到Select的结果(xml文件中参数要使用$标记的占位参数)
/// </summary>
/// <param name="statementName">语句ID</param>
/// <param name="paramObject">语句所需要的参数</param>
/// <returns>得到的DataTable</returns>
protected
DataTable ExecuteQueryForDataTable(
string
statementName,
object
paramObject)
![](https://i-blog.csdnimg.cn/blog_migrate/34031c708bfe702fe82d01ff5c6593aa.gif)
{
DataSet ds = new DataSet();
bool isSessionLocal = false;
IDalSession session = sqlMap.LocalSession;
if (session == null)
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
{
session = new SqlMapSession(sqlMap);
session.OpenConnection();
isSessionLocal = true;
}
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
IDbCommand cmd = GetDbCommand(statementName, paramObject);
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
try
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
{
cmd.Connection = session.Connection;
IDbDataAdapter adapter = session.CreateDataAdapter(cmd);
adapter.Fill(ds);
}
finally
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
{
if (isSessionLocal)
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
{
session.CloseConnection();
}
}
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
return ds.Tables[0];
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
}
理论上来说是没任何问题的,但前几天我做了有Output参数的存储过程来返回DataTable,如果用上面的ExecuteQueryForDataTable方法就会获得不到Output的参数,因为它在返回值的时候没有用到IBatisNet内部的方法了,所以上面的方法严谨的写法应该改成下面这样:
/**/
/// <summary>
/// 通用的以DataTable的方式得到Select的结果(xml文件中参数要使用$标记的占位参数)
/// </summary>
/// <param name="statementName">语句ID</param>
/// <param name="paramObject">语句所需要的参数</param>
/// <param name="htOutPutParameter)">Output参数值哈希表</param>
/// <returns>得到的DataTable</returns>
protected
DataTable ExecuteQueryForDataTable(
string
statementName,
object
paramObject,
out
Hashtable htOutPutParameter)
![](https://i-blog.csdnimg.cn/blog_migrate/34031c708bfe702fe82d01ff5c6593aa.gif)
{
DataSet ds = new DataSet();
bool isSessionLocal = false;
IDalSession session = sqlMap.LocalSession;
if (session == null)
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
{
session = new SqlMapSession(sqlMap);
session.OpenConnection();
isSessionLocal = true;
}
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
IDbCommand cmd = GetDbCommand(statementName, paramObject);
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
try
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
{
cmd.Connection = session.Connection;
IDbDataAdapter adapter = session.CreateDataAdapter(cmd);
adapter.Fill(ds);
}
finally
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
{
if (isSessionLocal)
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
{
session.CloseConnection();
}
}
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
foreach (IDataParameter parameter in cmd.Parameters)
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
{
if (parameter.Direction == ParameterDirection.Output)
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
{
htOutPutParameter[parameter.ParameterName] = parameter.Value;
}
}
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
return ds.Tables[0];
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
}