DELPHI盒子
!实时搜索: 盒子论坛 | 注册用户 | 修改信息 | 退出
检举帖 | 全文检索 | 关闭广告 | 捐赠
技术论坛
 用户名
 密  码
自动登陆(30天有效)
忘了密码
≡技术区≡
DELPHI技术
lazarus/fpc/Free Pascal
移动应用开发
Web应用开发
数据库专区
报表专区
网络通讯
开源项目
论坛精华贴
≡发布区≡
发布代码
发布控件
文档资料
经典工具
≡事务区≡
网站意见
盒子之家
招聘应聘
信息交换
论坛信息
最新加入: jsuguo
今日帖子: 31
在线用户: 18
导航: 论坛 -> 数据库专区 斑竹:liumazi,waterstone  
作者:
男 glwang (glwang) ★☆☆☆☆ -
盒子活跃会员
2019/4/11 9:00:01
标题:
求助:delphi使用unidac批量insert into插入sqlite数据库记录出现database is locked错误! 浏览:2074
加入我的收藏
楼主: 就是写了一个for循环插入数据:
for j := 0 to Num - 1 do  
      begin
         ..........
         UniQuery1.SQL.Add('insert into .......
         UniQuery1.ExecSQL;
         .........
      end;  
错误现象:循环插入10条以内的数据,都不会出错,循环插入48条以上数据就出现:database is locked错误!
----------------------------------------------
作者:
男 blueflag (昆了) ★☆☆☆☆ -
盒子活跃会员
2019/4/11 9:03:34
1楼: 先拼接,再一次执行~ 不要一条一执行~
类似这样:
  for j := 0 to Num - 1 do  
      begin
         ..........
         UniQuery1.SQL.Add('insert into .......
        
         .........
      end;  
    UniQuery1.ExecSQL;
----------------------------------------------
-
作者:
男 glwang (glwang) ★☆☆☆☆ -
盒子活跃会员
2019/4/11 14:36:02
2楼: 1楼的方案试了,还是报错:database is locked!百度了一下:好像是sqlite数据库的先天设计缺陷,如何解决?
----------------------------------------------
作者:
男 wang_80919 (Flying Wang) ★☆☆☆☆ -
普通会员
2019/4/11 15:11:33
3楼: 好奇怪,楼主的 for 难道和我们的不同吗?
我们的 for 是单线程的。代码是顺序执行的。不可能产生 锁定。
----------------------------------------------
(C)(P)Flying Wang
作者:
男 glwang (glwang) ★☆☆☆☆ -
盒子活跃会员
2019/4/11 15:18:24
4楼: CSDN百度了一下:C# 的,还是一头雾水,根据3楼的提示,或许是我对这个表在其他窗体已经Active Open了,导致出错?
SQLite 是一个软件库,实现了自给自足的、无服务器的、零配置的、事务性的 SQL 数据库引擎。SQLite允许多个进程/线程同时进行读操作,但在同一时刻只允许一个线程进行写操作。SQLite在进行写操作时,数据库文件会被锁定,此时任何其他的读/写操作都会被阻塞,如果阻塞超过5秒钟(默认是5秒,可通过重新编译SQLite进行修改),就会抛出描述为“database is locked”的异常。

出现上述现象的原因是SQLite只支持库级锁,不支持并发执行写操作,即使是不同的表,同一时刻也只能进行一个写操作。例如,事务T1在表A新插入一条数据,事务T2在表B中更新一条已存在的数据,这两个操作是不能同时进行的,只能顺序进行。

SQLite尽量延迟了申请X锁,直到数据块真正写盘时才申请X锁,再加上被阻塞的操作有等待时间,所以当SQLite作为客户端嵌入数据库被使用时时,一般情况下不会抛出“database is locked”的异常。但是,在高并发的环境下,还是很有可能抛出异常的。避免这种异常的最简单有效的方法,就是在进行写操作时实现互斥锁,并保证写操作按顺序执行。
---------- 
作者:time式 
来源:CSDN 
原文:https://blog.csdn.net/WZh0316/article/details/81188451 
版权声明:本文为博主原创文章,转载请附上博文链接!
----------------------------------------------
作者:
男 glwang (glwang) ★☆☆☆☆ -
盒子活跃会员
2019/4/11 15:20:11
5楼: 这边先说一下database is locked产生的原因:sqlite同一时间只能进行一个写操作,当同时有两个写操作的时候,后执行的只能先等待,如果等待时间超过5秒,就会产生这种错误.同样一个文件正在写入,重复打开数据库操作更容易导致这种问题的发生。

那首先,得避免重复打开数据库,首先引入单例方法与SQLiteOpenHelper类:
---------- 
作者:LoveWyf_ 
来源:CSDN 
原文:https://blog.csdn.net/qq_25412055/article/details/52414420 
版权声明:本文为博主原创文章,转载请附上博文链接!
----------------------------------------------
作者:
男 wang_80919 (Flying Wang) ★☆☆☆☆ -
普通会员
2019/4/11 15:54:56
6楼: 问题在于,我们的 for 不可能同时的。所以肯定是 一个写操作。不可能超过1。
----------------------------------------------
(C)(P)Flying Wang
作者:
男 glwang (glwang) ★☆☆☆☆ -
盒子活跃会员
2019/4/11 16:18:52
7楼: 比如我 for 了6次以内基本没有问题,都能插入记录,num数值如果是超过10例如:48,就只能成功插入几条记录然后就报错:database is locked

我后来在for循环里面加了一个:sleep(100);稍微好点,能支持插入10多条,但是还是达不到项目要求的48条连续插入记录的要求。
for j := 0 to Num - 1 do  
      begin
         ..........
         UniQuery1.SQL.Add('insert into .......
         UniQuery1.ExecSQL;
         sleep(100);
         .........
      end;
----------------------------------------------
作者:
男 sail2000 (小帆工作室) ★☆☆☆☆ -
盒子活跃会员
2019/4/11 16:41:18
8楼: 我写的 sqlite 数据库每天都要用事务更新近 20万条数据,没这事啊

for j := 0 to Num - 1 do  
      begin
         ..........
         UniQuery1.SQL.Add('insert into .......
         UniQuery1.ExecSQL;<-------别再在这里搞
         sleep(100);
         .........
      end;

//用事务
...StartTransaction;
...Add('insert into tab (col) VALUES (:col);
for ....
.Params[0].AsString := ...
 Query.ExecSQL;
end;
....Conn.Commit;
...EndTransaction;<---不知道 uniDAC 有没有这个
----------------------------------------------
delphi 是兴趣,和工作无关,即使它倒闭。又不靠它 delphi 吃饭,怕甚?
作者:
男 glwang (glwang) ★☆☆☆☆ -
盒子活跃会员
2019/4/11 17:12:44
9楼: 感谢8楼方案,我的代码乱,懒得改了,我又百度了一下:sqlite3给的函数sqlite3_busy_timeout来实现了延时(时间的延时)
//sqlite3_busy_timeout实际上是封装了sqlite3_busy_handler,这里面sqlite3_busy_handler调用的是个固定的回调,通过这个回调实现了固定时间的延时.

sqlite3_busy_timeout(db, 30*1000); //最长等待30m ,也相当于延时
sqlite3_exec(db , sqlcmd , NULL, NULL, &zErrMsg );    
sqlite3_close(db);    
----------
详细看了一下uniDAC文档,找到一个属性:BusyTimeout 可以调用:sqlite3_busy_timeout
代码如下:
 UniConnection1.SpecificOptions.Values['BusyTimeout'] := '10000';
结论:经测试问题解决;
----------------------------------------------
作者:
男 hnxxcxg (咏南中间件) ★☆☆☆☆ -
盒子活跃会员
2019/4/11 18:27:23
10楼: SQLITE是单连接数据库,当已经有一个连接,试图再连,就会报:database is locked
这个不是先天缺陷,也不是BUG,这是它的设计初衷——只支持一个数据库连接,你可以理解为它是独占的。
----------------------------------------------
中间件QQ群: 92449782 博客: http://www.cnblogs.com/hnxxcxg/
作者:
男 earthsbest (全能中间件) ▲▲▲▲△ -
普通会员
2019/4/11 19:08:03
11楼: 用 FireDAC 1 秒插入SQLite 几万条很轻松。
----------------------------------------------
Delphi4Linux Delphi三层/FireDAC 技术群:734515869 http://www.cnblogs.com/rtcmw
作者:
男 earthsbest (全能中间件) ▲▲▲▲△ -
普通会员
2019/4/11 19:40:08
12楼: 从没用过这么少的字段,随手写了demo测试下,发现速度快到让人窒息。
此帖子包含附件:
PNG 图像
大小:40.2K
----------------------------------------------
Delphi4Linux Delphi三层/FireDAC 技术群:734515869 http://www.cnblogs.com/rtcmw
作者:
男 glwang (glwang) ★☆☆☆☆ -
盒子活跃会员
2019/4/12 9:07:38
13楼: 10楼:“SQLITE是单连接数据库,当已经有一个连接,试图再连,就会报:database is locked”
我估计我的程序就是这个原因,由于数据库表业务关联很乱,窗体多,一时理不清。。。,使用sqlite3_busy_timeout虽然可以解决报错问题,但会导致插入大量记录的时候耗时太多
----------------------------------------------
信息
登陆以后才能回复
Copyright © 2CCC.Com 盒子论坛 v3.0.1 版权所有 页面执行70.3125毫秒 RSS