首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >SQLite:数据库被锁定了C#

SQLite:数据库被锁定了C#
EN

Stack Overflow用户
提问于 2022-04-25 12:29:26
回答 3查看 360关注 0票数 0

编辑!这是错误https://www.youtube.com/watch?v=_mJ3o3ykQrw的视频

在我的数据库处理程序类中创建了一个名为AddAttendance的方法。我可以从其他类访问它,因为它是静态的。下面是代码:

代码语言:javascript
复制
 public static void AddAttendance(string ID, string DateTime, string Action, string Session)
        {
            SQLiteConnection sqlite_conn = new SQLiteConnection("Data Source = " + database + "; Version = 3; New = True; Compress = True;");
            try
            {
                sqlite_conn.Open();
                SQLiteCommand sqlite_cmd = sqlite_conn.CreateCommand();
                sqlite_cmd.CommandText = "INSERT INTO AttendanceLog (UserID, DateTime, Action, Session) VALUES (" +
                    "'" + ID + "', '" + DateTime + "', '" + Action + "', '" + Session + "');";
                sqlite_cmd.ExecuteNonQuery();

                sqlite_conn.Close();

            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
            sqlite_conn.Close();
        }

此代码仅由绑定到一个按钮的对话框表单访问:

代码语言:javascript
复制
 private void buttonAccept_Click(object sender, EventArgs e)
        {

            if (textBoxID.Text.Length == 0 || textBoxTimeDate.Text.Length == 0)
            {
                MessageBox.Show("ID or Time and Date cannot be empty!", "Missing field", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            if (buttonAccept.Text.Equals("Accept"))
            {
                buttonAccept.Text = "Confirm!";
                return;
            }
            DatabaseHandles.AddAttendance(textBoxID.Text, textBoxTimeDate.Text, comboBoxAction.Text, comboBoxSession.Text);
            MessageBox.Show("Record added!", "Success", MessageBoxButtons.OK, MessageBoxIcon.Information);
            DialogResult = DialogResult.OK;
        }

如果im从我的表单Kiosk模式访问它,它工作得很好,但是如果我从其他任何地方访问它,它会报告数据库是锁定的。

奇怪的是,当我先进入我的Kiosk模式,然后到另一个地方,它工作得很好。

我不知道我错过了什么。这里使用的代码与调用表单时使用的代码相同:

代码语言:javascript
复制
 AttendanceInsert ai = new AttendanceInsert();
                ai.ShowDialog(); 
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2022-04-25 17:28:24

罪魁祸首是读取器,虽然我关闭了与using参数的所有连接,但我忘记关闭我使用的所有读取器,我也应该在这里使用using,但您知道了。数据库被锁定,读取器未关闭。

代码语言:javascript
复制
 public static void LoadScannedUser(string ID)
        {
            string sql = "SELECT * FROM Users WHERE ID = '" + ID + "'";

            using (var conn = new SQLiteConnection(ConnectionString))
            {
                using (var cmd = conn.CreateCommand())
                {


                    try
                    {
                        cmd.CommandText = sql;
                        conn.Open();
                        SQLiteDataReader reader = cmd.ExecuteReader();
                        while (reader.Read())
                        {
                            scannedUser.ID = reader.GetString(1);
                            scannedUser.Password = reader.GetString(2);
                            scannedUser.PPicture = Cryptorizer.Base64ToImage(reader.GetString(3));
                            scannedUser.FName = reader.GetString(4);
                            scannedUser.MName = reader.GetString(5);
                            scannedUser.LName = reader.GetString(6);
                            scannedUser.Agency = reader.GetString(7);
                            scannedUser.Position = reader.GetString(8);
                        }
                        reader.Close();
                    }

                    catch (Exception ex)
                    {
                        Console.WriteLine(ex.Message);
                    }

                }
            }

        }
票数 1
EN

Stack Overflow用户

发布于 2022-04-25 13:38:51

我不知道它是否能解决你的问题,但没有理由不做好:

代码语言:javascript
复制
public static void AddAttendance(string id, string datetime, string action, string session)
{
    try
    {
        using (var sqlite_conn = new SQLiteConnection("Data Source = " + database + "; Version = 3; New = True; Compress = True;")
        {
            sqlite_conn.Open();
            using (var sqlite_cmd = sqlite_conn.CreateCommand())
            { 
                sqlite_cmd.CommandText = "INSERT INTO AttendanceLog (UserID, DateTime, Action, Session) VALUES (@Id, @DateTime, @Action, @Session);";
                sqlite_cmd.Parameters.Add(new SqlParameter("@Id", SqlDbType.NVarChar)).Value = id;
                sqlite_cmd.Parameters.Add(new SqlParameter("DateTime", SqlDbType.NVarChar)).Value = datetime;
                sqlite_cmd.Parameters.Add(new SqlParameter("Action", SqlDbType.NVarChar)).Value = action;
                sqlite_cmd.Parameters.Add(new SqlParameter("Session", SqlDbType.NVarChar)).Value = session;
                sqlite_cmd.ExecuteNonQuery();
            }
        }
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);
    }
}

通过这种方式,您的连接和SqlCommand将被关闭和处理,并且您正在使用参数化查询,这将阻止SQL注入。如果数据库列不是NVarChar,则需要对其进行更改。还可以将长度添加到参数定义中。

票数 0
EN

Stack Overflow用户

发布于 2022-04-25 14:46:00

此锁定问题是由于试图重用数据库连接而产生的。ADO.Net有一个名为连接池的功能,这样在整个应用程序中重用相同的conenction对象是一个非常糟糕的想法,它实际上会使事情变得更慢,而且还会导致类似的锁定问题。

相反,您确实应该为大多数查询创建一个全新的连接对象,在运行查询之前立即打开连接,并在查询完成后立即释放对象。实现这一目标的最简单方法是通过一个using块:

代码语言:javascript
复制
private static string ConnectionString {get;} = "Data Source = " + database + "; Version = 3; New = True; Compress = True;"

public static void AddAttendance(string ID, string dateTime, string Action, string Session)
{
    string sql = "INSERT INTO AttendanceLog (UserID, DateTime, Action, Session) VALUES (@id, @time, @action, @session);";

    using (var conn = new SQLiteConnection(ConnectionString))
    using (var cmd = new SQLiteCommand(sql, conn))
    {
        cmd.Parameters.AddWithValue("@id", ID);
        // Note the DateTime format. It's necessary to store date values in this way in order to preserve cardinality and allow indexes and date math to function properly.
        // Better DB platforms would have a DateTime type to use instead
        cmd.Parameters.AddWithValue("@time", DateTime.Parse(dateTime).ToString("yyyy-MM-dd HH:mm:ss"));
        cmd.Parameters.AddWithValue("@action", Action);
        cmd.Parameters.AddWithValue("@session", session);

        try
        {
            conn.Open();
            cmd.ExecuteNonQuery();
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
    }
}

using块将保证连接正确关闭,即使在可能错过sqllite_conn.Close()调用的情况下也是如此。

事情是这样的:修复这个查询是不够的!

必须修复查询的所有才能依赖using块,否则仍有锁定的风险。锁定问题不会显示在实际导致锁定的查询上,但是在数据库被锁定后运行的查询。

在这种情况下,看起来锁定问题可能发生在显示网格的位置。网格查询运行很有趣,不会显示任何错误,但不会释放锁,因此您将得到试图添加记录的错误,因为这是之后的下一个查询。

参数也是如此。仅使用查询参数而不是字符串连接是不够的。您必须在每次将数据替换为SQL字符串时(在EveryQuery中)执行此操作。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71999560

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档