使用dapper与sqlite,查询方法抛出了null参考异常

发布于 2025-02-08 09:19:22 字数 1401 浏览 1 评论 0原文

测试环境:

- 框架版本:.net 6

-Microsoft.data.sqlite,版本:6.0.6-

dapper,版本:2.0.123

Q:当只有一个查询时执行,没有问题。当执行多个并发查询时发生问题。

(参考:当我在本机ado.net而不是dapper(conn.query)中编写代码时,没有问题!)

这是一个简单的演示可以很容易地重现问题。

using System.Data;
using Dapper;
using Microsoft.Data.Sqlite;

// SQLite db file
string connStr = $"Data Source={AppDomain.CurrentDomain.BaseDirectory}test.db";

// SQLite connection (Share the singleton connection) 
using SqliteConnection conn = new SqliteConnection(connStr);
conn.Open();
 
bool existError = false;
while (true)
{
    if (existError == true)
    {
        break;
    }

    // Perform concurrent reads
    Parallel.For(0, 100, index =>
    {
        try
        {
            // Test SQL
            string sql_test = " select * from T_Account where AccountId='ab001' ";

            // Perform query data (May throw a null reference exception )
            var t = conn.Query(sql_test);
        }
        catch (Exception ex)
        {
            existError = true;

            // Test output: Object reference not set to an instance of an object.
            Console.WriteLine($"Read error ({index}): {ex.Message}");
        }
    });

    Console.WriteLine($"{DateTime.Now}-------- split line --------");
}

整个项目一直在使用Dapper,我想知道问题在哪里,我应该如何解决?

Testing environment:

-- Framework version: .NET 6

-- Microsoft.Data.Sqlite, version: 6.0.6

-- Dapper, version: 2.0.123

Q: When only one query is executed, there is no problem. Problems occur when multiple concurrent queries are executed.

(Reference: When I write code in native ADO.NET instead of Dapper(conn.Query), there is no problem!)

Here is a simple demo that can reproduce the problem very easily.

using System.Data;
using Dapper;
using Microsoft.Data.Sqlite;

// SQLite db file
string connStr = 
quot;Data Source={AppDomain.CurrentDomain.BaseDirectory}test.db";

// SQLite connection (Share the singleton connection) 
using SqliteConnection conn = new SqliteConnection(connStr);
conn.Open();
 
bool existError = false;
while (true)
{
    if (existError == true)
    {
        break;
    }

    // Perform concurrent reads
    Parallel.For(0, 100, index =>
    {
        try
        {
            // Test SQL
            string sql_test = " select * from T_Account where AccountId='ab001' ";

            // Perform query data (May throw a null reference exception )
            var t = conn.Query(sql_test);
        }
        catch (Exception ex)
        {
            existError = true;

            // Test output: Object reference not set to an instance of an object.
            Console.WriteLine(
quot;Read error ({index}): {ex.Message}");
        }
    });

    Console.WriteLine(
quot;{DateTime.Now}-------- split line --------");
}

The whole project has been using Dapper, I want to know where the problem is, how should I solve it?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

神魇的王 2025-02-15 09:19:22

您可能会认为重复使用连接是一个超级好主意,但事实并非如此。已经有一个内置的ADO连接池,它比我们想出的任何内容都要高得多。我试图使用另一个SQLITE数据库和查询来运行您的代码,在第6或7次迭代中,我得到了null参考异常。然后,我这样更改了您的代码:

// Perform concurrent reads
Parallel.For(0, 100, index =>
{
    try
    {
        // These two lines moved inside the loop
        using SqliteConnection conn = new SqliteConnection(connStr);
        conn.Open();

        // Test SQL
        string sql_test = " select * from T_Account where AccountId='ab001' ";

        // Perform query data (May throw a null reference exception )
        var t = conn.Query(sql_test);
    }
    catch (Exception ex)
    {
        existError = true;

        // Test output: Object reference not set to an instance of an object.
        Console.WriteLine($"Read error ({index}): {ex.Message}");
    }
});

并且代码可以按预期进行。最佳实践是在使用语句中创建数据库连接,并在完成后立即将其处置。
由于我还没有看到您使用RAW ADO.NET的代码,因此我无法说出为什么有效。

You might think that it's a super good idea to reuse the connection, but it isn't. There already is a connection pool built-in to ADO, and it's far more efficient than anything we can come up with. I tried to run your code, obviously with another sqlite database and query, and on the 6th or 7th iteration I got the null reference exception. Then I changed your code like this:

// Perform concurrent reads
Parallel.For(0, 100, index =>
{
    try
    {
        // These two lines moved inside the loop
        using SqliteConnection conn = new SqliteConnection(connStr);
        conn.Open();

        // Test SQL
        string sql_test = " select * from T_Account where AccountId='ab001' ";

        // Perform query data (May throw a null reference exception )
        var t = conn.Query(sql_test);
    }
    catch (Exception ex)
    {
        existError = true;

        // Test output: Object reference not set to an instance of an object.
        Console.WriteLine(
quot;Read error ({index}): {ex.Message}");
    }
});

And the code can go on and on as expected. Best practice is to create the database connection in a using statement and have it disposed as soon as you are done with it.
Since I haven't seen your code with raw ADO.NET, I can't tell why that works.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文