-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Deadlock in SQL Server when INSERT INTO SPRING_SESSION_ATTRIBUTES by JdbcOperationsSessionRepository #1550
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
Comments
Hi, We are facing similar issue when there are two parallel session inserts. Currently we are using Sql server. The following is the deadlock graph: Please let us know your thoughts on this. |
I ran into this issue as well, which is quite easy to reproduce. I also think I've fixed it, by simply changing the SQL that inserts new attributes to take the primary key of the session directly rather than deriving it from the session ID using a nested select. Based on the deadlock XML that was posted it looks like the deadlock is caused by locks on the unique index on that session ID. |
Reproduces this error, plus another bug, here: https://github.com/jkuipers/spring-session-jdbc-sql-server-bugs/ Confirmed that my suggestion fixes the deadlock problem. The other bug I found is that Spring Session JDBC performs an INSERT when it thinks an attribute was added to the session, while a concurrent request might have added the same attribute already causing the INSERT to fail. This really requires some sort of UPSERT, but there's no standard way to do that in SQL. |
Thank you for providing a sample @jkuipers.
Could you describe which section of the code you are referring to here? |
Here's the full class with my edits:
|
BTW, in case this wasn't clear already: please consider to incorporate the change. I'll create a separate issue for the other bug. This change is breaking for people defining their own query for the insert attributes, as the parameter order changed, but honestly I don't think anyone does that and it would be trivial for them to switch the order in their own query. OTOH it does fix a showstopping bug that happens as soon as two people start using you app with SQL Server. |
Thank you @jkuipers. |
I didn't include a license in my repo with the TestContainers test, but feel free to incorporate that one as well. The other test there will still fail, but that's more of a design flaw in spring-session-jdbc which seems to believe it has exclusive access to the session state from a single thread and can therefore derive if an INSERT or UPDATE should be used. |
Hi @jkuipers,
See #1031 for background on why this
See #1213. I'll try to take a closer look over the next couple of days. |
I see: that's tricky, as the current code with the DB schema it provides makes spring-session-jdbc pretty much unusable on SQL Server (can't even have two users concurrently doing smth with their own session). The deadlock graph that was provided here shows the problem is with the unique index on the session table, which is updated in the same transaction that then performs the insert into the attributes using the nested select. Maybe some SQL Server specific change of index type could work around the issue, but I'm not a SQL Server DBA. In general the whole approach taken by spring-session-jdbc seems to be a tricky one: it needs to reason about what changes are made to an existing session so that it knows how to update the DB, but doesn't account for concurrent updates (which could involve deletions of attributes or the session itself). |
I am facing similar issue in my project and we are using SQL Server |
We are encountering a similar issue on our project using the following combination of main Spring Frameworks in conjunction with a MySQL 8.0.20 Server which is run as a docker container, using the official mysql:8.0.20 docker image:
We are using the mysql schema for the Also the Since we are using the default session cleanup cron expression "0 * * * * *" we observed the issue that requests to our server which are happening around the 00 second of each minute might be responding with an error 500. Internally the already mentioned
After some debugging we found out that this is triggered when the method Specifically this issue happens in our application as soon as a browser requests static resources in parallel were each request contains the same session. If this is happening around the 00 second of each minute we have the chance to run into the described From our point of view this seems to be a race condition which happens under the following circumstances:
In order to mitigate this issue we tried to reduce access on sessions on parallel requests such as those that are aiming for our static resources. We could successfully eliminate those calls in our own code. The only call to We explored other ways to eliminate this issue, for instance by changing the default session cleanup cron expression, but then again this is only a mitigating workaround, not a solution, since there is still a timing that could be hit by our clients. Is there any news on this issue? |
At present, the SQL statement used to insert a session attribute record contains a nested select statement that verifies the existence of parent record in the session table. Such approach can be susceptible to deadlocks on certain RDMBSs. This commit optimizes the SQL statement used to insert session attribute so that it doesn't perform a nested select statement. Closes: spring-projects#1550
At present, the SQL statement used to insert a session attribute record contains a nested select statement that verifies the existence of parent record in the session table. Such approach can be susceptible to deadlocks on certain RDMBSs. This commit optimizes the SQL statement used to insert session attribute so that it doesn't perform a nested select statement. Closes: spring-projects#1550
We are also facing the deadlocks in our production set up. |
I have a deadlock in SQL Server.
LOG
I read all the previous issues about this problem.
As #1083 @TorosyanV said:
we need to always keep order to avoid deadlock on parent and child relationship table's operation.
like as below:
parnet = SPRING_SESSION
child = SPRING_SESSION_ATTRIBUTES
insert parent first, then child
update parent first, then child
delete parent first, then child
select parent first, then child
I looked at the JdbcOperationsSessionRepository code,
and I understood it looks like keeping transaction order.
but major problem here is DELETE_SESSIONS_BY_EXPIRY_TIME_QUERY is depending on each relational database's CASCADE ON DELETE algorithm
which might not be the same order deleting parent and child.
and also, we are difficult position to know or change relational database's CASCADE ON DELETE algorithm.
It is better not rely on to database's CASCADE ON DELETE.
I wish, Spring framework will ensure the every session table's transaction operation order by own.
The text was updated successfully, but these errors were encountered: