-
-
Notifications
You must be signed in to change notification settings - Fork 6.2k
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
fix: fix "Cannot commit, no transaction is active" error in sql.js #9234
fix: fix "Cannot commit, no transaction is active" error in sql.js #9234
Conversation
*/ | ||
async autoSave() { | ||
if (this.options.autoSave) { | ||
if (this.options.autoSave && !this.queryRunner?.isTransactionActive) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
shouldn't we throw an error if one tries to autoSave during active transaction? Imagine someone called autoSave but it didn't save anything if transaction was active, and user still thinks everything was saved.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I get your point though it would be a bit tricky to do it as this method is automatically called on query runner release if database has changed (code from SqljsQueryRunner.ts
):
private async flush() {
if (this.isDirty) {
await this.driver.autoSave()
this.isDirty = false
}
}
async release(): Promise<void> {
await this.flush()
return super.release()
}
If we throw an error everytime this gets called within a transaction, we will end up with tons of errors as a simple update
on the repository during a transaction will trigger it.
Is there a way to inform the user without throwing an error?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
okay, another question:
shouldn't we add the proposed check into commitTransaction
override?:
async commitTransaction(): Promise<void> {
await super.commitTransaction()
if (this.isTransactionActive === false)
await this.flush()
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You want to add it there to ensure that the database is saved after the transaction?
Currently, COMMIT
sets isDirty
to true
. Then, when the query runner is released after the query, it automatically flushes the database as there is no active transaction.
So, database is already saved after transaction but it would be easier to understand I admit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It makes sense to have it there I think. We flush after the transaction. And we do it only if transaction was committed.
Any news on merging this? |
Thank you for contribution! 🎉 |
Fixes: #9100
Description of change
When calling
autoSave
in a transaction, typeorm automatically closes the transaction in theexport
method. Therefore, when callingcommitTransaction
, the transaction is already committed and sqljs throws an exception "Cannot commit, no transaction is active".This fix disables
autoSave
during the transaction to avoid this. Of course,autoSave
is still called after the transaction, when calling commit.There was another PR for this issue (#9101) but this fix is not working when saving the database inside a transaction. If we call a
find
on the repository, typeorm releases the connection and it's callingautoSave
. Waiting for the transaction to finish before saving was not working as we wait indefinitely.Pull-Request Checklist
master
branchnpm run format
to apply prettier formattingnpm run test
passes with this changeFixes #0000