Coder Social home page Coder Social logo

Comments (83)

Vincentzzg avatar Vincentzzg commented on July 17, 2024 1

@casatwy 老哥,我又回来了,数据库偶尔崩溃的问题找到了原因了。

使用场景我描述下:
1、所有的读写操作都在CTPersistanceAsyncExecutor读写锁的控制下
2、项目中有单例持有DataCenter->table->queryCommand->database->sqlite3 *database

问题出在操作使用table实例的时候,对于同一个table多个读操作并发的时候,用到的是同一个table实例(也就是同一个sqlite3 *database实例),如果第一个读操作结束时,另一个正在执行操作。这个时候第一个读操作的线程回收,CTPersistanceDatabasePool里面的didReceiveNSThreadWillExitNotification方法会找到table持有的这个database,调用close方法关掉并置空,这时另外一个正在执行的线程就崩溃了。

现在的模型是多个线程会共享一个table实例(sqlite3 *database),然后第一个创建的线程拥有释放的权利。而且不管其他线程有没有在用,这样就导致了偶尔的崩溃。

from ctpersistance.

casatwy avatar casatwy commented on July 17, 2024 1

我这边选择的解决方案还是基于现有的方案改进了一下,在关闭数据库之前数一数每个数据库有多少线程在操作。

如果某个数据库只有一个线程在操作,而且这个线程就是didReceiveNSThreadWillExitNotification的线程的话,我就认为这个线程打开的数据库是可以安全关闭的。

如果这个线程退出时操作的数据库,别的线程也在使用,那么ownershipCount就会大于1,这个数据库就不会被关闭。
如果ownershipCount等于1,但是记录的线程不是当前退出线程,那么这个数据库就也不会被关闭。

最新版已经改好发版了,版本号是200

from ctpersistance.

casatwy avatar casatwy commented on July 17, 2024 1

我今天看一下

from ctpersistance.

casatwy avatar casatwy commented on July 17, 2024 1

我复现了

from ctpersistance.

casatwy avatar casatwy commented on July 17, 2024 1

发好版了,最新版本号是201

from ctpersistance.

casatwy avatar casatwy commented on July 17, 2024

感觉这个像是多线程导致的问题,是不是在执行这个删除操作的时候,还有别的线程在处理相关的事情?

删除操作你是放在异步调用的那个方法里面做的吗?

from ctpersistance.

Vincentzzg avatar Vincentzzg commented on July 17, 2024

所有的数据库操作都是放到CTPersistanceAsyncExecutor类里面那三个方法的block里面做的

不过有些对table实例的创建是在block外面的,例如下面这种:
屏幕快照 2019-05-08 下午2 42 33
会不会创建table实例的是在fetchMyApplicationList方法调用的线程里面,table实例创建会做createTable的操作,这个跟其他地方提交的block里面的出现了并发的数据库写操作

from ctpersistance.

casatwy avatar casatwy commented on July 17, 2024

你可以试试在block里面做所有的事情,包括createTable。

还有,syncRead是会多线程同时操作的,syncWrite一次只允许一个线程操作。

所以是不是有代码可能在syncRead里面做了数据库写的操作?然后多个syncRead可能就同时写了。delete操作算是写操作。

from ctpersistance.

casatwy avatar casatwy commented on July 17, 2024

如果一套逻辑里面同时有读有写的,应该都放在syncWrite里,这样才能保证只有唯一线程操作数据库。

from ctpersistance.

Vincentzzg avatar Vincentzzg commented on July 17, 2024

嗯,我试下

有些读写是分开的,读放到了syncRead里面,写的操作在write里面,唯一线程能保证的,就是可能会有原子性问题,读写中间可能有其他操作插入;解决这个问题的时候我就把读写都放到一个write里面做了

from ctpersistance.

casatwy avatar casatwy commented on July 17, 2024

嗯,先试试看

from ctpersistance.

Vincentzzg avatar Vincentzzg commented on July 17, 2024

