Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

mysql开启连接池后事务操作会被中断,用单连接又有串事务的问题 #408

Closed
johnzgit opened this issue Aug 1, 2016 · 23 comments
Labels

Comments

@johnzgit
Copy link
Contributor

johnzgit commented Aug 1, 2016

DESC

上次发现开启多连接 mysql事务会乱掉之后改用单连接,最近又发现一个硬伤,单连接情况下如果并发请求的话多个事务貌似会串在一起,症状是select for update失效 事务中的查询排他锁用不了 具体操作为事务中 查询某条记录后修改 前面的请求还没commit 后面的请求的查询就开始了

ENV

Platform:

Node.js Version:

ThinkJS Version:

@welefen
Copy link
Member

welefen commented Aug 1, 2016

多谢反馈,我们研究下怎么解决这个问题

@welefen welefen added the bug label Aug 1, 2016
@johnzgit
Copy link
Contributor Author

johnzgit commented Aug 2, 2016

好的,我们这边的项目急着上线 这几天要解决这个问提先, 你们要是有什么解决思路来不及实现和发版本的话希望能告知我一声 不胜感激

@johnzgit
Copy link
Contributor Author

johnzgit commented Aug 2, 2016

是不是可以这么修改 1. await model.startTrans()...这些方法保持不变,作用仅为生成sql并query 2.修改model.transaction方法,尾部增加一个参数 temporaryConnection,接受布尔值或者一个nodel-mysql的连接实例, 默认为true,即给方法内的sql操作新建一个connection来执行事务, 传false则跟await model.startTrans()执行效果一样 传一个连接实例则用该连接来执行方法内的sql操作

@johnzgit
Copy link
Contributor Author

johnzgit commented Aug 2, 2016

或者直接把node-mysql换成 https://github.com/sequelize/sequelize

@johnzgit
Copy link
Contributor Author

johnzgit commented Aug 2, 2016

https://github.com/HBYoon/node-mysql-transaction 这种方式应该也可以

@welefen
Copy link
Member

welefen commented Aug 3, 2016

已经修复,见: 8d7e89d

请从 GitHub 上下载最新的代码帮忙测试下。(下载完成后,执行 npm install 安装依赖,然后执行 npm run compile 编译)

@johnzgit
Copy link
Contributor Author

johnzgit commented Aug 3, 2016

好的

@johnzgit
Copy link
Contributor Author

johnzgit commented Aug 3, 2016

用 await model.startTrans()和model.transaction方法都可以么

@johnzgit
Copy link
Contributor Author

johnzgit commented Aug 3, 2016

现在并发请求会报错[Error] Error: Cannot enqueue Query after invoking quit.
at Protocol._validateEnqueue (C:\Users\yuhang\Documents\N5-jubaopeng\node_modules\mysql\lib\protocol\Protocol.js:202:16)
at Protocol._enqueue (C:\Users\yuhang\Documents\N5-jubaopeng\node_modules\mysql\lib\protocol\Protocol.js:135:13)
at Connection.query (C:\Users\yuhang\Documents\N5-jubaopeng\node_modules\mysql\lib\Connection.js:214:25)
at C:\Users\yuhang\Documents\N5-jubaopeng\node_modules\thinkit\lib\index.js:47:10
at Promise._execute (C:\Users\yuhang\Documents\N5-jubaopeng\node_modules\thinkjs\node_modules\bluebird\js\release\debuggability.js:272:9)
at Promise._resolveFromExecutor (C:\Users\yuhang\Documents\N5-jubaopeng\node_modules\thinkjs\node_modules\bluebird\js\release\promise.js:473:18)
at new Promise (C:\Users\yuhang\Documents\N5-jubaopeng\node_modules\thinkjs\node_modules\bluebird\js\release\promise.js:77:14)
at C:\Users\yuhang\Documents\N5-jubaopeng\node_modules\thinkit\lib\index.js:46:12
at _class._callee3$ (C:\Users\yuhang\Documents\N5-jubaopeng\node_modules\thinkjs\src\adapter\socket\mysql.js:117:19)
at tryCatch (C:\Users\yuhang\Documents\N5-jubaopeng\node_modules\thinkjs\node_modules\babel-runtime\regenerator\runtime.js:88:40)
at GeneratorFunctionPrototype.invoke as _invoke
at GeneratorFunctionPrototype.prototype.(anonymous function) as next
at step (C:\Users\yuhang\Documents\N5-jubaopeng\node_modules\thinkjs\node_modules\babel-runtime\helpers\asyncToGenerator.js:17:30)
at C:\Users\yuhang\Documents\N5-jubaopeng\node_modules\thinkjs\node_modules\babel-runtime\helpers\asyncToGenerator.js:28:20
at tryCatcher (C:\Users\yuhang\Documents\N5-jubaopeng\node_modules\thinkjs\node_modules\bluebird\js\release\util.js:16:23)
at Promise._settlePromiseFromHandler (C:\Users\yuhang\Documents\N5-jubaopeng\node_modules\thinkjs\node_modules\bluebird\js\release\promise.js:502:31)
at Promise._settlePromise (C:\Users\yuhang\Documents\N5-jubaopeng\node_modules\thinkjs\node_modules\bluebird\js\release\promise.js:559:18)
at Promise._settlePromise0 (C:\Users\yuhang\Documents\N5-jubaopeng\node_modules\thinkjs\node_modules\bluebird\js\release\promise.js:604:10)
at Promise._settlePromises (C:\Users\yuhang\Documents\N5-jubaopeng\node_modules\thinkjs\node_modules\bluebird\js\release\promise.js:683:18)
at Async._drainQueue (C:\Users\yuhang\Documents\N5-jubaopeng\node_modules\thinkjs\node_modules\bluebird\js\release\async.js:138:16)
at Async._drainQueues (C:\Users\yuhang\Documents\N5-jubaopeng\node_modules\thinkjs\node_modules\bluebird\js\release\async.js:148:10)
at Immediate.Async.drainQueues as _onImmediate

@johnzgit
Copy link
Contributor Author

johnzgit commented Aug 3, 2016

测试代码如下
async testAction() {
//systemMessageModel为global里初始化的一个model实例
await systemMessageModel.startTrans();
await systemMessageModel.order('create_time DESC').find()
await systemMessageModel.add({
create_time: moment().format("YYYY-MM-DD HH:mm:ss")
});
await systemMessageModel.commit();
return this.success();
}

@johnzgit
Copy link
Contributor Author

johnzgit commented Aug 3, 2016

从日志上观察到是这样的
[2016-08-03 10:10:01] [SOCKET] Connect mysql with mysql://jubaopen_db:oscar2016@rdspr7557sg3894mkt6oo.mysql.rds.aliyuncs.com:3306/jubaopen_test
[2016-08-03 10:10:01] [SQL] START TRANSACTION 115ms
[2016-08-03 10:10:01] [SQL] START TRANSACTION 157ms
[2016-08-03 10:10:02] [SOCKET] Connect mysql with mysql://jubaopen_db:oscar2016@rdspr7557sg3894mkt6oo.mysql.rds.aliyuncs.com:3306/jubaopen_test
[2016-08-03 10:10:02] [SQL] SHOW COLUMNS FROM jbp_system_message 15ms
[2016-08-03 10:10:02] [SQL] SELECT * FROM jbp_system_message ORDER BY create_time DESC LIMIT 1 38ms
[2016-08-03 10:10:02] [SQL] INSERT INTO jbp_system_message (create_time,update_time) VALUES ('2016-08-03 10:10:02','2016-08-03T10:10:02+08:00') 90ms
[2016-08-03 10:10:02] [SQL] INSERT INTO jbp_system_message (create_time,update_time) VALUES ('2016-08-03 10:10:02','2016-08-03T10:10:02+08:00') 106ms
[2016-08-03 10:10:02] [HTTP] GET /home/test/trade/test 200 431ms
[2016-08-03 10:10:02] [SQL] COMMIT 30ms
[2016-08-03 10:10:02] [HTTP] GET /home/test/trade/test 200 761ms
里面有个问题是commit只打印了一次

@welefen
Copy link
Member

welefen commented Aug 3, 2016

systemMessageModel 不能为一个 global 的实例,在 Action 里实例化应该就可以了

@johnzgit
Copy link
Contributor Author

johnzgit commented Aug 3, 2016

好的 我改下代码再试试

@johnzgit
Copy link
Contributor Author

johnzgit commented Aug 3, 2016

测试成功了 是不是model实例不能是同一个才能分开创建连接呢?

@welefen
Copy link
Member

welefen commented Aug 3, 2016

恩 是的,同一个 model 会共用一个连接的

@johnzgit
Copy link
Contributor Author

johnzgit commented Aug 3, 2016

那如果一个事务中涉及到多个model会怎么处理呢

@welefen
Copy link
Member

welefen commented Aug 3, 2016

可以通过数据库连接完成,你再更新下。
类似下面的代码:

let model = this.model('aaa');
try{
  await model.startTrans();
  await model.add({name: 'xxx'});
  let model2 = this.model('bbb').db(model.db());
  await model2.add({title: 'yyyy'});
  await model.commit();
}catch(e){
  await model.rollback();
}

transaction 方法也可以,如:

let model = this.model('aaa');
await model.transaction(async () => {
   await model.add({name: 'wwww'});
   let model2 = this.model('bbb').db(model.db());
   await model2.add({title: 'yyyy'})
})

@johnzgit
Copy link
Contributor Author

johnzgit commented Aug 3, 2016

明白了 我试试

@johnzgit
Copy link
Contributor Author

johnzgit commented Aug 3, 2016

什么时候发布2.2.8呢

@welefen
Copy link
Member

welefen commented Aug 3, 2016

会尽快发布,最迟本周五

@welefen
Copy link
Member

welefen commented Aug 4, 2016

没有确认没问题了,把这个 issue 关了吧

@johnzgit
Copy link
Contributor Author

johnzgit commented Aug 4, 2016

恩 关掉吧 我这边暂时没有发现什么问题了

@welefen
Copy link
Member

welefen commented Aug 4, 2016

已经发布 2.2.8 版本

@welefen welefen closed this as completed Aug 4, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants