导航
  • 主页
  • C#综合技术
  • C#互联网桌面应用
  • AppLauncher
  • WinForm
  • WPF
  • 问答

问题似乎是随机的。请问哪里有问题?又该如何捕获错误?

leon51 2019-07-09 03:54:06
以下代码一般可以返回正确的DataTable,但是有时、在个别机器上返回空的DataTable,重启程序或换一台电脑又ok了。数据是肯定存在的。因为问题似乎是随机的,不知道怎么调试。请问哪里有问题?又该如何捕获错误?谢谢

	private void Test()
{
string sql = $@"SELECT * FROM tab WHERE name = 'ABC'";
string connectString = "...";
this.Cursor = Cursors.WaitCursor;
mrpSteps = OracleHelper.GetDataTable(sql, connectString); //此处有时、在有的机器上返回空的DataTable,数据是肯定存在的
}

public static class OracleHelper
{
public static DataTable GetDataTable(string sql, string connectionString)
{
DataTable dataTable = new DataTable();
using (OracleDataAdapter dataAdapter = new OracleDataAdapter())
{
dataAdapter.SelectCommand = new OracleCommand
{
Connection = new OracleConnection(connectionString),
CommandType = CommandType.Text,
CommandText = sql
};
dataAdapter.Fill(dataTable);
}
return dataTable;
}
}
...全文
2100 1 收藏 49
写回复
49 条回复
切换为时间正序
请发表友善的回复…
发表回复
引用 48 楼 leon51 的回复:
我现在改用我们sql server中的数据,虽然麻烦了一点, 这个帖子暂不结,跟着大神们学知识
??改存储过程了吗?
回复
leon51 2019-07-12
我现在改用我们sql server中的数据,虽然麻烦了一点, 这个帖子暂不结,跟着大神们学知识
回复
FainSheeg 2019-07-12
另外楼主using还是using connection比较好,connection才是最需要释放的资源。或者代码里面加个Dispose
回复
FainSheeg 2019-07-12
我也出现过这个情况,也是很长时间找不到问题所在,后来,在Helper代码里面,给DataTable套上DataSet就再没出现过了,也不知道是什么原因,还是有什么BUG。

public static DataTable GetDataTable(string sql, string connectionString)
{
DataTable dataTable = new DataTable();
DataSet dataSet=new DataSet();
using (OracleDataAdapter dataAdapter = new OracleDataAdapter())
{
dataAdapter.SelectCommand = new OracleCommand
{
Connection = new OracleConnection(connectionString),
CommandType = CommandType.Text,
CommandText = sql
};
dataAdapter.Fill(dataSet);
If(dataSet.Tables.Count > 0){
dataTable = dataSet.Tables(0);
}
}
return dataTable;
}
回复
leon51 2019-07-12
引用 49 楼 胖叔叔写代码 的回复:
[quote=引用 48 楼 leon51 的回复:] 我现在改用我们sql server中的数据,虽然麻烦了一点, 这个帖子暂不结,跟着大神们学知识
??改存储过程了吗?[/quote] 没有,我极少用存储过程,因为没有权限创建存储过程
回复
XBodhi. 2019-07-11
参考。https://blog.csdn.net/qiaohuyue/article/details/95459438
回复
XBodhi. 2019-07-11
https://docs.microsoft.com/zh-cn/dotnet/framework/data/adonet/sql-server-connection-pooling
回复
XBodhi. 2019-07-11
我也遇到这个问题,因为走入了一个误区。
首先单线程的情况下 Static 方式没有问题,

如果高并发和多线程需要使用连接池技术,同时 Connection 需要 多实例体现。

请参考

https://docs.microsoft.com/en-us/dotnet/framework/data/adonet/sql-server-connection-pooling

和 sql server 其实一样。
回复
另外说一下,你OracleDataAdapter的自动回收会不会回收new OracleConnection(connectionString)这件事建议你还是看看调试快照。
回复
不记得谁说过,using就是简化的try 语句,然后百度了一下博客那边就有这样的文章: https://blog.csdn.net/weixin_33943347/article/details/90663853 所以我推测是using中间部分出现异常导致直接返回了空的数据。 没测试,中间部分的异常也需要按照楼上的代码捕获。
回复
wanghui0380 2019-07-11
引用 37 楼 吹风的兔子 的回复:
而且,如果没记错的话,楼主的 代码,是用于 如下场景: > 从数据库 得到一个 DataTable,不断开连接。 > 程序修改 DataTable 后,调用 DataTable.AcceptChange() 函数,数据自动同步到数据库。 > 不需要你写一行 Update Insert Delete 代码 —— DataTable.AcceptChange() 会自动将数据 同步回数据库。 这是一个非常牛逼的功能,而这个功能的牛逼 就在于 DbDataAdapter 对象。 参考楼主的代码 dataAdapter.SelectCommand, DbDataAdapter 有 SelectCommand,还有 UpdateCommand .... —————————————————————————— 但是,这个非常牛逼的功能 却很少有人在使用了: > 因为这套机制,获取>修改>自动回写数据库 —— 必然要保持 数据库连接,OracleConnection 是不允许释放的。 【所以楼主的代码 是 直接 new OracleConnection() 但却没有考虑释放的问题】 > 很明显,楼主的这套代码 肯定也是 从某位 大牛或书本那里 借鉴的 —— 这段代码更适用于 【获取>修改>自动回写数据库】 这套模式,但大牛没有在代码中 注释出来。 > 牛逼的功能 带来的 资源长时间占用 是一方面。 楼主只想 【获取数据】,但是却为 【>修改>自动回写数据库】 这两个环节 额外占用了资源。 > 而且在实战中,【获取>修改>自动回写数据库】 这套牛逼的 【自动回写数据库】 其实很鸡肋,如果你的 sql 脚本查询特别复杂,微软底层再牛逼 也不能回写到 数据库。 久而久之,我们用 数据库查询 DataTable DataSet 也就不用 楼主的那套代码了。 取而代之的都是 数据库资源 用完即释放 的模式,都加上 using 语法。
又得往回拽了,无论是dt,ds, DbDataAdapter,有或是EF的跟踪都是离线的,除了dataread是在线的,其他都是离线的,他根本就不必保持open,他内部有行状态跟踪,也就是拿到数据就可以断开,更新的时候连接,利用行状态去构造sql,此时在open都不迟
回复
吹风的兔子 2019-07-11
而且,如果没记错的话,楼主的 代码,是用于 如下场景: > 从数据库 得到一个 DataTable,不断开连接。 > 程序修改 DataTable 后,调用 DataTable.AcceptChange() 函数,数据自动同步到数据库。 > 不需要你写一行 Update Insert Delete 代码 —— DataTable.AcceptChange() 会自动将数据 同步回数据库。 这是一个非常牛逼的功能,而这个功能的牛逼 就在于 DbDataAdapter 对象。 参考楼主的代码 dataAdapter.SelectCommand, DbDataAdapter 有 SelectCommand,还有 UpdateCommand .... —————————————————————————— 但是,这个非常牛逼的功能 却很少有人在使用了: > 因为这套机制,获取>修改>自动回写数据库 —— 必然要保持 数据库连接,OracleConnection 是不允许释放的。 【所以楼主的代码 是 直接 new OracleConnection() 但却没有考虑释放的问题】 > 很明显,楼主的这套代码 肯定也是 从某位 大牛或书本那里 借鉴的 —— 这段代码更适用于 【获取>修改>自动回写数据库】 这套模式,但大牛没有在代码中 注释出来。 > 牛逼的功能 带来的 资源长时间占用 是一方面。 楼主只想 【获取数据】,但是却为 【>修改>自动回写数据库】 这两个环节 额外占用了资源。 > 而且在实战中,【获取>修改>自动回写数据库】 这套牛逼的 【自动回写数据库】 其实很鸡肋,如果你的 sql 脚本查询特别复杂,微软底层再牛逼 也不能回写到 数据库。 久而久之,我们用 数据库查询 DataTable DataSet 也就不用 楼主的那套代码了。 取而代之的都是 数据库资源 用完即释放 的模式,都加上 using 语法。
回复
吹风的兔子 2019-07-11
说两点: > 楼主用的是 Oracle.ManagedDataAccess.dll 还是 Oracle.DataAccess.dll ?? 【前者一般很稳定,后者总会有各种诡异问题】 > 我这边 获取 DataTable 的代码是酱紫的,楼主可以参考一下:


DataTable dataTable = new DataTable();
using (OracleConnection conn = new OracleConnection(connString))
{
    conn.Open();
    using (OracleCommand cmd = conn.CreateCommand())
    {
        cmd.CommandTimeout = int.MaxValue;
        cmd.CommandText = sql;
        using (OracleDataAdapter adapter = new OracleDataAdapter(cmd))
        {
            adapter.Fill(dataTable);
        }
     }
}

return dataTable;


注意看,楼主的代码 虽然 new OracleConnection,但却没有 释放这个 OracleConnection —— 不手动Dispose,就得等好久之后 GC回收时 可能会回收这个 OracleConnection
回复
xiaoxiangqing 2019-07-11
返回空的数据,记录一下日志
回复
leon51 2019-07-11
引用 36 楼 吹风的兔子 的回复:
说两点:
> 楼主用的是 Oracle.ManagedDataAccess.dll 还是 Oracle.DataAccess.dll ?? 【前者一般很稳定,后者总会有各种诡异问题】
> 我这边 获取 DataTable 的代码是酱紫的,楼主可以参考一下:



DataTable dataTable = new DataTable();
using (OracleConnection conn = new OracleConnection(connString))
{
conn.Open();
using (OracleCommand cmd = conn.CreateCommand())
{
cmd.CommandTimeout = int.MaxValue;
cmd.CommandText = sql;
using (OracleDataAdapter adapter = new OracleDataAdapter(cmd))
{
adapter.Fill(dataTable);
}
}
}

return dataTable;




注意看,楼主的代码 虽然 new OracleConnection,但却没有 释放这个 OracleConnection —— 不手动Dispose,就得等好久之后 GC回收时 可能会回收这个 OracleConnection


真不幸,我用的恰好是OracleClient.dll,就是微软提供的已过时的,另外using不是自动释放资源么
回复
JasonShih 2019-07-11
引用 33 楼 leon51 的回复:
[quote=引用 32 楼 JasonShih 的回复:]
问题可能出在:
1. ConnectionString指向了不同的数据库,首先检查排除
2. sql逻辑有问题,比如where子句的限制条件,此时满足,彼时不满足。可以先写成最简单的语句比如select top 1 * from tb,以缩小范围,隔离问题。
3. 以上都不是,考虑是否存在command执行超时,可以采用楼上捕获异常的方法查看,也可尝试将OracleCommand实例的CommandTimeout设置成较大的数值试试看。

1,连接字符串是只读的
2,sql确实没有问题,并且PLSQL Developer始终可以得到正确的结果集
3,很快就执行结束,不像是超时,超时理应会有错误消息,不管如何我还是设置CommandTimeout看看。你说“捕获异常”怎么做?我在using块中间加了try...catch,但并没有捕获任何异常,是下面的写法有问题吗?
        public static DataTable GetDataTable(string sql, string connectionString)
{
DataTable dataTable = new DataTable();
using (OracleDataAdapter dataAdapter = new OracleDataAdapter())
{
try
{
dataAdapter.SelectCommand = new OracleCommand
{
Connection = new OracleConnection(connectionString),
CommandType = CommandType.Text,

CommandText = sql
};
dataAdapter.Fill(dataTable);
}
catch (OracleException ex)
{
MessageBox.Show("出错了,请将此画面抓图发给管理员\n" + sql + "\n" + ex.Message, "错误");
}
catch (Exception ex)
{
MessageBox.Show("出错了,请将此画面抓图发给管理员\n" + sql + "\n" + ex.Message, "错误");
}
}
return dataTable;
}



[/quote]

如果确实没有捕获到异常,那么更倾向于sql有问题,可否试将sql换成,select GETDATE(),看是否每次都能获得时间,加以验证。

回复
陳嘉村 2019-07-10
真有用,我也碰到相同問題,我再來試試看
回复
足球中国 2019-07-10
能确定你发在这里的测试代码会出现这个问题???
回复
wbzlld 2019-07-10
可能是指向了不同的数据库
回复
正怒月神 2019-07-10
引用 25 楼 leon51 的回复:
[quote=引用 24 楼 leon51 的回复:] [quote=引用 21 楼 正怒月神 的回复:] 那么在问问其他问题, 有异常处理吗?
我以为有,但实际并没有,所以我现在加了try...catch观察一下[/quote] 我在using中间加了一个try...catch,然而,并没有什么用[/quote] try catch中没有任何日志是吗?数据确保存在,就有点奇怪了。
回复
发动态
发帖子
C#
创建于2007-09-28

10.4w+

社区成员

.NET技术 C#
申请成为版主
社区公告

全世界最好的语言,没有之一.