Skip to content

Commit 87c2e53

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-1031
1 parent 268ba66 commit 87c2e53

File tree

2 files changed

+34
-7
lines changed

2 files changed

+34
-7
lines changed

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

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -743,6 +743,31 @@ public void saveUpdatedRemoveAndAddAttribute() {
743743
assertThat(session.<String>getAttribute("testName")).isEqualTo("testValue2");
744744
}
745745

746+
@Test // gh-1031
747+
public void saveDeleted() {
748+
JdbcOperationsSessionRepository.JdbcSession session = this.repository.createSession();
749+
this.repository.save(session);
750+
session = this.repository.findById(session.getId());
751+
this.repository.deleteById(session.getId());
752+
session.setLastAccessedTime(Instant.now());
753+
this.repository.save(session);
754+
755+
assertThat(this.repository.findById(session.getId())).isNull();
756+
}
757+
758+
@Test // gh-1031
759+
public void saveDeletedAddAttribute() {
760+
JdbcOperationsSessionRepository.JdbcSession session = this.repository.createSession();
761+
this.repository.save(session);
762+
session = this.repository.findById(session.getId());
763+
this.repository.deleteById(session.getId());
764+
session.setLastAccessedTime(Instant.now());
765+
session.setAttribute("testName", "testValue1");
766+
this.repository.save(session);
767+
768+
assertThat(this.repository.findById(session.getId())).isNull();
769+
}
770+
746771
private String getSecurityName() {
747772
return this.context.getAuthentication().getName();
748773
}

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

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

145145
private static final String CREATE_SESSION_ATTRIBUTE_QUERY =
146146
"INSERT INTO %TABLE_NAME%_ATTRIBUTES(SESSION_PRIMARY_ID, ATTRIBUTE_NAME, ATTRIBUTE_BYTES) " +
147-
"VALUES (?, ?, ?)";
147+
"SELECT PRIMARY_ID, ?, ? " +
148+
"FROM %TABLE_NAME% " +
149+
"WHERE SESSION_ID = ?";
148150

149151
private static final String GET_SESSION_QUERY =
150152
"SELECT S.PRIMARY_ID, S.SESSION_ID, S.CREATION_TIME, S.LAST_ACCESS_TIME, S.MAX_INACTIVE_INTERVAL, SA.ATTRIBUTE_NAME, SA.ATTRIBUTE_BYTES " +
@@ -499,9 +501,9 @@ private void insertSessionAttributes(JdbcSession session, List<String> attribute
499501
@Override
500502
public void setValues(PreparedStatement ps, int i) throws SQLException {
501503
String attributeName = attributeNames.get(i);
502-
ps.setString(1, session.primaryKey);
503-
ps.setString(2, attributeName);
504-
serialize(ps, 3, session.getAttribute(attributeName));
504+
ps.setString(1, attributeName);
505+
serialize(ps, 2, session.getAttribute(attributeName));
506+
ps.setString(3, session.getId());
505507
}
506508

507509
@Override
@@ -514,9 +516,9 @@ public int getBatchSize() {
514516
else {
515517
this.jdbcOperations.update(this.createSessionAttributeQuery, (ps) -> {
516518
String attributeName = attributeNames.get(0);
517-
ps.setString(1, session.primaryKey);
518-
ps.setString(2, attributeName);
519-
serialize(ps, 3, session.getAttribute(attributeName));
519+
ps.setString(1, attributeName);
520+
serialize(ps, 2, session.getAttribute(attributeName));
521+
ps.setString(3, session.getId());
520522
});
521523
}
522524
}

0 commit comments

Comments
 (0)