吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 1554|回复: 22
收起左侧

[已解决] C# 操作SQLite,如何在开启insert事务后还能执行不用事务的select语句?

[复制链接]
getstr88 发表于 2022-7-5 07:31
本帖最后由 getstr88 于 2022-7-5 10:13 编辑

客户的需求是:
有一批username,要合并到新的数据库中


要求,插入时为了速度,要用事务,每100条数据commit一次。但每插入一条时,要先判断,如果新数据库中有这个username了,那本程序停止掉。


所以,我就开了个事务用于insert,本想每从旧数据库读一个数据,然后用非事务的sqliteCommand在新数据库中select,如果没有,就向事务中加一个insert,如果已经有了,就把之前事务调教掉,然后停止程序


但实测发现,已经开启事务后,就不允许非事务的sqliteCommand执行,会抛出异常




然后我给客户提了几个方案,都不被允许。。那么我还有什么其他办法?


我被否决的方案:
1、开2个sqliteConnection,一个开启事务进行inset,另一个执行普通select
2、先select验证一批不存在于新数据库,然后再用事务insert。然后再select验证一批不存在于新数据库再用事务insert……
这个也被客户否决了,说,验1条插一条,不能先select一批在做

所以,想不出还有其他什么办法,满足客户这2点要求了
另外,3楼我还有一个问题(附代码),也请大佬们解答下

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

dlxg 发表于 2022-7-5 08:28
第2完全没看懂。。。。
 楼主| getstr88 发表于 2022-7-5 08:29
另外,还要请教,虽然方案1直接被客户否决了

因为我之前没用过SQLite,还是想测试下,是否支持多个Connection

本以为下面测试代码应该行得通,结果报错为:SQLite Error 5: 'database is locked
(可以确保其他程序没有使用的)

也请教下这样的原因:

[C#] 纯文本查看 复制代码
using Microsoft.Data.Sqlite;

namespace TestDB
{
    public partial class Form2 : Form
    {
        public Form2()
        {
            InitializeComponent();
        }

        private void Form2_Load(object sender, EventArgs e)
        {
            SqliteConnection connectionForSelect = new SqliteConnection(@"DataSource=D:\111.db");
            connectionForSelect.Open();

            SqliteConnection connectionForTransaction = new SqliteConnection(@"DataSource=D:\111.db");
            connectionForTransaction.Open();

            /**
             * 新建名为my_test_table的表格,它有一列为id,然后插入一行数据3
             */
            SqliteCommand createTableCmd = connectionForSelect.CreateCommand();
            createTableCmd.CommandText = "DROP TABLE IF EXISTS 'my_test_table'";
            createTableCmd.ExecuteNonQuery();

            createTableCmd.CommandText = "CREATE TABLE my_test_table(id integer primary key)";
            createTableCmd.ExecuteNonQuery();

            createTableCmd.CommandText = "INSERT INTO my_test_table(id) values(3)";
            createTableCmd.ExecuteNonQuery();

            SqliteCommand selectDataCmd = connectionForSelect.CreateCommand();
            using (SqliteTransaction transaction = connectionForTransaction.BeginTransaction())
            {
                int currentId = 0;
                while (true)
                {
                    selectDataCmd.CommandText = $"SELECT * from my_test_table where id={currentId}";
                    SqliteDataReader reader = selectDataCmd.ExecuteReader();
                    if (reader.HasRows == true)
                    {
                        // 遇到已存在的,则停止,并提交事务
                        transaction.Commit();
                        reader.Close();
                        break;
                    }
                    else
                    {
                        // 没有则插入
                        SqliteCommand insertCmd = connectionForTransaction.CreateCommand();
                        insertCmd.Transaction = transaction;
                        insertCmd.CommandText = $"INSERT INTO my_test_table(id) values({currentId})";
                        insertCmd.ExecuteNonQuery();
                    }

                    reader.Close();
                    currentId++;
                }
            }
            connectionForSelect.Close();
            connectionForTransaction.Close();
            SqliteConnection.ClearAllPools();
            MessageBox.Show("完毕");
        }
    }
}
 楼主| getstr88 发表于 2022-7-5 08:34
dlxg 发表于 2022-7-5 08:28
第2完全没看懂。。。。

就是说,既然不允许开启事务后再执行不用事务的SQL
那我就先从旧数据,比如取出50个数据,然后在新数据库select 50次,验证是不是已经有了

如果没有,则开启事务,将这50个用事务批量insert。然后关闭事务

就保证在事务开启时,不会select

但是客户不允许我这样“绕路”的方法
dlxg 发表于 2022-7-5 08:49
首先,我只会简单的sql操作,不会复杂的。
其次,提供个思路,不知道有没有用。
客户说的,每100条数据,commit一次,但每插入一条,要先判断是否存在。
这样的话,试着搞三个集合,集合A(要合并到数据库的username),集合B(确定查重后的username),集合C(已经存在的username),搞一个循环,判断集合A中的username是否在数据库中存在,如果存在,将该username放入集合C,如果不存在,将该username放入集合B,循环结束后,集合A应该=集合B+集合C。
然后循环写入集合B到数据库。
不知道这样是不是你需要的?

至于你贴出来的代码,你不能对同一个数据库打开两次,也就是在第一次打开后没有关闭的情况下,就打开第二次。
解决方法:可以尝试用进程。
 楼主| getstr88 发表于 2022-7-5 08:59
dlxg 发表于 2022-7-5 08:49
首先,我只会简单的sql操作,不会复杂的。
其次,提供个思路,不知道有没有用。
客户说的,每100条数据, ...

额。首先客户要求查一条验1条,你都搞集合了,难道不是select一批了?客户不允许

另外,不能对同一个数据库打开两次。really??? SQLite 我查了下,支持多个客户端同时连接,并发进行读。只是不能同时写

而我开两个connect,一个只select、另一个用事务写。这样也不行?
 楼主| getstr88 发表于 2022-7-5 09:16
dlxg 发表于 2022-7-5 08:49
首先,我只会简单的sql操作,不会复杂的。
其次,提供个思路,不知道有没有用。
客户说的,每100条数据, ...

我刚才试下。可以一个程序开多个Connection ,只要不是同时写就行。逐个用不同connection写是没有问题的

那么,是不是说sqltite开启事务后,也就不允许其他connection进行读了?但感觉没必要啊。其他的读又有什么影响呢
fightingmy 发表于 2022-7-5 09:21
插入时为了速度,要用事务,每100条数据commit一次。但每插入一条时,要先判断,如果新数据库中有这个username了,那本程序停止掉。


插入速度和事务有毛关系,奇葩需求
雨天晒太阳 发表于 2022-7-5 09:23
加锁吗,一次只允许一个请求访问,效率低了点
 楼主| getstr88 发表于 2022-7-5 09:33
fightingmy 发表于 2022-7-5 09:21
插入时为了速度,要用事务,每100条数据commit一次。但每插入一条时,要先判断,如果新数据库中有这个usern ...

????

这个我挺客户的。你可以试一下。插入1万条数据。用事务我这里0.02秒,不用事务25秒。多少倍的差距。。

您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-25 10:40

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表