例如:
分别向3个表各插入1条数据。
plus.sqlite.transaction 是异步的。
plus.sqlite.execSql 是异步的。
类似下面的逻辑肯定是不行的。那么,这个”事务“该如何处理?或者有详细的例子参考吗?
plus.sqlite.transaction({
name: dbname,
operation: 'begin',
success: function () {},
fail: function (err){}
})
try{
plus.sqlite.executeSql(dbname, sql_table1)
plus.sqlite.executeSql(dbname, sql_table2)
plus.sqlite.executeSql(dbname, sql_table3)
plus.sqlite.transaction({
name: dbname,
operation: 'commit',
success: function () {},
fail: function (err){}
})
}catch(err) {
plus.sqlite.transaction({
name: dbname,
operation: 'rollback',
success: function () {},
fail: function (err){}
})
}
11 个回复
uniapper (作者) - abc
顶一下
uniapper (作者) - abc
谁有实例代码?
DCloud_App_Array
所有方法都有成功回调,触发成功回调就说明异步操作完成。
uniapper (作者) - abc
@DCloud_App_Array
这个“成功回调”我理解。
问题是,begin/ CUD sql / commit / rollback 的执行顺序。
就像上面的代码,begin/ CUD sql / commit / rollback都是异步执行。
begin和自己的CUD操作先后顺序还好确定。可以在begin的success回调中执行CUD的多条sql。
但是,
(若在每条executeSql()的fail回调中调用rollback,可能会导致rollback后其他仍未执行完成的executeSql() 在没有触发自己的fail回调时,成功完成对数据库的修改)
uniapper (作者) - abc
求解答
uniapper (作者) - abc
摸索出来怎么执行事务了。但是却不敢用事务了!
以下是自己通过多次实验对执行原理的猜测:
plus.sqlite sdk的api都是“异步执行”但也是“同步执行”。
异步执行:
相对于同逻辑模块的非plus.sqlite代码,所有的plus.sqlite代码是异步的。类似于,放到一个异步队列中。
同步执行:
相同逻辑模块中的所有plus.sqlite代码,又是按照其在代码中出现的位置,严格按照先后顺序“同步执行”的。
其实,这些原理官方应该在文档中有个明确的说明。文档差没关系,但是这些关键的原理不能靠开发者去猜测吧。
通过封装成Promise也解决了,多条CUD sql语句执行过程中某一条或几条失败,也可以触发真正意义上的rollback了。
但是!!!
事务执行完毕后,会被锁库(database is locked).这个库就废了。
无论是通过sdk的原生写法还是自己封装的Promise,都会锁库。
而,plus.sqlite.transaction 中的operation中开始事务只能用commit,无法执行 commit immediate等因而无法尝试其他的sqlite锁形式...
uniapper (作者) - abc
这个“锁库”的原因,找到了:
在执行CUD sql的过程中发生了异常,没有走到commit/rollback
并且,在CUD的异常处理函数中关闭了数据库连接。
即: 事务没有commit/rollback的情况下关闭了连接,导致sqlite的锁没有释放!
话说, @DCloud_App_Array plus.sqlite.closeDatabase中加上end transatcion的相关操作有没有可行性?
2***@qq.com
哥们能给个例子吗?
uniapper (作者)
就按上面写的, 只开启事务,然后执行插入等sql,之后立即关闭(closeDatabase).既不commit也不rollback。在执行完第一次后,之后就会提示 database is locked。
2019-06-09 10:39
2***@qq.com
回复 uniapper: 你的异常 没有进 catch??? 那里不是rollback了吗
2019-06-09 21:13
uniapper (作者)
回复 2***@qq.com: 我的问题中只是当时问问题时随便写的(而且executeSql的传参方式也写错了)。当时实际写逻辑时,因为涉及的逻辑代码较多导致出错没有捕捉对异常。你复现“锁库”可以尝试不写 commit/rollback直接closeDatabase试一下。
2019-06-10 10:55
2***@qq.com
回复 uniapper: 我现在是 打开成功,开始事务成功,执行SQL成功,提交事务成功,关闭数据库成功, 再次执行SQL的时候 打开数据库 就锁库了 ,都不知道为什么了
2019-06-11 00:31
uniapper (作者)
回复 2***@qq.com: 你可以新开一贴,把你的测试代码贴出来然后@官方看看是啥情况
2019-06-11 09:27
2***@qq.com
回复 uniapper: 这个问题已经解决了是 事务并发的问题,只要保证同时别有两个事务同时存在就行了。但是 锁库有什么办法解锁你知道吗?除了重启程序的话
2019-06-14 02:56
uniapper (作者)
回复 2***@qq.com: 是的,并发操作容易出问题,这是sqlite的特性决定的。我暂时没再敢用事务。当时发现自己这边是因为没有commit/rollback导致的锁库后,简单写了个插入数据的事务测试执行了多次(单webview内)并未复现“锁库”。 建议你的情况,单独开帖问官方。
2019-06-14 08:43
2***@qq.com
回复 uniapper: 你是直接 读写数据库,不用事务么?那样不会锁库是吗
2019-06-18 01:25
uniapper (作者)
回复 2***@qq.com: 现在没用事务,还没遇到过锁库的情况。
2019-06-18 08:24
n***@qq.com
哥们能给个例子吗?
uniapper (作者)
就按上面写的, 只开启事务,然后执行插入等sql,之后立即关闭(closeDatabase).既不commit也不rollback。在执行完第一次后,之后就会提示 database is locked。
2019-06-09 10:39
8***@qq.com - 初来咋到
我觉得可以使用promise或async await做这块,通过传入一个存有sql的数组,循环执行,html5+这边的success和fail执行resolve和reject,在promise的catch区间执行回滚,在最后的一条sql执行完后,进行commit,另外我想请教下,您们是怎么获取最后执行的sql的id的,我现在想到的是使用事务的情况,想请教下楼主怎么解决并发和获取最后执行的sql的id(程序可能会进行数据下拉、上传的操作、人为操作,这些会导致并发的问题)
8***@qq.com
使用promise.all
2019-06-19 11:20
uniapper (作者)
回复 8***@qq.com:
参考以下MDN上的Promise.all 的文档
Promise.all
> 在任何情况下,Promise.all 返回的 promise 的完成状态的结果都是一个数组,它包含所有的传入迭代参数对象的值(也包括非 promise 值)
2019-06-19 14:43
8***@qq.com
回复 uniapper: 嗯嗯,我刚刚尝试了异步执行多条事务,发现这几条执行后获取到的都是最后一个id,而不是当前事务中获取的id,唉,executeSql成功没有参数返回真伤啊。。
2019-06-19 15:43
w***@163.com - 90后程序员
看了一下官方的关于sqlite数据库操作的例子,发现没有关于数据事务操作的用法,估计这个事务操作还是存在很多问题的,我还是先不用了吧