顺便问个其他的问题,我看insertRecordList里面的实现是for循环每个record单个插入的,意味着数组里面有多少个元素就会执行多少次写入操作,那insertRecordList是不是放到事务里面会快一点

from ctpersistance.

casatwy avatar casatwy commented on July 17, 2024

用事务的话就要考虑插入失败的回滚操作,我思考了一下一般客户端很少出现成百上千的操作的,所以就这么做了。

migration的时候倒是建议事务操作。

from ctpersistance.

Vincentzzg avatar Vincentzzg commented on July 17, 2024

然后,事务操作也是要再放到write里面做并发控制的吧
这种操作没问题吧
屏幕快照 2019-05-08 下午3 12 57

from ctpersistance.

Vincentzzg avatar Vincentzzg commented on July 17, 2024

全部操作,加上table实例的创建都在CTPersistanceAsyncExecutor的队列里面调度了,但是有个问题就是,table实例的创建现在是懒加载的,就是说第一次调用在那个block里面,就是跟随在那个block的线程里面做了table实例初始化的create table操作,也就是写操作。这个block可以能是syncRead的block,就出现了你说的写出现在了syncRead里面

例如下面这个:
屏幕快照 2019-05-09 上午9 27 21
如果这个syncRead执行的时候,另外又有一个syncRead里面做了createTable,就出现了并发写入的问题

我现在能想到的解决办法就是在把[[table alloc] init]放到一个同步写操作里面,确保这个create table的写操作完成之后再返回table实例

from ctpersistance.

Vincentzzg avatar Vincentzzg commented on July 17, 2024

@casatwy 所有的读写操作都放到CTPersistanceAsyncExecutor的队列里操作了,包括创建一个table实例时的create table也放到write里面了,还是会出现偶尔崩溃的情况

from ctpersistance.

casatwy avatar casatwy commented on July 17, 2024

一样的错误提示?

from ctpersistance.

Vincentzzg avatar Vincentzzg commented on July 17, 2024

是的,都是EXC_BAD_ACCESS

from ctpersistance.

Vincentzzg avatar Vincentzzg commented on July 17, 2024

这个问题我又研究了几天,限于知识水平和能力,目前还没啥进展😢
这个库项目里已经用了很久了,老版本用户的本地数据库已经生成了,切换其他数据库封装库的话要适配很多东西,也挺麻烦,中间我也提过PR,还是想能找到问题帮助这个库更好的发展,更完善一些。

目前的进展:
由于崩溃是偶尔崩溃,而且是由于EXC_BAD_ACCESS导致的崩溃,你之前也说过可能是多线程导致的,我现在正在排查对于sqlite3 *database的引用、关闭和置空,还有DatabasePool里面线程退出时对database关闭的处理。目前还没发现问题

@casatwy 能不能给点可能出问题的方向?我再继续排查

from ctpersistance.

casatwy avatar casatwy commented on July 17, 2024

现在的情况是我也没什么方向…

from ctpersistance.

Vincentzzg avatar Vincentzzg commented on July 17, 2024

@casatwy 有方向了,这个issue应该可以关闭了。之前由于找不到方向,又结合应用的前一个加密版本(SQLCipher4.0.1)没有崩溃问题的情况,然后对应SQLCipher4.1.0版本的发布时间,怀疑是SQLCipher版本的问题,然后就回退了SQLCipher的版本,果然,经过了一周时间多个同事的使用,没有发现崩溃问题。所以,目前可以基本断定是SQLCipher版本更新导致了崩溃的问题,所以,先把这个issue关掉了,后面有时间我再去跟进。

from ctpersistance.

casatwy avatar casatwy commented on July 17, 2024

可以的👍

from ctpersistance.

Vincentzzg avatar Vincentzzg commented on July 17, 2024

回复神速😄

from ctpersistance.

casatwy avatar casatwy commented on July 17, 2024

旷日持久的追踪啊

from ctpersistance.

casatwy avatar casatwy commented on July 17, 2024

看来我要针对多线程的table实例持有做计数了

from ctpersistance.

Vincentzzg avatar Vincentzzg commented on July 17, 2024

😄还在用这个库,所以问题早晚要解决的。之前以为是SQLCipher的问题。最近又升版本,问题又回来了,跟踪多了慢慢就发现了问题。

from ctpersistance.

Vincentzzg avatar Vincentzzg commented on July 17, 2024

有个问题,就是如果不用这个CTPersistanceDatabasePool呢,table自己管理sqlite3 *database呢?
不再针对线程维护database的创建和关闭,一个table实例对应一个sqlite3 *database,然后table销毁的时候关闭数据库、销毁databas实例,好像也可以。如果我的table需要一直用,database一直不关就好了。
而且table一般不会太多,也不太会频繁创建、销毁,所以也不会出现database的频繁创建、打开、关闭、销毁的开销。

from ctpersistance.

Vincentzzg avatar Vincentzzg commented on July 17, 2024

老哥神速👍

from ctpersistance.

casatwy avatar casatwy commented on July 17, 2024

还得仰仗你的业务场景呀,这次修改应该能够好很多。不知道你这边新版什么时候上线,观察观察数据这一类crash是不是就降下来了

from ctpersistance.

Vincentzzg avatar Vincentzzg commented on July 17, 2024

问题可能我这边搞错了,我们这边另外一个同事也在看这个问题。发现多线程环境下一个table对应的database实例会是多个,每个线程对应一个。

CTPersistanceTable类里面queryCommand的get方法走的都是initWithDatabaseName:swiftModuleName:swiftModuleName:,这个方法里面设置self.shouldKeepDatabas = NO
`

  • (CTPersistanceQueryCommand *)queryCommand
    {
    if (_queryCommand == nil && self.isFromMigration == NO) {
    NSString *swiftModuleName = nil;
    if ([self.child respondsToSelector:@selector(swiftModuleName)]) {
    swiftModuleName = [self.child swiftModuleName];
    }
    _queryCommand = [[CTPersistanceQueryCommand alloc] initWithDatabaseName:[self.child databaseName] swiftModuleName:swiftModuleName];
    }
    return _queryCommand;
    }
    `

`

  • (instancetype)initWithDatabaseName:(NSString *)databaseName swiftModuleName:(NSString *)swiftModuleName
    {
    self = [super init];
    if (self) {
    self.shouldKeepDatabase = NO;
    self.databaseName = databaseName;
    self.swiftModuleName = swiftModuleName;
    }
    return self;
    }
    `

这样每次执行compileSqlString:bindValueList:error:方法时self.database拿到的是从pool中重新获取的线程对应的_database实例,新的线程会拿到新的实例
`

  • (CTPersistanceSqlStatement *)compileSqlString:(NSString *)sqlString bindValueList:(NSMutableArray <NSInvocation *> *)bindValueList error:(NSError *__autoreleasing *)error
    {
    CTPersistanceSqlStatement *statement = [[CTPersistanceSqlStatement alloc] initWithSqlString:sqlString bindValueList:bindValueList database:self.database error:error];
    return statement;
    }
  • (CTPersistanceDataBase *)database
    {
    if (self.shouldKeepDatabase) {
    return _database;
    }
    _database = [[CTPersistanceDatabasePool sharedInstance] databaseWithName:self.databaseName swiftModuleName:self.swiftModuleName];
    return _database;
    }
    `

所以,多线程共享database的情况可能是不存在的,当时漏掉了这段代码

from ctpersistance.

casatwy avatar casatwy commented on July 17, 2024

现在你比我都更了解这个库了~

这改动先放着好了,因为走gcd的话,任务被dispatch到哪个线程是不确定的,这段代码还有存在的价值

from ctpersistance.

Vincentzzg avatar Vincentzzg commented on July 17, 2024

😄 我是“久病成医”。嗯嗯,代码是有价值的,应该留着。

其他的还发现几个小问题:
1、重复的关闭动作
didReceiveNSThreadWillExitNotification方法里面 [databaseToClose makeObjectsPerformSelector:@selector(closeDatabase)];执行了关闭操作,紧接着CTPersistanceDataBase对象从databaseList中移除,不再被持有,销毁的时候dealloc方法里面又调用了一次。没发现什么问题,但是应该是不必要的
[keyToDelete enumerateObjectsUsingBlock:^(NSString * _Nonnull key, NSUInteger idx, BOOL * _Nonnull stop) { [self.databaseList removeObjectForKey:key]; }];
`

  • (void)dealloc
    {
    [self closeDatabase];
    }
    `

2、sql语句中字符串变量值的单引号
库里面单引号有些用的是,我查了一下这个是重音符,现在删除操作都是ok的,不知道会不会引起什么其他的问题

  • (CTPersistanceSqlStatement *)deleteTable:(NSString *)tableName whereString:(NSString *)whereString bindValueList:(NSMutableArray <NSInvocation *> *)bindValueList error:(NSError *__autoreleasing *)error
    {
    NSString *sqlString = [NSString stringWithFormat:@"DELETE FROM %@ WHERE %@", tableName, whereString];
    return [self compileSqlString:sqlString bindValueList:bindValueList error:error];
    }
    `

from ctpersistance.

casatwy avatar casatwy commented on July 17, 2024
  1. 这个是冗余代码,我防御性地写一下的

  2. `是SQL的一种标准吧,数据库名、表名、字段名这些,在标准的SQL里是用`的

from ctpersistance.

Vincentzzg avatar Vincentzzg commented on July 17, 2024
  1. 这个是冗余代码,我防御性地写一下的

  2. `是SQL的一种标准吧,数据库名、表名、字段名这些,在标准的SQL里是用`的

好的,我再研究下

from ctpersistance.

Vincentzzg avatar Vincentzzg commented on July 17, 2024

老哥,我又来了,数据库偶尔崩溃的问题,这次估计是找到了最终的原因。
现象是这样的,由于使用的时间增加,用户本地数据库的数据量越来越大,几万条的样子,数据库的读写都会变慢,这样的情况下,崩溃变得更频繁了,由于崩溃的频繁,也更容易找出问题的特点了。

现在崩溃的特点是并发读也会崩溃,而且每次崩溃的几个并发读线程里,肯定有一个是在走数据库sqlite3_key的方法:
截屏2021-02-06 下午9 55 43

截屏2021-02-06 下午9 59 39

Sqlite数据库是支持并发读的,所以应该不是读的问题,所以我猜测是不是sqlite3_key是不能跟读同时出现的,我搜了没找到sqlite3_key明确的线程安全相关的数据,这个我目前只能确认到这一步了。
不过我做了反向验证,就是项目中特别容易出现并发读操作且容易引起崩溃的操作,我给改成了加到write锁里面执行,前后并发执行了几十次都没有崩溃,同样的测试平常一两次并发肯定会崩一次,所以这也侧面验证了并发读会崩的问题。

另外这个问题,直接在CTPersistance这个项目里面加测试代码也是能复现的,上面的截图就是我在CTPersistance的项目里加测试代码先插入几万条数据,然后并发读复现的崩溃,老哥,有时间一起看下这种并发读的崩溃问题吧

下面是我的测试代码,放到CTPersistance项目里跑几次基本就能复现崩溃:
CTPersistanceTestConcurrentRead.m.zip

from ctpersistance.

casatwy avatar casatwy commented on July 17, 2024

正好下周有空可以一起看看

from ctpersistance.

Vincentzzg avatar Vincentzzg commented on July 17, 2024

老哥,啥时候有空一起看下,这个问题不解决,只能考虑换库了,不过换库的成本太高了,问题能解决的话,还是希望继续用这个库的

from ctpersistance.

Vincentzzg avatar Vincentzzg commented on July 17, 2024

测试用例直接拖到CTPersistanceTests里面,模拟器跑也能复现

CTPersistanceTestConcurrentRead.m.zip

from ctpersistance.

casatwy avatar casatwy commented on July 17, 2024

我跑了几次,没复现出来?

我考虑把队列换成serial队列,这样的话就相当于是“读任务”一个一个执行
你这边的业务场景能够撑得住不?

或者我换成operation queue,最多同时执行10个读任务
这样会不会更好一些?

from ctpersistance.

Vincentzzg avatar Vincentzzg commented on July 17, 2024

再多试几次呢,本地多积累点数据呢,我这边跑的话是很容易复现的。
数据库加密的情况下,读写都会变慢,数据量再大一点,就更慢了,并发的读就更容易出现多个读同时执行的情况,这种情况就容易崩溃

from ctpersistance.

Vincentzzg avatar Vincentzzg commented on July 17, 2024

真机试下呢,我用模拟器第一次就复现了,但是后面确实没再复现,我用真机(iPhone XS)复现的概率很大,这个可能跟设备的性能也有关系

截屏2021-02-22 下午5 20 57

你再试下这个,我用这个用例,iPhone XS真机崩溃复现的概率会高一些
CTPersistanceTestConcurrentRead.m.zip

from ctpersistance.

casatwy avatar casatwy commented on July 17, 2024

好的,我试一下

from ctpersistance.

casatwy avatar casatwy commented on July 17, 2024

可以把真机上的crash日志导出贴上来么?

from ctpersistance.

Vincentzzg avatar Vincentzzg commented on July 17, 2024

我还在弄日志,发现有日志也都是没有符号化的地址信息,现在应该不需要日志了

from ctpersistance.

Vincentzzg avatar Vincentzzg commented on July 17, 2024

老哥,这个问题有解决的方向吗?

from ctpersistance.

casatwy avatar casatwy commented on July 17, 2024

你拉取synchronized分支,看看是不是就好了?

from ctpersistance.

casatwy avatar casatwy commented on July 17, 2024

测试用例我也已经放进去了

from ctpersistance.

Vincentzzg avatar Vincentzzg commented on July 17, 2024

好的,我试下

from ctpersistance.

casatwy avatar casatwy commented on July 17, 2024

好了的话跟我说一声,我发个版

from ctpersistance.

Vincentzzg avatar Vincentzzg commented on July 17, 2024

好的,在试了,我再多试几次

from ctpersistance.

Vincentzzg avatar Vincentzzg commented on July 17, 2024

跑了十几次,没崩,应该是可以了

from ctpersistance.

Vincentzzg avatar Vincentzzg commented on July 17, 2024

按照我的理解,改了之后是同一个table实例的操作变成串行了吧,但是多个table之间还是并发的,对吧
目前看着对性能的影响不是很大

from ctpersistance.

casatwy avatar casatwy commented on July 17, 2024

不是的,即使单个table也是并发的

这个问题的原因在于statement的创建和使用不是原子性的
然后如果一个statement刚创建,但另一个线程用了这个statement
就导致statement失效了

现在的做法就是让statement的创建和使用放到一个原子操作里面去了
多线程还是正常的

from ctpersistance.

casatwy avatar casatwy commented on July 17, 2024

话说这个问题跟踪了2年,终于是解决了啊~

from ctpersistance.

Vincentzzg avatar Vincentzzg commented on July 17, 2024

😄是的,还好没放弃

from ctpersistance.

Vincentzzg avatar Vincentzzg commented on July 17, 2024

不过我还是有些疑问:
1、代码中的同步锁用的是@synchronized (self),self对应的是table实例,那么所有加了@synchronized (self)锁的操作之间是不能并发的,因为用的是同一把锁“self”,所以只能一个@synchronized (self){}花括号中的代码执行完下一个@synchronized (self){}花括号中的代码才会执行
@synchronized (self) {}也包住了所有sql执行的代码,所以其实是一个table实例间的sql执行都串行了,如下图:
截屏2021-02-23 下午2 32 09

我在括号里加了一个sleep(1),打印就变成了每秒1次:
截屏2021-02-23 下午2 36 29

from ctpersistance.

Vincentzzg avatar Vincentzzg commented on July 17, 2024

2、CTPersistanceSqlStatement *statement这个我看了下,是一个局部变量(它持有sqlite3_stmt *statement),没有对象持有它,每个实例都是临时生成的,所以应该是每个线程使用的都是新生成的statement对象,应该不存在原子性问题吧

from ctpersistance.

casatwy avatar casatwy commented on July 17, 2024

哦,事实上确实还是串行了,只是乱序了而已,我理解错了。

from ctpersistance.

Vincentzzg avatar Vincentzzg commented on July 17, 2024

嗯,开始时是并发的,但是后面都在等锁了

from ctpersistance.

casatwy avatar casatwy commented on July 17, 2024

是的,后面就在等锁了.

崩溃的时候,看到的情况是statement这个对象变成野指针了,所以bad access
是因为从sqlcommand出来的statement没有正确被execute或fetch导致的

我当初写的时候想的也是这些都是我创建的临时变量,应该不会有线程安全问题
但看起来事实并不是我想的这样

from ctpersistance.

Vincentzzg avatar Vincentzzg commented on July 17, 2024

你说的statement是CTPersistanceSqlStatement还是它持有的sqlite3_stmt *statement

from ctpersistance.

Vincentzzg avatar Vincentzzg commented on July 17, 2024

我用老的代码复现了崩溃,这个时候statement是能访问的,崩溃的点是在很底层了
截屏2021-02-23 下午3 07 22

from ctpersistance.

casatwy avatar casatwy commented on July 17, 2024

我说的是sqlite3_stmt *statement
在这个地方你po self.statement,就会发现这是个野指针

from ctpersistance.

Vincentzzg avatar Vincentzzg commented on July 17, 2024

崩溃的地方打印好像是正常的,提示的是unknown class
截屏2021-02-23 下午4 02 16

from ctpersistance.

casatwy avatar casatwy commented on July 17, 2024

按道理来说不应该是个unknown class吧?

from ctpersistance.

Vincentzzg avatar Vincentzzg commented on July 17, 2024

这里unknown class应该是因为它是个结构体,不是OC对象,这里正常断点打印也是unknown class
截屏2021-02-23 下午4 34 46

from ctpersistance.

Vincentzzg avatar Vincentzzg commented on July 17, 2024

会不会真的是我开始说的sqlite3_key的问题,sqlite3_key不是线程安全的或者是作为一个写操作,需要加写锁之类的,现象确实是每次崩溃都有一个sqlite3_key的调用在

from ctpersistance.

casatwy avatar casatwy commented on July 17, 2024

可能是,如果真是这样,那就还是只能靠加锁解决了😂

from ctpersistance.

Vincentzzg avatar Vincentzzg commented on July 17, 2024

synchronized分支加锁保证单个table的操作串行确实解决了崩溃的问题,还有一种情况还是会崩

synchronized分支里面,把table改成临时创建的,这个作用就没了,还是会崩
截屏2021-02-23 下午4 56 20

截屏2021-02-23 下午4 56 05

想要不崩溃,咋这么难😿

from ctpersistance.

casatwy avatar casatwy commented on July 17, 2024

你在master分支上试一下呢?因为之前我遗漏了两处没有加锁。现在新版本是202了

from ctpersistance.

Vincentzzg avatar Vincentzzg commented on July 17, 2024

OK

from ctpersistance.

Vincentzzg avatar Vincentzzg commented on July 17, 2024

上面读取改成table临时创建,使用master分支的代码,试了很多次都是好的,还是复现了一次崩溃,table初始化的时候的createTable操作跟其他的数据库操作是一样的,应该也要加锁,这样来看的话,需要加锁的范围应该更大一些,可能还有其他的操作需要加锁

截屏2021-02-23 下午7 14 35

from ctpersistance.

Vincentzzg avatar Vincentzzg commented on July 17, 2024

我又思考了下,上面说的可能是有问题的,table每次都是一个新的实例,就不会存在同一个table之前的并发.因为都在read:{}里面,是顺序执行的先createTable,然后是具体的读操作。
这个崩溃是源于不同的table实例之间的问题,也就是说tableA在读的同时,tableB执行createTable,触发了sqlite3_key,也是可能会崩溃的

如果这个崩溃是由于sqlite3_key不能与其他的读写操作并发,那么是不是应该加全局的锁,做到全局不并发。我们现在是针对table加的锁,不同的table之间还是有可能会崩溃的

from ctpersistance.

Vincentzzg avatar Vincentzzg commented on July 17, 2024

sqlcipher那边我也提了一个issue,作者给了一个回复,可以参考下
is it safe call sqlite3_key when other threads reading on the same db #381

from ctpersistance.

casatwy avatar casatwy commented on July 17, 2024

我大概明白了,我可能要去掉数据库链接池,因为如果池里有链接,那我就会复用这个链接,就会出现他说的情况。

from ctpersistance.

Vincentzzg avatar Vincentzzg commented on July 17, 2024

他第1条说“每个线程都有自己的数据库连接,是安全的”,我们这个数据库链接池,满足了这个条件

第2条是“在多个线程上重复调用一个数据库句柄上的sqlite3_key是不安全的。”这个现在的库应该也是满足的,而且如果线程尽量发现针对自己已经有了数据库连接,直接拿来用,是不会调用open和sqlite3_key的,也不会出问题

from ctpersistance.

Vincentzzg avatar Vincentzzg commented on July 17, 2024

他第1条说“每个线程都有自己的数据库连接,是安全的”,我们这个数据库连接池,满足了这个条件

第2条是“在多个线程上重复调用一个数据库句柄上的sqlite3_key是不安全的。”这个现在的库应该也是满足的,而且如果线程发现针对自己已经有了数据库连接,直接拿来用,是不会调用open和sqlite3_key的,也不会出问题,就是说我们存储了数据库连接,同一个数据库连接不会调用两次open和sqlite3_key。

from ctpersistance.

casatwy avatar casatwy commented on July 17, 2024

我看了一下,我这边数据库连接池是按照线程区分的,按道理确实是不会出现他说的情况。
之前我记错了,我以为复用链接的时候没有区分线程。

现在202先用着吧,等我有空了再好好研究这个问题。

from ctpersistance.

Vincentzzg avatar Vincentzzg commented on July 17, 2024

好的,sqlcipher那边我继续跟着,看是不是他们库的缺陷

from ctpersistance.

Vincentzzg avatar Vincentzzg commented on July 17, 2024

最新的demo项目有些问题,文件没提交
截屏2021-02-24 下午1 57 57

from ctpersistance.

casatwy avatar casatwy commented on July 17, 2024

好了,我推上来了

from ctpersistance.

Vincentzzg avatar Vincentzzg commented on July 17, 2024

老哥,项目中碰到两个table之间的崩溃了,一个table(messageTable)正在读,另一个线程另外一个table(conversationTable)打开了一个新的database,就崩了

resultv1_1.log

sqlcipher那边我给他们回复了,他们的回复我没看太懂,他们可能觉得还是CTPersistance库的问题(最新回复),老哥啥时候有时间帮忙看下

from ctpersistance.

casatwy avatar casatwy commented on July 17, 2024

我大概看明白了,是因为我在open之后调用了很多次sqlite3_key,我回头看一下这个应该怎么解决一下

from ctpersistance.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.