Skip to content

Commit cb6f7fd

Browse files
committed
Insert new attributes conditionally in JDBC repo
At present, the insert of new attributes in JdbcOperationsSessionRepository is done unconditionally. This can cause data integrity violation errors with concurrent requests, where one request attempts to add new session attribute while the other, concurrent request, deletes the session. This commit addresses the described scenario by executing insert of new attributes conditionally on presence of parent record. Closes gh-1153
1 parent b50a4e2 commit cb6f7fd

File tree

2 files changed

+34
-7
lines changed

2 files changed

+34
-7
lines changed

spring-session/src/integration-test/java/org/springframework/session/jdbc/AbstractJdbcOperationsSessionRepositoryITests.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -608,6 +608,31 @@ public void cleanupInactiveSessionsUsingSessionDefinedInterval() {
608608
assertThat(this.repository.getSession(session.getId())).isNull();
609609
}
610610

611+
@Test // gh-1153
612+
public void saveDeleted() {
613+
JdbcOperationsSessionRepository.JdbcSession session = this.repository.createSession();
614+
this.repository.save(session);
615+
session = this.repository.getSession(session.getId());
616+
this.repository.delete(session.getId());
617+
session.setLastAccessedTime(System.currentTimeMillis());
618+
this.repository.save(session);
619+
620+
assertThat(this.repository.getSession(session.getId())).isNull();
621+
}
622+
623+
@Test // gh-1153
624+
public void saveDeletedAddAttribute() {
625+
JdbcOperationsSessionRepository.JdbcSession session = this.repository.createSession();
626+
this.repository.save(session);
627+
session = this.repository.getSession(session.getId());
628+
this.repository.delete(session.getId());
629+
session.setLastAccessedTime(System.currentTimeMillis());
630+
session.setAttribute("testName", "testValue1");
631+
this.repository.save(session);
632+
633+
assertThat(this.repository.getSession(session.getId())).isNull();
634+
}
635+
611636
private String getSecurityName() {
612637
return this.context.getAuthentication().getName();
613638
}

spring-session/src/main/java/org/springframework/session/jdbc/JdbcOperationsSessionRepository.java

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,9 @@ public class JdbcOperationsSessionRepository implements
143143

144144
private static final String CREATE_SESSION_ATTRIBUTE_QUERY =
145145
"INSERT INTO %TABLE_NAME%_ATTRIBUTES(SESSION_ID, ATTRIBUTE_NAME, ATTRIBUTE_BYTES) " +
146-
"VALUES (?, ?, ?)";
146+
"SELECT SESSION_ID, ?, ? " +
147+
"FROM %TABLE_NAME% " +
148+
"WHERE SESSION_ID = ?";
147149

148150
private static final String GET_SESSION_QUERY =
149151
"SELECT S.SESSION_ID, S.CREATION_TIME, S.LAST_ACCESS_TIME, S.MAX_INACTIVE_INTERVAL, SA.ATTRIBUTE_NAME, SA.ATTRIBUTE_BYTES " +
@@ -398,9 +400,9 @@ public void setValues(PreparedStatement ps) throws SQLException {
398400

399401
public void setValues(PreparedStatement ps, int i) throws SQLException {
400402
String attributeName = attributeNames.get(i);
401-
ps.setString(1, session.getId());
402-
ps.setString(2, attributeName);
403-
serialize(ps, 3, session.getAttribute(attributeName));
403+
ps.setString(1, attributeName);
404+
serialize(ps, 2, session.getAttribute(attributeName));
405+
ps.setString(3, session.getId());
404406
}
405407

406408
public int getBatchSize() {
@@ -465,9 +467,9 @@ public void setValues(PreparedStatement ps) throws SQLException {
465467
new PreparedStatementSetter() {
466468

467469
public void setValues(PreparedStatement ps) throws SQLException {
468-
ps.setString(1, session.getId());
469-
ps.setString(2, entry.getKey());
470-
serialize(ps, 3, entry.getValue());
470+
ps.setString(1, entry.getKey());
471+
serialize(ps, 2, entry.getValue());
472+
ps.setString(3, session.getId());
471473
}
472474

473475
});

0 commit comments

Comments
 (0)