From be2604ca69c6d3cac08dd1663899d53f6d624850 Mon Sep 17 00:00:00 2001 From: Rob Winch Date: Thu, 20 Jul 2017 15:03:18 -0500 Subject: [PATCH] Add Session.changeSessionId --- docs/src/test/java/docs/IndexDocTests.java | 4 +- .../src/main/java/sample/Initializer.java | 5 +- .../session/MapReactorSessionRepository.java | 20 ++-- .../springframework/session/MapSession.java | 24 +++- .../session/MapSessionRepository.java | 14 ++- .../org/springframework/session/Session.java | 6 + .../web/http/SessionRepositoryFilter.java | 28 +---- .../MapReactorSessionRepositoryTests.java | 28 +++++ .../session/MapSessionRepositoryTests.java | 28 +++++ .../session/MapSessionTests.java | 4 + .../http/SessionRepositoryFilterTests.java | 14 +-- ...edisOperationsSessionRepositoryITests.java | 82 +++++++++++++ .../RedisOperationsSessionRepository.java | 18 ++- ...RedisOperationsSessionRepositoryTests.java | 10 ++ .../AbstractHazelcastRepositoryITests.java | 89 ++++++++++++++ .../hazelcast/HazelcastSessionRepository.java | 12 ++ ...JdbcOperationsSessionRepositoryITests.java | 92 +++++++++++++++ .../jdbc/JdbcOperationsSessionRepository.java | 110 ++++++++++-------- .../session/jdbc/schema-db2.sql | 14 ++- .../session/jdbc/schema-derby.sql | 14 ++- .../session/jdbc/schema-h2.sql | 14 ++- .../session/jdbc/schema-hsqldb.sql | 14 ++- .../session/jdbc/schema-mysql.sql | 14 ++- .../session/jdbc/schema-oracle.sql | 14 ++- .../session/jdbc/schema-postgresql.sql | 14 ++- .../session/jdbc/schema-sqlite.sql | 14 ++- .../session/jdbc/schema-sqlserver.sql | 14 ++- .../session/jdbc/schema-sybase.sql | 14 ++- .../JdbcOperationsSessionRepositoryTests.java | 17 +-- 29 files changed, 576 insertions(+), 169 deletions(-) diff --git a/docs/src/test/java/docs/IndexDocTests.java b/docs/src/test/java/docs/IndexDocTests.java index 838599969..01ace774c 100644 --- a/docs/src/test/java/docs/IndexDocTests.java +++ b/docs/src/test/java/docs/IndexDocTests.java @@ -50,7 +50,7 @@ public class IndexDocTests { @Test public void repositoryDemo() { - RepositoryDemo demo = new RepositoryDemo<>(); + RepositoryDemo demo = new RepositoryDemo<>(); demo.repository = new MapSessionRepository(); demo.demo(); @@ -82,7 +82,7 @@ public void demo() { @Test public void expireRepositoryDemo() { - ExpiringRepositoryDemo demo = new ExpiringRepositoryDemo<>(); + ExpiringRepositoryDemo demo = new ExpiringRepositoryDemo<>(); demo.repository = new MapSessionRepository(); demo.demo(); diff --git a/samples/misc/hazelcast/src/main/java/sample/Initializer.java b/samples/misc/hazelcast/src/main/java/sample/Initializer.java index 36d3227fc..fb033d423 100644 --- a/samples/misc/hazelcast/src/main/java/sample/Initializer.java +++ b/samples/misc/hazelcast/src/main/java/sample/Initializer.java @@ -34,7 +34,6 @@ import org.springframework.session.MapSession; import org.springframework.session.MapSessionRepository; import org.springframework.session.Session; -import org.springframework.session.SessionRepository; import org.springframework.session.web.http.SessionRepositoryFilter; @WebListener @@ -48,8 +47,8 @@ public void contextInitialized(ServletContextEvent sce) { this.instance = createHazelcastInstance(); Map sessions = this.instance.getMap(SESSION_MAP_NAME); - SessionRepository sessionRepository = new MapSessionRepository(sessions); - SessionRepositoryFilter filter = new SessionRepositoryFilter<>( + MapSessionRepository sessionRepository = new MapSessionRepository(sessions); + SessionRepositoryFilter filter = new SessionRepositoryFilter<>( sessionRepository); Dynamic fr = sce.getServletContext().addFilter("springSessionFilter", filter); diff --git a/spring-session-core/src/main/java/org/springframework/session/MapReactorSessionRepository.java b/spring-session-core/src/main/java/org/springframework/session/MapReactorSessionRepository.java index 087308be9..e13a50d3e 100644 --- a/spring-session-core/src/main/java/org/springframework/session/MapReactorSessionRepository.java +++ b/spring-session-core/src/main/java/org/springframework/session/MapReactorSessionRepository.java @@ -39,7 +39,7 @@ * @author Rob Winch * @since 2.0 */ -public class MapReactorSessionRepository implements ReactorSessionRepository { +public class MapReactorSessionRepository implements ReactorSessionRepository { /** * If non-null, this value is used to override * {@link Session#setMaxInactiveInterval(Duration)}. @@ -80,7 +80,7 @@ public MapReactorSessionRepository(Session... sessions) { } this.sessions = new ConcurrentHashMap<>(); for (Session session : sessions) { - this.performSave(session); + this.performSave(new MapSession(session)); } } @@ -96,7 +96,7 @@ public MapReactorSessionRepository(Iterable sessions) { } this.sessions = new ConcurrentHashMap<>(); for (Session session : sessions) { - this.performSave(session); + this.performSave(new MapSession(session)); } } @@ -110,15 +110,19 @@ public void setDefaultMaxInactiveInterval(int defaultMaxInactiveInterval) { this.defaultMaxInactiveInterval = Integer.valueOf(defaultMaxInactiveInterval); } - public Mono save(Session session) { + public Mono save(MapSession session) { return Mono.fromRunnable(() -> performSave(session)); } - private void performSave(Session session) { + private void performSave(MapSession session) { + if (!session.getId().equals(session.getOriginalId())) { + this.sessions.remove(session.getOriginalId()); + session.setOriginalId(session.getId()); + } this.sessions.put(session.getId(), new MapSession(session)); } - public Mono findById(String id) { + public Mono findById(String id) { return Mono.defer(() -> { Session saved = this.sessions.get(id); if (saved == null) { @@ -136,9 +140,9 @@ public Mono delete(String id) { return Mono.fromRunnable(() -> this.sessions.remove(id)); } - public Mono createSession() { + public Mono createSession() { return Mono.defer(() -> { - Session result = new MapSession(); + MapSession result = new MapSession(); if (this.defaultMaxInactiveInterval != null) { result.setMaxInactiveInterval( Duration.ofSeconds(this.defaultMaxInactiveInterval)); diff --git a/spring-session-core/src/main/java/org/springframework/session/MapSession.java b/spring-session-core/src/main/java/org/springframework/session/MapSession.java index f0b7764ea..ad61fb878 100644 --- a/spring-session-core/src/main/java/org/springframework/session/MapSession.java +++ b/spring-session-core/src/main/java/org/springframework/session/MapSession.java @@ -52,6 +52,7 @@ public final class MapSession implements Session, Serializable { public static final int DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS = 1800; private String id; + private String originalId; private Map sessionAttrs = new HashMap<>(); private Instant creationTime = Instant.now(); private Instant lastAccessedTime = this.creationTime; @@ -65,9 +66,10 @@ public final class MapSession implements Session, Serializable { * Creates a new instance with a secure randomly generated identifier. */ public MapSession() { - this(UUID.randomUUID().toString()); + this(generateId()); } + /** * Creates a new instance with the specified id. This is preferred to the default * constructor when the id is known to prevent unnecessary consumption on entropy @@ -77,6 +79,7 @@ public MapSession() { */ public MapSession(String id) { this.id = id; + this.originalId = id; } /** @@ -90,6 +93,7 @@ public MapSession(Session session) { throw new IllegalArgumentException("session cannot be null"); } this.id = session.getId(); + this.originalId = this.id; this.sessionAttrs = new HashMap<>( session.getAttributeNames().size()); for (String attrName : session.getAttributeNames()) { @@ -115,6 +119,20 @@ public String getId() { return this.id; } + String getOriginalId() { + return this.originalId; + } + + void setOriginalId(String originalId) { + this.originalId = originalId; + } + + public String changeSessionId() { + String changedId = generateId(); + setId(changedId); + return changedId; + } + public Instant getLastAccessedTime() { return this.lastAccessedTime; } @@ -188,5 +206,9 @@ public int hashCode() { return this.id.hashCode(); } + private static String generateId() { + return UUID.randomUUID().toString(); + } + private static final long serialVersionUID = 7160779239673823561L; } diff --git a/spring-session-core/src/main/java/org/springframework/session/MapSessionRepository.java b/spring-session-core/src/main/java/org/springframework/session/MapSessionRepository.java index 086ddcb53..cd6dfb678 100644 --- a/spring-session-core/src/main/java/org/springframework/session/MapSessionRepository.java +++ b/spring-session-core/src/main/java/org/springframework/session/MapSessionRepository.java @@ -37,7 +37,7 @@ * @author Rob Winch * @since 1.0 */ -public class MapSessionRepository implements SessionRepository { +public class MapSessionRepository implements SessionRepository { /** * If non-null, this value is used to override * {@link Session#setMaxInactiveInterval(Duration)}. @@ -76,11 +76,15 @@ public void setDefaultMaxInactiveInterval(int defaultMaxInactiveInterval) { this.defaultMaxInactiveInterval = Integer.valueOf(defaultMaxInactiveInterval); } - public void save(Session session) { + public void save(MapSession session) { + if (!session.getId().equals(session.getOriginalId())) { + this.sessions.remove(session.getOriginalId()); + session.setOriginalId(session.getId()); + } this.sessions.put(session.getId(), new MapSession(session)); } - public Session findById(String id) { + public MapSession findById(String id) { Session saved = this.sessions.get(id); if (saved == null) { return null; @@ -96,8 +100,8 @@ public void deleteById(String id) { this.sessions.remove(id); } - public Session createSession() { - Session result = new MapSession(); + public MapSession createSession() { + MapSession result = new MapSession(); if (this.defaultMaxInactiveInterval != null) { result.setMaxInactiveInterval( Duration.ofSeconds(this.defaultMaxInactiveInterval)); diff --git a/spring-session-core/src/main/java/org/springframework/session/Session.java b/spring-session-core/src/main/java/org/springframework/session/Session.java index 3014c494d..0dbdf911f 100644 --- a/spring-session-core/src/main/java/org/springframework/session/Session.java +++ b/spring-session-core/src/main/java/org/springframework/session/Session.java @@ -37,6 +37,12 @@ public interface Session { */ String getId(); + /** + * Changes the session id. After invoking the {@link #getId()} will return a new identifier. + * @return the new session id which {@link #getId()} will now return + */ + String changeSessionId(); + /** * Gets the Object associated with the specified name or null if no Object is * associated to that name. diff --git a/spring-session-core/src/main/java/org/springframework/session/web/http/SessionRepositoryFilter.java b/spring-session-core/src/main/java/org/springframework/session/web/http/SessionRepositoryFilter.java index 221183f10..59e21e6db 100644 --- a/spring-session-core/src/main/java/org/springframework/session/web/http/SessionRepositoryFilter.java +++ b/spring-session-core/src/main/java/org/springframework/session/web/http/SessionRepositoryFilter.java @@ -18,9 +18,6 @@ import java.io.IOException; import java.time.Instant; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.Map; import javax.servlet.FilterChain; import javax.servlet.ServletContext; @@ -274,30 +271,7 @@ public String changeSessionId() { "Cannot change session ID. There is no session associated with this request."); } - // eagerly get session attributes in case implementation lazily loads them - Map attrs = new HashMap<>(); - Enumeration iAttrNames = session.getAttributeNames(); - while (iAttrNames.hasMoreElements()) { - String attrName = iAttrNames.nextElement(); - Object value = session.getAttribute(attrName); - - attrs.put(attrName, value); - } - - SessionRepositoryFilter.this.sessionRepository.deleteById(session.getId()); - HttpSessionWrapper original = getCurrentSession(); - setCurrentSession(null); - - HttpSessionWrapper newSession = getSession(); - original.setSession(newSession.getSession()); - - newSession.setMaxInactiveInterval(session.getMaxInactiveInterval()); - for (Map.Entry attr : attrs.entrySet()) { - String attrName = attr.getKey(); - Object attrValue = attr.getValue(); - newSession.setAttribute(attrName, attrValue); - } - return newSession.getId(); + return getCurrentSession().getSession().changeSessionId(); } @Override diff --git a/spring-session-core/src/test/java/org/springframework/session/MapReactorSessionRepositoryTests.java b/spring-session-core/src/test/java/org/springframework/session/MapReactorSessionRepositoryTests.java index c52dbeac4..22604f565 100644 --- a/spring-session-core/src/test/java/org/springframework/session/MapReactorSessionRepositoryTests.java +++ b/spring-session-core/src/test/java/org/springframework/session/MapReactorSessionRepositoryTests.java @@ -145,4 +145,32 @@ public void createSessionWhenCustomMaxInactiveIntervalThenCustomMaxInactiveInter assertThat(session.getMaxInactiveInterval()) .isEqualTo(expectedMaxInterval); } + + @Test + public void changeSessionIdWhenNotYetSaved() { + MapSession createSession = this.repository.createSession().block(); + + String originalId = createSession.getId(); + createSession.changeSessionId(); + + this.repository.save(createSession).block(); + + assertThat(this.repository.findById(originalId).block()).isNull(); + assertThat(this.repository.findById(createSession.getId()).block()).isNotNull(); + } + + @Test + public void changeSessionIdWhenSaved() { + MapSession createSession = this.repository.createSession().block(); + + this.repository.save(createSession).block(); + + String originalId = createSession.getId(); + createSession.changeSessionId(); + + this.repository.save(createSession).block(); + + assertThat(this.repository.findById(originalId).block()).isNull(); + assertThat(this.repository.findById(createSession.getId()).block()).isNotNull(); + } } diff --git a/spring-session-core/src/test/java/org/springframework/session/MapSessionRepositoryTests.java b/spring-session-core/src/test/java/org/springframework/session/MapSessionRepositoryTests.java index 0149abe22..15fca2e21 100644 --- a/spring-session-core/src/test/java/org/springframework/session/MapSessionRepositoryTests.java +++ b/spring-session-core/src/test/java/org/springframework/session/MapSessionRepositoryTests.java @@ -66,4 +66,32 @@ public void createSessionCustomDefaultExpiration() { assertThat(session.getMaxInactiveInterval()) .isEqualTo(expectedMaxInterval); } + + @Test + public void changeSessionIdWhenNotYetSaved() { + MapSession createSession = this.repository.createSession(); + + String originalId = createSession.getId(); + createSession.changeSessionId(); + + this.repository.save(createSession); + + assertThat(this.repository.findById(originalId)).isNull(); + assertThat(this.repository.findById(createSession.getId())).isNotNull(); + } + + @Test + public void changeSessionIdWhenSaved() { + MapSession createSession = this.repository.createSession(); + + this.repository.save(createSession); + + String originalId = createSession.getId(); + createSession.changeSessionId(); + + this.repository.save(createSession); + + assertThat(this.repository.findById(originalId)).isNull(); + assertThat(this.repository.findById(createSession.getId())).isNotNull(); + } } diff --git a/spring-session-core/src/test/java/org/springframework/session/MapSessionTests.java b/spring-session-core/src/test/java/org/springframework/session/MapSessionTests.java index 20940861c..8df3490b1 100644 --- a/spring-session-core/src/test/java/org/springframework/session/MapSessionTests.java +++ b/spring-session-core/src/test/java/org/springframework/session/MapSessionTests.java @@ -134,6 +134,10 @@ public Instant getCreationTime() { return Instant.EPOCH; } + public String changeSessionId() { + throw new UnsupportedOperationException(); + } + public String getId() { return "id"; } diff --git a/spring-session-core/src/test/java/org/springframework/session/web/http/SessionRepositoryFilterTests.java b/spring-session-core/src/test/java/org/springframework/session/web/http/SessionRepositoryFilterTests.java index 3f510b54d..1a65b8aa3 100644 --- a/spring-session-core/src/test/java/org/springframework/session/web/http/SessionRepositoryFilterTests.java +++ b/spring-session-core/src/test/java/org/springframework/session/web/http/SessionRepositoryFilterTests.java @@ -76,9 +76,9 @@ public class SessionRepositoryFilterTests { private Map sessions; - private SessionRepository sessionRepository; + private SessionRepository sessionRepository; - private SessionRepositoryFilter filter; + private SessionRepositoryFilter filter; private MockHttpServletRequest request; @@ -422,7 +422,7 @@ public void doFilter(HttpServletRequest wrappedRequest) { public void doFilterSetsCookieIfChanged() throws Exception { this.sessionRepository = new MapSessionRepository() { @Override - public Session findById(String id) { + public MapSession findById(String id) { return createSession(); } }; @@ -1256,7 +1256,7 @@ public void doFilter(HttpServletRequest wrappedRequest, @SuppressWarnings("unchecked") public void doFilterRequestSessionNoRequestSessionNoSessionRepositoryInteractions() throws Exception { - SessionRepository sessionRepository = spy(new MapSessionRepository()); + SessionRepository sessionRepository = spy(new MapSessionRepository()); this.filter = new SessionRepositoryFilter<>(sessionRepository); @@ -1283,7 +1283,7 @@ public void doFilter(HttpServletRequest wrappedRequest, @Test public void doFilterLazySessionCreation() throws Exception { - SessionRepository sessionRepository = spy(new MapSessionRepository()); + SessionRepository sessionRepository = spy(new MapSessionRepository()); this.filter = new SessionRepositoryFilter<>(sessionRepository); @@ -1299,9 +1299,9 @@ public void doFilter(HttpServletRequest wrappedRequest, @Test public void doFilterLazySessionUpdates() throws Exception { - Session session = this.sessionRepository.createSession(); + MapSession session = this.sessionRepository.createSession(); this.sessionRepository.save(session); - SessionRepository sessionRepository = spy(this.sessionRepository); + SessionRepository sessionRepository = spy(this.sessionRepository); setSessionCookie(session.getId()); this.filter = new SessionRepositoryFilter<>(sessionRepository); diff --git a/spring-session-data-redis/src/integration-test/java/org/springframework/session/data/redis/RedisOperationsSessionRepositoryITests.java b/spring-session-data-redis/src/integration-test/java/org/springframework/session/data/redis/RedisOperationsSessionRepositoryITests.java index 206f236b2..e32744ea6 100644 --- a/spring-session-data-redis/src/integration-test/java/org/springframework/session/data/redis/RedisOperationsSessionRepositoryITests.java +++ b/spring-session-data-redis/src/integration-test/java/org/springframework/session/data/redis/RedisOperationsSessionRepositoryITests.java @@ -455,6 +455,88 @@ public void findByChangedSecurityPrincipalNameReload() throws Exception { assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId()); } + @Test + public void changeSessionIdWhenOnlyChangeId() throws Exception { + String attrName = "changeSessionId"; + String attrValue = "changeSessionId-value"; + RedisSession toSave = this.repository.createSession(); + toSave.setAttribute(attrName, attrValue); + + this.repository.save(toSave); + + RedisSession findById = this.repository.findById(toSave.getId()); + + assertThat(findById.getAttribute(attrName)).isEqualTo(attrValue); + + String originalFindById = findById.getId(); + String changeSessionId = findById.changeSessionId(); + + this.repository.save(findById); + + assertThat(this.repository.findById(originalFindById)).isNull(); + + RedisSession findByChangeSessionId = this.repository.findById(changeSessionId); + + assertThat(findByChangeSessionId.getAttribute(attrName)).isEqualTo(attrValue); + } + + @Test + public void changeSessionIdWhenChangeTwice() throws Exception { + RedisSession toSave = this.repository.createSession(); + + this.repository.save(toSave); + + String originalId = toSave.getId(); + String changeId1 = toSave.changeSessionId(); + String changeId2 = toSave.changeSessionId(); + + this.repository.save(toSave); + + assertThat(this.repository.findById(originalId)).isNull(); + assertThat(this.repository.findById(changeId1)).isNull(); + assertThat(this.repository.findById(changeId2)).isNotNull(); + } + + @Test + public void changeSessionIdWhenSetAttributeOnChangedSession() throws Exception { + String attrName = "changeSessionId"; + String attrValue = "changeSessionId-value"; + + RedisSession toSave = this.repository.createSession(); + + this.repository.save(toSave); + + RedisSession findById = this.repository.findById(toSave.getId()); + + findById.setAttribute(attrName, attrValue); + + String originalFindById = findById.getId(); + String changeSessionId = findById.changeSessionId(); + + this.repository.save(findById); + + assertThat(this.repository.findById(originalFindById)).isNull(); + + RedisSession findByChangeSessionId = this.repository.findById(changeSessionId); + + assertThat(findByChangeSessionId.getAttribute(attrName)).isEqualTo(attrValue); + } + + @Test + public void changeSessionIdWhenHasNotSaved() throws Exception { + String attrName = "changeSessionId"; + String attrValue = "changeSessionId-value"; + + RedisSession toSave = this.repository.createSession(); + String originalId = toSave.getId(); + toSave.changeSessionId(); + + this.repository.save(toSave); + + assertThat(this.repository.findById(toSave.getId())).isNotNull(); + assertThat(this.repository.findById(originalId)).isNull(); + } + private String getSecurityName() { return this.context.getAuthentication().getName(); } diff --git a/spring-session-data-redis/src/main/java/org/springframework/session/data/redis/RedisOperationsSessionRepository.java b/spring-session-data-redis/src/main/java/org/springframework/session/data/redis/RedisOperationsSessionRepository.java index f6644fec1..35f0e69a1 100644 --- a/spring-session-data-redis/src/main/java/org/springframework/session/data/redis/RedisOperationsSessionRepository.java +++ b/spring-session-data-redis/src/main/java/org/springframework/session/data/redis/RedisOperationsSessionRepository.java @@ -675,6 +675,7 @@ final class RedisSession implements Session { private Map delta = new HashMap<>(); private boolean isNew; private String originalPrincipalName; + private String originalSessionId; /** * Creates a new instance ensuring to mark all of the new attributes to be @@ -699,6 +700,7 @@ final class RedisSession implements Session { Assert.notNull(cached, "MapSession cannot be null"); this.cached = cached; this.originalPrincipalName = PRINCIPAL_NAME_RESOLVER.resolvePrincipal(this); + this.originalSessionId = cached.getId(); } public void setNew(boolean isNew) { @@ -726,6 +728,10 @@ public String getId() { return this.cached.getId(); } + public String changeSessionId() { + return this.cached.changeSessionId(); + } + public Instant getLastAccessedTime() { return this.cached.getLastAccessedTime(); } @@ -773,10 +779,11 @@ private void putAndFlush(String a, Object v) { * session. */ private void saveDelta() { + String sessionId = getId(); + saveChangeSessionId(sessionId); if (this.delta.isEmpty()) { return; } - String sessionId = getId(); getSessionBoundHashOperations(sessionId).putAll(this.delta); String principalSessionKey = getSessionAttrNameKey( FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME); @@ -806,6 +813,15 @@ private void saveDelta() { RedisOperationsSessionRepository.this.expirationPolicy .onExpirationUpdated(originalExpiration, this); } + + private void saveChangeSessionId(String sessionId) { + if (!isNew() && !sessionId.equals(this.originalSessionId)) { + String originalSessionIdKey = getSessionKey(this.originalSessionId); + String sessionIdKey = getSessionKey(sessionId); + RedisOperationsSessionRepository.this.sessionRedisOperations.rename(originalSessionIdKey, sessionIdKey); + this.originalSessionId = sessionId; + } + } } /** diff --git a/spring-session-data-redis/src/test/java/org/springframework/session/data/redis/RedisOperationsSessionRepositoryTests.java b/spring-session-data-redis/src/test/java/org/springframework/session/data/redis/RedisOperationsSessionRepositoryTests.java index d99415000..c45037dd4 100644 --- a/spring-session-data-redis/src/test/java/org/springframework/session/data/redis/RedisOperationsSessionRepositoryTests.java +++ b/spring-session-data-redis/src/test/java/org/springframework/session/data/redis/RedisOperationsSessionRepositoryTests.java @@ -131,6 +131,16 @@ public void constructorConnectionFactory() { this.redisRepository.save(session); } + @Test + public void changeSessionId() { + RedisSession createSession = this.redisRepository.createSession(); + String originalId = createSession.getId(); + String changeSessionId = createSession.changeSessionId(); + + assertThat(originalId).isNotEqualTo(changeSessionId); + assertThat(createSession.getId()).isEqualTo(createSession.getId()); + } + @Test public void createSessionDefaultMaxInactiveInterval() throws Exception { Session session = this.redisRepository.createSession(); diff --git a/spring-session-hazelcast/src/integration-test/java/org/springframework/session/hazelcast/AbstractHazelcastRepositoryITests.java b/spring-session-hazelcast/src/integration-test/java/org/springframework/session/hazelcast/AbstractHazelcastRepositoryITests.java index c7d536f87..0207dd580 100644 --- a/spring-session-hazelcast/src/integration-test/java/org/springframework/session/hazelcast/AbstractHazelcastRepositoryITests.java +++ b/spring-session-hazelcast/src/integration-test/java/org/springframework/session/hazelcast/AbstractHazelcastRepositoryITests.java @@ -60,4 +60,93 @@ public void createAndDestroySession() { assertThat(hazelcastMap.size()).isEqualTo(0); } + @Test + public void changeSessionIdWhenOnlyChangeId() throws Exception { + String attrName = "changeSessionId"; + String attrValue = "changeSessionId-value"; + HazelcastSession toSave = this.repository.createSession(); + toSave.setAttribute(attrName, attrValue); + + this.repository.save(toSave); + + HazelcastSession findById = this.repository.findById(toSave.getId()); + + assertThat(findById.getAttribute(attrName)).isEqualTo(attrValue); + + String originalFindById = findById.getId(); + String changeSessionId = findById.changeSessionId(); + + this.repository.save(findById); + + assertThat(this.repository.findById(originalFindById)).isNull(); + + HazelcastSession findByChangeSessionId = this.repository.findById(changeSessionId); + + assertThat(findByChangeSessionId.getAttribute(attrName)).isEqualTo(attrValue); + + this.repository.deleteById(changeSessionId); + } + + @Test + public void changeSessionIdWhenChangeTwice() throws Exception { + HazelcastSession toSave = this.repository.createSession(); + + this.repository.save(toSave); + + String originalId = toSave.getId(); + String changeId1 = toSave.changeSessionId(); + String changeId2 = toSave.changeSessionId(); + + this.repository.save(toSave); + + assertThat(this.repository.findById(originalId)).isNull(); + assertThat(this.repository.findById(changeId1)).isNull(); + assertThat(this.repository.findById(changeId2)).isNotNull(); + + this.repository.deleteById(changeId2); + } + + @Test + public void changeSessionIdWhenSetAttributeOnChangedSession() throws Exception { + String attrName = "changeSessionId"; + String attrValue = "changeSessionId-value"; + + HazelcastSession toSave = this.repository.createSession(); + + this.repository.save(toSave); + + HazelcastSession findById = this.repository.findById(toSave.getId()); + + findById.setAttribute(attrName, attrValue); + + String originalFindById = findById.getId(); + String changeSessionId = findById.changeSessionId(); + + this.repository.save(findById); + + assertThat(this.repository.findById(originalFindById)).isNull(); + + HazelcastSession findByChangeSessionId = this.repository.findById(changeSessionId); + + assertThat(findByChangeSessionId.getAttribute(attrName)).isEqualTo(attrValue); + + this.repository.deleteById(changeSessionId); + } + + @Test + public void changeSessionIdWhenHasNotSaved() throws Exception { + String attrName = "changeSessionId"; + String attrValue = "changeSessionId-value"; + + HazelcastSession toSave = this.repository.createSession(); + String originalId = toSave.getId(); + toSave.changeSessionId(); + + this.repository.save(toSave); + + assertThat(this.repository.findById(toSave.getId())).isNotNull(); + assertThat(this.repository.findById(originalId)).isNull(); + + this.repository.deleteById(toSave.getId()); + } } diff --git a/spring-session-hazelcast/src/main/java/org/springframework/session/hazelcast/HazelcastSessionRepository.java b/spring-session-hazelcast/src/main/java/org/springframework/session/hazelcast/HazelcastSessionRepository.java index 38149a551..212e7011e 100644 --- a/spring-session-hazelcast/src/main/java/org/springframework/session/hazelcast/HazelcastSessionRepository.java +++ b/spring-session-hazelcast/src/main/java/org/springframework/session/hazelcast/HazelcastSessionRepository.java @@ -202,6 +202,10 @@ public HazelcastSession createSession() { } public void save(HazelcastSession session) { + if (!session.getId().equals(session.originalId)) { + this.sessions.remove(session.originalId); + session.originalId = session.getId(); + } if (session.isChanged()) { this.sessions.put(session.getId(), session.getDelegate(), session.getMaxInactiveInterval().getSeconds(), TimeUnit.SECONDS); @@ -273,6 +277,7 @@ final class HazelcastSession implements Session { private final MapSession delegate; private boolean changed; + private String originalId; /** * Creates a new instance ensuring to mark all of the new attributes to be @@ -292,6 +297,7 @@ final class HazelcastSession implements Session { HazelcastSession(MapSession cached) { Assert.notNull(cached, "MapSession cannot be null"); this.delegate = cached; + this.originalId = cached.getId(); } public void setLastAccessedTime(Instant lastAccessedTime) { @@ -312,6 +318,12 @@ public String getId() { return this.delegate.getId(); } + public String changeSessionId() { + this.changed = true; + String result = this.delegate.changeSessionId(); + return result; + } + public Instant getLastAccessedTime() { return this.delegate.getLastAccessedTime(); } diff --git a/spring-session-jdbc/src/integration-test/java/org/springframework/session/jdbc/AbstractJdbcOperationsSessionRepositoryITests.java b/spring-session-jdbc/src/integration-test/java/org/springframework/session/jdbc/AbstractJdbcOperationsSessionRepositoryITests.java index 43f715bef..91a362b6a 100644 --- a/spring-session-jdbc/src/integration-test/java/org/springframework/session/jdbc/AbstractJdbcOperationsSessionRepositoryITests.java +++ b/spring-session-jdbc/src/integration-test/java/org/springframework/session/jdbc/AbstractJdbcOperationsSessionRepositoryITests.java @@ -83,6 +83,16 @@ public void setup() throws Exception { AuthorityUtils.createAuthorityList("ROLE_USER"))); } + @Test + public void saveWhenNoAttributesThenCanBeFound() throws Exception { + JdbcOperationsSessionRepository.JdbcSession toSave = this.repository + .createSession(); + + this.repository.save(toSave); + + assertThat(this.repository.findById(toSave.getId())).isNotNull(); + } + @Test public void saves() throws InterruptedException { String username = "saves-" + System.currentTimeMillis(); @@ -560,6 +570,88 @@ public void cleanupInactiveSessionsUsingSessionDefinedInterval() { assertThat(this.repository.findById(session.getId())).isNull(); } + @Test + public void changeSessionIdWhenOnlyChangeId() throws Exception { + String attrName = "changeSessionId"; + String attrValue = "changeSessionId-value"; + JdbcOperationsSessionRepository.JdbcSession toSave = this.repository.createSession(); + toSave.setAttribute(attrName, attrValue); + + this.repository.save(toSave); + + JdbcOperationsSessionRepository.JdbcSession findById = this.repository.findById(toSave.getId()); + + assertThat(findById.getAttribute(attrName)).isEqualTo(attrValue); + + String originalFindById = findById.getId(); + String changeSessionId = findById.changeSessionId(); + + this.repository.save(findById); + + assertThat(this.repository.findById(originalFindById)).isNull(); + + JdbcOperationsSessionRepository.JdbcSession findByChangeSessionId = this.repository.findById(changeSessionId); + + assertThat(findByChangeSessionId.getAttribute(attrName)).isEqualTo(attrValue); + } + + @Test + public void changeSessionIdWhenChangeTwice() throws Exception { + JdbcOperationsSessionRepository.JdbcSession toSave = this.repository.createSession(); + + this.repository.save(toSave); + + String originalId = toSave.getId(); + String changeId1 = toSave.changeSessionId(); + String changeId2 = toSave.changeSessionId(); + + this.repository.save(toSave); + + assertThat(this.repository.findById(originalId)).isNull(); + assertThat(this.repository.findById(changeId1)).isNull(); + assertThat(this.repository.findById(changeId2)).isNotNull(); + } + + @Test + public void changeSessionIdWhenSetAttributeOnChangedSession() throws Exception { + String attrName = "changeSessionId"; + String attrValue = "changeSessionId-value"; + + JdbcOperationsSessionRepository.JdbcSession toSave = this.repository.createSession(); + + this.repository.save(toSave); + + JdbcOperationsSessionRepository.JdbcSession findById = this.repository.findById(toSave.getId()); + + findById.setAttribute(attrName, attrValue); + + String originalFindById = findById.getId(); + String changeSessionId = findById.changeSessionId(); + + this.repository.save(findById); + + assertThat(this.repository.findById(originalFindById)).isNull(); + + JdbcOperationsSessionRepository.JdbcSession findByChangeSessionId = this.repository.findById(changeSessionId); + + assertThat(findByChangeSessionId.getAttribute(attrName)).isEqualTo(attrValue); + } + + @Test + public void changeSessionIdWhenHasNotSaved() throws Exception { + String attrName = "changeSessionId"; + String attrValue = "changeSessionId-value"; + + JdbcOperationsSessionRepository.JdbcSession toSave = this.repository.createSession(); + String originalId = toSave.getId(); + toSave.changeSessionId(); + + this.repository.save(toSave); + + assertThat(this.repository.findById(toSave.getId())).isNotNull(); + assertThat(this.repository.findById(originalId)).isNull(); + } + private String getSecurityName() { return this.context.getAuthentication().getName(); } diff --git a/spring-session-jdbc/src/main/java/org/springframework/session/jdbc/JdbcOperationsSessionRepository.java b/spring-session-jdbc/src/main/java/org/springframework/session/jdbc/JdbcOperationsSessionRepository.java index 6b7a981cb..f6458b256 100644 --- a/spring-session-jdbc/src/main/java/org/springframework/session/jdbc/JdbcOperationsSessionRepository.java +++ b/spring-session-jdbc/src/main/java/org/springframework/session/jdbc/JdbcOperationsSessionRepository.java @@ -27,6 +27,7 @@ import java.util.List; import java.util.Map; import java.util.Set; +import java.util.UUID; import javax.sql.DataSource; @@ -95,25 +96,26 @@ * *
  * CREATE TABLE SPRING_SESSION (
+ *   PRIMARY_ID CHAR(36) NOT NULL,
  *   SESSION_ID CHAR(36),
  *   CREATION_TIME BIGINT NOT NULL,
  *   LAST_ACCESS_TIME BIGINT NOT NULL,
  *   MAX_INACTIVE_INTERVAL INT NOT NULL,
  *   PRINCIPAL_NAME VARCHAR(100),
- *   CONSTRAINT SPRING_SESSION_PK PRIMARY KEY (SESSION_ID)
+ *   CONSTRAINT SPRING_SESSION_PK PRIMARY KEY (PRIMARY_ID)
  * );
  *
  * CREATE INDEX SPRING_SESSION_IX1 ON SPRING_SESSION (LAST_ACCESS_TIME);
  *
  * CREATE TABLE SPRING_SESSION_ATTRIBUTES (
- *  SESSION_ID CHAR(36),
+ *  SESSION_PRIMARY_ID CHAR(36) NOT NULL,
  *  ATTRIBUTE_NAME VARCHAR(200),
  *  ATTRIBUTE_BYTES BYTEA,
- *  CONSTRAINT SPRING_SESSION_ATTRIBUTES_PK PRIMARY KEY (SESSION_ID, ATTRIBUTE_NAME),
- *  CONSTRAINT SPRING_SESSION_ATTRIBUTES_FK FOREIGN KEY (SESSION_ID) REFERENCES SPRING_SESSION(SESSION_ID) ON DELETE CASCADE
+ *  CONSTRAINT SPRING_SESSION_ATTRIBUTES_PK PRIMARY KEY (SESSION_PRIMARY_ID, ATTRIBUTE_NAME),
+ *  CONSTRAINT SPRING_SESSION_ATTRIBUTES_FK FOREIGN KEY (SESSION_PRIMARY_ID) REFERENCES SPRING_SESSION(PRIMARY_ID) ON DELETE CASCADE
  * );
  *
- * CREATE INDEX SPRING_SESSION_ATTRIBUTES_IX1 ON SPRING_SESSION_ATTRIBUTES (SESSION_ID);
+ * CREATE INDEX SPRING_SESSION_ATTRIBUTES_IX1 ON SPRING_SESSION_ATTRIBUTES (SESSION_PRIMARY_ID);
  * 
* * Due to the differences between the various database vendors, especially when it comes @@ -136,31 +138,31 @@ public class JdbcOperationsSessionRepository implements private static final String SPRING_SECURITY_CONTEXT = "SPRING_SECURITY_CONTEXT"; private static final String CREATE_SESSION_QUERY = - "INSERT INTO %TABLE_NAME%(SESSION_ID, CREATION_TIME, LAST_ACCESS_TIME, MAX_INACTIVE_INTERVAL, PRINCIPAL_NAME) " + - "VALUES (?, ?, ?, ?, ?)"; + "INSERT INTO %TABLE_NAME%(PRIMARY_ID, SESSION_ID, CREATION_TIME, LAST_ACCESS_TIME, MAX_INACTIVE_INTERVAL, PRINCIPAL_NAME) " + + "VALUES (?, ?, ?, ?, ?, ?)"; private static final String CREATE_SESSION_ATTRIBUTE_QUERY = - "INSERT INTO %TABLE_NAME%_ATTRIBUTES(SESSION_ID, ATTRIBUTE_NAME, ATTRIBUTE_BYTES) " + + "INSERT INTO %TABLE_NAME%_ATTRIBUTES(SESSION_PRIMARY_ID, ATTRIBUTE_NAME, ATTRIBUTE_BYTES) " + "VALUES (?, ?, ?)"; private static final String GET_SESSION_QUERY = - "SELECT S.SESSION_ID, S.CREATION_TIME, S.LAST_ACCESS_TIME, S.MAX_INACTIVE_INTERVAL, SA.ATTRIBUTE_NAME, SA.ATTRIBUTE_BYTES " + + "SELECT S.PRIMARY_ID, S.SESSION_ID, S.CREATION_TIME, S.LAST_ACCESS_TIME, S.MAX_INACTIVE_INTERVAL, SA.ATTRIBUTE_NAME, SA.ATTRIBUTE_BYTES " + "FROM %TABLE_NAME% S " + - "LEFT OUTER JOIN %TABLE_NAME%_ATTRIBUTES SA ON S.SESSION_ID = SA.SESSION_ID " + + "LEFT OUTER JOIN %TABLE_NAME%_ATTRIBUTES SA ON S.PRIMARY_ID = SA.SESSION_PRIMARY_ID " + "WHERE S.SESSION_ID = ?"; private static final String UPDATE_SESSION_QUERY = - "UPDATE %TABLE_NAME% SET LAST_ACCESS_TIME = ?, MAX_INACTIVE_INTERVAL = ?, PRINCIPAL_NAME = ? " + - "WHERE SESSION_ID = ?"; + "UPDATE %TABLE_NAME% SET SESSION_ID = ?, LAST_ACCESS_TIME = ?, MAX_INACTIVE_INTERVAL = ?, PRINCIPAL_NAME = ? " + + "WHERE PRIMARY_ID = ?"; private static final String UPDATE_SESSION_ATTRIBUTE_QUERY = "UPDATE %TABLE_NAME%_ATTRIBUTES SET ATTRIBUTE_BYTES = ? " + - "WHERE SESSION_ID = ? " + + "WHERE SESSION_PRIMARY_ID = ? " + "AND ATTRIBUTE_NAME = ?"; private static final String DELETE_SESSION_ATTRIBUTE_QUERY = "DELETE FROM %TABLE_NAME%_ATTRIBUTES " + - "WHERE SESSION_ID = ? " + + "WHERE SESSION_PRIMARY_ID = ? " + "AND ATTRIBUTE_NAME = ?"; private static final String DELETE_SESSION_QUERY = @@ -168,9 +170,9 @@ public class JdbcOperationsSessionRepository implements "WHERE SESSION_ID = ?"; private static final String LIST_SESSIONS_BY_PRINCIPAL_NAME_QUERY = - "SELECT S.SESSION_ID, S.CREATION_TIME, S.LAST_ACCESS_TIME, S.MAX_INACTIVE_INTERVAL, SA.ATTRIBUTE_NAME, SA.ATTRIBUTE_BYTES " + + "SELECT S.PRIMARY_ID, S.SESSION_ID, S.CREATION_TIME, S.LAST_ACCESS_TIME, S.MAX_INACTIVE_INTERVAL, SA.ATTRIBUTE_NAME, SA.ATTRIBUTE_BYTES " + "FROM %TABLE_NAME% S " + - "LEFT OUTER JOIN %TABLE_NAME%_ATTRIBUTES SA ON S.SESSION_ID = SA.SESSION_ID " + + "LEFT OUTER JOIN %TABLE_NAME%_ATTRIBUTES SA ON S.PRIMARY_ID = SA.SESSION_PRIMARY_ID " + "WHERE S.PRINCIPAL_NAME = ?"; private static final String DELETE_SESSIONS_BY_LAST_ACCESS_TIME_QUERY = @@ -186,7 +188,7 @@ public class JdbcOperationsSessionRepository implements private final TransactionOperations transactionOperations; - private final ResultSetExtractor> extractor = new SessionResultSetExtractor(); + private final ResultSetExtractor> extractor = new SessionResultSetExtractor(); /** * The name of database table used by Spring Session to store sessions. @@ -378,11 +380,12 @@ protected void doInTransactionWithoutResult(TransactionStatus status) { JdbcOperationsSessionRepository.this.jdbcOperations.update( JdbcOperationsSessionRepository.this.createSessionQuery, ps -> { - ps.setString(1, session.getId()); - ps.setLong(2, session.getCreationTime().toEpochMilli()); - ps.setLong(3, session.getLastAccessedTime().toEpochMilli()); - ps.setInt(4, (int) session.getMaxInactiveInterval().getSeconds()); - ps.setString(5, session.getPrincipalName()); + ps.setString(1, session.primaryKey); + ps.setString(2, session.getId()); + ps.setLong(3, session.getCreationTime().toEpochMilli()); + ps.setLong(4, session.getLastAccessedTime().toEpochMilli()); + ps.setInt(5, (int) session.getMaxInactiveInterval().getSeconds()); + ps.setString(6, session.getPrincipalName()); }); if (!session.getAttributeNames().isEmpty()) { final List attributeNames = new ArrayList<>(session.getAttributeNames()); @@ -392,7 +395,7 @@ protected void doInTransactionWithoutResult(TransactionStatus status) { public void setValues(PreparedStatement ps, int i) throws SQLException { String attributeName = attributeNames.get(i); - ps.setString(1, session.getId()); + ps.setString(1, session.primaryKey); ps.setString(2, attributeName); serialize(ps, 3, session.getAttribute(attributeName)); } @@ -415,10 +418,11 @@ protected void doInTransactionWithoutResult(TransactionStatus status) { JdbcOperationsSessionRepository.this.jdbcOperations.update( JdbcOperationsSessionRepository.this.updateSessionQuery, ps -> { - ps.setLong(1, session.getLastAccessedTime().toEpochMilli()); - ps.setInt(2, (int) session.getMaxInactiveInterval().getSeconds()); - ps.setString(3, session.getPrincipalName()); - ps.setString(4, session.getId()); + ps.setString(1, session.getId()); + ps.setLong(2, session.getLastAccessedTime().toEpochMilli()); + ps.setInt(3, (int) session.getMaxInactiveInterval().getSeconds()); + ps.setString(4, session.getPrincipalName()); + ps.setString(5, session.primaryKey); }); } Map delta = session.getDelta(); @@ -428,7 +432,7 @@ protected void doInTransactionWithoutResult(TransactionStatus status) { JdbcOperationsSessionRepository.this.jdbcOperations.update( JdbcOperationsSessionRepository.this.deleteSessionAttributeQuery, ps -> { - ps.setString(1, session.getId()); + ps.setString(1, session.primaryKey); ps.setString(2, entry.getKey()); }); } @@ -437,14 +441,14 @@ protected void doInTransactionWithoutResult(TransactionStatus status) { JdbcOperationsSessionRepository.this.updateSessionAttributeQuery, ps -> { serialize(ps, 1, entry.getValue()); - ps.setString(2, session.getId()); + ps.setString(2, session.primaryKey); ps.setString(3, entry.getKey()); }); if (updatedCount == 0) { JdbcOperationsSessionRepository.this.jdbcOperations.update( JdbcOperationsSessionRepository.this.createSessionAttributeQuery, ps -> { - ps.setString(1, session.getId()); + ps.setString(1, session.primaryKey); ps.setString(2, entry.getKey()); serialize(ps, 3, entry.getValue()); }); @@ -460,8 +464,8 @@ protected void doInTransactionWithoutResult(TransactionStatus status) { } public JdbcSession findById(final String id) { - final Session session = this.transactionOperations.execute(status -> { - List sessions = JdbcOperationsSessionRepository.this.jdbcOperations.query( + final JdbcSession session = this.transactionOperations.execute(status -> { + List sessions = JdbcOperationsSessionRepository.this.jdbcOperations.query( JdbcOperationsSessionRepository.this.getSessionQuery, ps -> ps.setString(1, id), JdbcOperationsSessionRepository.this.extractor @@ -477,7 +481,7 @@ public JdbcSession findById(final String id) { deleteById(id); } else { - return new JdbcSession(session); + return session; } } return null; @@ -500,7 +504,7 @@ public Map findByIndexNameAndIndexValue(String indexName, return Collections.emptyMap(); } - List sessions = this.transactionOperations.execute(status -> + List sessions = this.transactionOperations.execute(status -> JdbcOperationsSessionRepository.this.jdbcOperations.query( JdbcOperationsSessionRepository.this.listSessionsByPrincipalNameQuery, ps -> ps.setString(1, indexValue), @@ -509,8 +513,8 @@ public Map findByIndexNameAndIndexValue(String indexName, Map sessionMap = new HashMap<>( sessions.size()); - for (Session session : sessions) { - sessionMap.put(session.getId(), new JdbcSession(session)); + for (JdbcSession session : sessions) { + sessionMap.put(session.getId(), session); } return sessionMap; @@ -596,6 +600,8 @@ final class JdbcSession implements Session { private final Session delegate; + private final String primaryKey; + private boolean isNew; private boolean changed; @@ -605,10 +611,13 @@ final class JdbcSession implements Session { JdbcSession() { this.delegate = new MapSession(); this.isNew = true; + this.primaryKey = UUID.randomUUID().toString(); } - JdbcSession(Session delegate) { + JdbcSession(String primaryKey, Session delegate) { + Assert.notNull(primaryKey, "primaryKey cannot be null"); Assert.notNull(delegate, "Session cannot be null"); + this.primaryKey = primaryKey; this.delegate = delegate; } @@ -638,6 +647,11 @@ public String getId() { return this.delegate.getId(); } + public String changeSessionId() { + this.changed = true; + return this.delegate.changeSessionId(); + } + public T getAttribute(String attributeName) { return this.delegate.getAttribute(attributeName); } @@ -713,21 +727,23 @@ public String resolvePrincipal(Session session) { } - private class SessionResultSetExtractor implements ResultSetExtractor> { + private class SessionResultSetExtractor implements ResultSetExtractor> { - public List extractData(ResultSet rs) throws SQLException, DataAccessException { - List sessions = new ArrayList<>(); + public List extractData(ResultSet rs) throws SQLException, DataAccessException { + List sessions = new ArrayList<>(); while (rs.next()) { String id = rs.getString("SESSION_ID"); - MapSession session; + JdbcSession session; if (sessions.size() > 0 && getLast(sessions).getId().equals(id)) { - session = (MapSession) getLast(sessions); + session = getLast(sessions); } else { - session = new MapSession(id); - session.setCreationTime(Instant.ofEpochMilli(rs.getLong("CREATION_TIME"))); - session.setLastAccessedTime(Instant.ofEpochMilli(rs.getLong("LAST_ACCESS_TIME"))); - session.setMaxInactiveInterval(Duration.ofSeconds(rs.getInt("MAX_INACTIVE_INTERVAL"))); + MapSession delegate = new MapSession(id); + String primaryKey = rs.getString("PRIMARY_ID"); + delegate.setCreationTime(Instant.ofEpochMilli(rs.getLong("CREATION_TIME"))); + delegate.setLastAccessedTime(Instant.ofEpochMilli(rs.getLong("LAST_ACCESS_TIME"))); + delegate.setMaxInactiveInterval(Duration.ofSeconds(rs.getInt("MAX_INACTIVE_INTERVAL"))); + session = new JdbcSession(primaryKey, delegate); } String attributeName = rs.getString("ATTRIBUTE_NAME"); if (attributeName != null) { @@ -738,7 +754,7 @@ public List extractData(ResultSet rs) throws SQLException, DataAccessEx return sessions; } - private Session getLast(List sessions) { + private JdbcSession getLast(List sessions) { return sessions.get(sessions.size() - 1); } diff --git a/spring-session-jdbc/src/main/resources/org/springframework/session/jdbc/schema-db2.sql b/spring-session-jdbc/src/main/resources/org/springframework/session/jdbc/schema-db2.sql index a2c1ad2be..c3111d167 100644 --- a/spring-session-jdbc/src/main/resources/org/springframework/session/jdbc/schema-db2.sql +++ b/spring-session-jdbc/src/main/resources/org/springframework/session/jdbc/schema-db2.sql @@ -1,20 +1,22 @@ CREATE TABLE SPRING_SESSION ( + PRIMARY_ID CHAR(36) NOT NULL, SESSION_ID CHAR(36) NOT NULL, CREATION_TIME BIGINT NOT NULL, LAST_ACCESS_TIME BIGINT NOT NULL, MAX_INACTIVE_INTERVAL INT NOT NULL, PRINCIPAL_NAME VARCHAR(100), - CONSTRAINT SPRING_SESSION_PK PRIMARY KEY (SESSION_ID) + CONSTRAINT SPRING_SESSION_PK PRIMARY KEY (PRIMARY_ID) ); -CREATE INDEX SPRING_SESSION_IX1 ON SPRING_SESSION (LAST_ACCESS_TIME); +CREATE INDEX SPRING_SESSION_IX1 ON SPRING_SESSION (SESSION_ID); +CREATE INDEX SPRING_SESSION_IX2 ON SPRING_SESSION (LAST_ACCESS_TIME); CREATE TABLE SPRING_SESSION_ATTRIBUTES ( - SESSION_ID CHAR(36) NOT NULL, + SESSION_PRIMARY_ID CHAR(36) NOT NULL, ATTRIBUTE_NAME VARCHAR(200) NOT NULL, ATTRIBUTE_BYTES BLOB NOT NULL, - CONSTRAINT SPRING_SESSION_ATTRIBUTES_PK PRIMARY KEY (SESSION_ID, ATTRIBUTE_NAME), - CONSTRAINT SPRING_SESSION_ATTRIBUTES_FK FOREIGN KEY (SESSION_ID) REFERENCES SPRING_SESSION(SESSION_ID) ON DELETE CASCADE + CONSTRAINT SPRING_SESSION_ATTRIBUTES_PK PRIMARY KEY (SESSION_PRIMARY_ID, ATTRIBUTE_NAME), + CONSTRAINT SPRING_SESSION_ATTRIBUTES_FK FOREIGN KEY (SESSION_PRIMARY_ID) REFERENCES SPRING_SESSION(PRIMARY_ID) ON DELETE CASCADE ); -CREATE INDEX SPRING_SESSION_ATTRIBUTES_IX1 ON SPRING_SESSION_ATTRIBUTES (SESSION_ID); +CREATE INDEX SPRING_SESSION_ATTRIBUTES_IX1 ON SPRING_SESSION_ATTRIBUTES (SESSION_PRIMARY_ID); diff --git a/spring-session-jdbc/src/main/resources/org/springframework/session/jdbc/schema-derby.sql b/spring-session-jdbc/src/main/resources/org/springframework/session/jdbc/schema-derby.sql index a2c1ad2be..c3111d167 100644 --- a/spring-session-jdbc/src/main/resources/org/springframework/session/jdbc/schema-derby.sql +++ b/spring-session-jdbc/src/main/resources/org/springframework/session/jdbc/schema-derby.sql @@ -1,20 +1,22 @@ CREATE TABLE SPRING_SESSION ( + PRIMARY_ID CHAR(36) NOT NULL, SESSION_ID CHAR(36) NOT NULL, CREATION_TIME BIGINT NOT NULL, LAST_ACCESS_TIME BIGINT NOT NULL, MAX_INACTIVE_INTERVAL INT NOT NULL, PRINCIPAL_NAME VARCHAR(100), - CONSTRAINT SPRING_SESSION_PK PRIMARY KEY (SESSION_ID) + CONSTRAINT SPRING_SESSION_PK PRIMARY KEY (PRIMARY_ID) ); -CREATE INDEX SPRING_SESSION_IX1 ON SPRING_SESSION (LAST_ACCESS_TIME); +CREATE INDEX SPRING_SESSION_IX1 ON SPRING_SESSION (SESSION_ID); +CREATE INDEX SPRING_SESSION_IX2 ON SPRING_SESSION (LAST_ACCESS_TIME); CREATE TABLE SPRING_SESSION_ATTRIBUTES ( - SESSION_ID CHAR(36) NOT NULL, + SESSION_PRIMARY_ID CHAR(36) NOT NULL, ATTRIBUTE_NAME VARCHAR(200) NOT NULL, ATTRIBUTE_BYTES BLOB NOT NULL, - CONSTRAINT SPRING_SESSION_ATTRIBUTES_PK PRIMARY KEY (SESSION_ID, ATTRIBUTE_NAME), - CONSTRAINT SPRING_SESSION_ATTRIBUTES_FK FOREIGN KEY (SESSION_ID) REFERENCES SPRING_SESSION(SESSION_ID) ON DELETE CASCADE + CONSTRAINT SPRING_SESSION_ATTRIBUTES_PK PRIMARY KEY (SESSION_PRIMARY_ID, ATTRIBUTE_NAME), + CONSTRAINT SPRING_SESSION_ATTRIBUTES_FK FOREIGN KEY (SESSION_PRIMARY_ID) REFERENCES SPRING_SESSION(PRIMARY_ID) ON DELETE CASCADE ); -CREATE INDEX SPRING_SESSION_ATTRIBUTES_IX1 ON SPRING_SESSION_ATTRIBUTES (SESSION_ID); +CREATE INDEX SPRING_SESSION_ATTRIBUTES_IX1 ON SPRING_SESSION_ATTRIBUTES (SESSION_PRIMARY_ID); diff --git a/spring-session-jdbc/src/main/resources/org/springframework/session/jdbc/schema-h2.sql b/spring-session-jdbc/src/main/resources/org/springframework/session/jdbc/schema-h2.sql index d3278d30f..c9076c4da 100644 --- a/spring-session-jdbc/src/main/resources/org/springframework/session/jdbc/schema-h2.sql +++ b/spring-session-jdbc/src/main/resources/org/springframework/session/jdbc/schema-h2.sql @@ -1,20 +1,22 @@ CREATE TABLE SPRING_SESSION ( + PRIMARY_ID CHAR(36) NOT NULL, SESSION_ID CHAR(36) NOT NULL, CREATION_TIME BIGINT NOT NULL, LAST_ACCESS_TIME BIGINT NOT NULL, MAX_INACTIVE_INTERVAL INT NOT NULL, PRINCIPAL_NAME VARCHAR(100), - CONSTRAINT SPRING_SESSION_PK PRIMARY KEY (SESSION_ID) + CONSTRAINT SPRING_SESSION_PK PRIMARY KEY (PRIMARY_ID) ); -CREATE INDEX SPRING_SESSION_IX1 ON SPRING_SESSION (LAST_ACCESS_TIME); +CREATE INDEX SPRING_SESSION_IX1 ON SPRING_SESSION (SESSION_ID); +CREATE INDEX SPRING_SESSION_IX2 ON SPRING_SESSION (LAST_ACCESS_TIME); CREATE TABLE SPRING_SESSION_ATTRIBUTES ( - SESSION_ID CHAR(36) NOT NULL, + SESSION_PRIMARY_ID CHAR(36) NOT NULL, ATTRIBUTE_NAME VARCHAR(200) NOT NULL, ATTRIBUTE_BYTES LONGVARBINARY NOT NULL, - CONSTRAINT SPRING_SESSION_ATTRIBUTES_PK PRIMARY KEY (SESSION_ID, ATTRIBUTE_NAME), - CONSTRAINT SPRING_SESSION_ATTRIBUTES_FK FOREIGN KEY (SESSION_ID) REFERENCES SPRING_SESSION(SESSION_ID) ON DELETE CASCADE + CONSTRAINT SPRING_SESSION_ATTRIBUTES_PK PRIMARY KEY (SESSION_PRIMARY_ID, ATTRIBUTE_NAME), + CONSTRAINT SPRING_SESSION_ATTRIBUTES_FK FOREIGN KEY (SESSION_PRIMARY_ID) REFERENCES SPRING_SESSION(PRIMARY_ID) ON DELETE CASCADE ); -CREATE INDEX SPRING_SESSION_ATTRIBUTES_IX1 ON SPRING_SESSION_ATTRIBUTES (SESSION_ID); +CREATE INDEX SPRING_SESSION_ATTRIBUTES_IX1 ON SPRING_SESSION_ATTRIBUTES (SESSION_PRIMARY_ID); diff --git a/spring-session-jdbc/src/main/resources/org/springframework/session/jdbc/schema-hsqldb.sql b/spring-session-jdbc/src/main/resources/org/springframework/session/jdbc/schema-hsqldb.sql index d3278d30f..c9076c4da 100644 --- a/spring-session-jdbc/src/main/resources/org/springframework/session/jdbc/schema-hsqldb.sql +++ b/spring-session-jdbc/src/main/resources/org/springframework/session/jdbc/schema-hsqldb.sql @@ -1,20 +1,22 @@ CREATE TABLE SPRING_SESSION ( + PRIMARY_ID CHAR(36) NOT NULL, SESSION_ID CHAR(36) NOT NULL, CREATION_TIME BIGINT NOT NULL, LAST_ACCESS_TIME BIGINT NOT NULL, MAX_INACTIVE_INTERVAL INT NOT NULL, PRINCIPAL_NAME VARCHAR(100), - CONSTRAINT SPRING_SESSION_PK PRIMARY KEY (SESSION_ID) + CONSTRAINT SPRING_SESSION_PK PRIMARY KEY (PRIMARY_ID) ); -CREATE INDEX SPRING_SESSION_IX1 ON SPRING_SESSION (LAST_ACCESS_TIME); +CREATE INDEX SPRING_SESSION_IX1 ON SPRING_SESSION (SESSION_ID); +CREATE INDEX SPRING_SESSION_IX2 ON SPRING_SESSION (LAST_ACCESS_TIME); CREATE TABLE SPRING_SESSION_ATTRIBUTES ( - SESSION_ID CHAR(36) NOT NULL, + SESSION_PRIMARY_ID CHAR(36) NOT NULL, ATTRIBUTE_NAME VARCHAR(200) NOT NULL, ATTRIBUTE_BYTES LONGVARBINARY NOT NULL, - CONSTRAINT SPRING_SESSION_ATTRIBUTES_PK PRIMARY KEY (SESSION_ID, ATTRIBUTE_NAME), - CONSTRAINT SPRING_SESSION_ATTRIBUTES_FK FOREIGN KEY (SESSION_ID) REFERENCES SPRING_SESSION(SESSION_ID) ON DELETE CASCADE + CONSTRAINT SPRING_SESSION_ATTRIBUTES_PK PRIMARY KEY (SESSION_PRIMARY_ID, ATTRIBUTE_NAME), + CONSTRAINT SPRING_SESSION_ATTRIBUTES_FK FOREIGN KEY (SESSION_PRIMARY_ID) REFERENCES SPRING_SESSION(PRIMARY_ID) ON DELETE CASCADE ); -CREATE INDEX SPRING_SESSION_ATTRIBUTES_IX1 ON SPRING_SESSION_ATTRIBUTES (SESSION_ID); +CREATE INDEX SPRING_SESSION_ATTRIBUTES_IX1 ON SPRING_SESSION_ATTRIBUTES (SESSION_PRIMARY_ID); diff --git a/spring-session-jdbc/src/main/resources/org/springframework/session/jdbc/schema-mysql.sql b/spring-session-jdbc/src/main/resources/org/springframework/session/jdbc/schema-mysql.sql index 0739d69c9..28bdf3c1d 100644 --- a/spring-session-jdbc/src/main/resources/org/springframework/session/jdbc/schema-mysql.sql +++ b/spring-session-jdbc/src/main/resources/org/springframework/session/jdbc/schema-mysql.sql @@ -1,20 +1,22 @@ CREATE TABLE SPRING_SESSION ( + PRIMARY_ID CHAR(36) NOT NULL, SESSION_ID CHAR(36) NOT NULL, CREATION_TIME BIGINT NOT NULL, LAST_ACCESS_TIME BIGINT NOT NULL, MAX_INACTIVE_INTERVAL INT NOT NULL, PRINCIPAL_NAME VARCHAR(100), - CONSTRAINT SPRING_SESSION_PK PRIMARY KEY (SESSION_ID) + CONSTRAINT SPRING_SESSION_PK PRIMARY KEY (PRIMARY_ID) ) ENGINE=InnoDB; -CREATE INDEX SPRING_SESSION_IX1 ON SPRING_SESSION (LAST_ACCESS_TIME); +CREATE INDEX SPRING_SESSION_IX1 ON SPRING_SESSION (SESSION_ID); +CREATE INDEX SPRING_SESSION_IX2 ON SPRING_SESSION (LAST_ACCESS_TIME); CREATE TABLE SPRING_SESSION_ATTRIBUTES ( - SESSION_ID CHAR(36) NOT NULL, + SESSION_PRIMARY_ID CHAR(36) NOT NULL, ATTRIBUTE_NAME VARCHAR(200) NOT NULL, ATTRIBUTE_BYTES BLOB NOT NULL, - CONSTRAINT SPRING_SESSION_ATTRIBUTES_PK PRIMARY KEY (SESSION_ID, ATTRIBUTE_NAME), - CONSTRAINT SPRING_SESSION_ATTRIBUTES_FK FOREIGN KEY (SESSION_ID) REFERENCES SPRING_SESSION(SESSION_ID) ON DELETE CASCADE + CONSTRAINT SPRING_SESSION_ATTRIBUTES_PK PRIMARY KEY (SESSION_PRIMARY_ID, ATTRIBUTE_NAME), + CONSTRAINT SPRING_SESSION_ATTRIBUTES_FK FOREIGN KEY (SESSION_PRIMARY_ID) REFERENCES SPRING_SESSION(PRIMARY_ID) ON DELETE CASCADE ) ENGINE=InnoDB; -CREATE INDEX SPRING_SESSION_ATTRIBUTES_IX1 ON SPRING_SESSION_ATTRIBUTES (SESSION_ID); +CREATE INDEX SPRING_SESSION_ATTRIBUTES_IX1 ON SPRING_SESSION_ATTRIBUTES (SESSION_PRIMARY_ID); diff --git a/spring-session-jdbc/src/main/resources/org/springframework/session/jdbc/schema-oracle.sql b/spring-session-jdbc/src/main/resources/org/springframework/session/jdbc/schema-oracle.sql index 2444869f4..69d3892af 100644 --- a/spring-session-jdbc/src/main/resources/org/springframework/session/jdbc/schema-oracle.sql +++ b/spring-session-jdbc/src/main/resources/org/springframework/session/jdbc/schema-oracle.sql @@ -1,20 +1,22 @@ CREATE TABLE SPRING_SESSION ( + PRIMARY_ID CHAR(36) NOT NULL, SESSION_ID CHAR(36) NOT NULL, CREATION_TIME NUMBER(19,0) NOT NULL, LAST_ACCESS_TIME NUMBER(19,0) NOT NULL, MAX_INACTIVE_INTERVAL NUMBER(10,0) NOT NULL, PRINCIPAL_NAME VARCHAR2(100 CHAR), - CONSTRAINT SPRING_SESSION_PK PRIMARY KEY (SESSION_ID) + CONSTRAINT SPRING_SESSION_PK PRIMARY KEY (PRIMARY_ID) ); -CREATE INDEX SPRING_SESSION_IX1 ON SPRING_SESSION (LAST_ACCESS_TIME); +CREATE INDEX SPRING_SESSION_IX1 ON SPRING_SESSION (SESSION_ID); +CREATE INDEX SPRING_SESSION_IX2 ON SPRING_SESSION (LAST_ACCESS_TIME); CREATE TABLE SPRING_SESSION_ATTRIBUTES ( - SESSION_ID CHAR(36) NOT NULL, + SESSION_PRIMARY_ID CHAR(36) NOT NULL, ATTRIBUTE_NAME VARCHAR2(200 CHAR) NOT NULL, ATTRIBUTE_BYTES BLOB NOT NULL, - CONSTRAINT SPRING_SESSION_ATTRIBUTES_PK PRIMARY KEY (SESSION_ID, ATTRIBUTE_NAME), - CONSTRAINT SPRING_SESSION_ATTRIBUTES_FK FOREIGN KEY (SESSION_ID) REFERENCES SPRING_SESSION(SESSION_ID) ON DELETE CASCADE + CONSTRAINT SPRING_SESSION_ATTRIBUTES_PK PRIMARY KEY (SESSION_PRIMARY_ID, ATTRIBUTE_NAME), + CONSTRAINT SPRING_SESSION_ATTRIBUTES_FK FOREIGN KEY (SESSION_PRIMARY_ID) REFERENCES SPRING_SESSION(PRIMARY_ID) ON DELETE CASCADE ); -CREATE INDEX SPRING_SESSION_ATTRIBUTES_IX1 ON SPRING_SESSION_ATTRIBUTES (SESSION_ID); +CREATE INDEX SPRING_SESSION_ATTRIBUTES_IX1 ON SPRING_SESSION_ATTRIBUTES (SESSION_PRIMARY_ID); diff --git a/spring-session-jdbc/src/main/resources/org/springframework/session/jdbc/schema-postgresql.sql b/spring-session-jdbc/src/main/resources/org/springframework/session/jdbc/schema-postgresql.sql index 4889ec7a9..570e2ed25 100644 --- a/spring-session-jdbc/src/main/resources/org/springframework/session/jdbc/schema-postgresql.sql +++ b/spring-session-jdbc/src/main/resources/org/springframework/session/jdbc/schema-postgresql.sql @@ -1,20 +1,22 @@ CREATE TABLE SPRING_SESSION ( + PRIMARY_ID CHAR(36) NOT NULL, SESSION_ID CHAR(36) NOT NULL, CREATION_TIME BIGINT NOT NULL, LAST_ACCESS_TIME BIGINT NOT NULL, MAX_INACTIVE_INTERVAL INT NOT NULL, PRINCIPAL_NAME VARCHAR(100), - CONSTRAINT SPRING_SESSION_PK PRIMARY KEY (SESSION_ID) + CONSTRAINT SPRING_SESSION_PK PRIMARY KEY (PRIMARY_ID) ); -CREATE INDEX SPRING_SESSION_IX1 ON SPRING_SESSION (LAST_ACCESS_TIME); +CREATE INDEX SPRING_SESSION_IX1 ON SPRING_SESSION (SESSION_ID); +CREATE INDEX SPRING_SESSION_IX2 ON SPRING_SESSION (LAST_ACCESS_TIME); CREATE TABLE SPRING_SESSION_ATTRIBUTES ( - SESSION_ID CHAR(36) NOT NULL, + SESSION_PRIMARY_ID CHAR(36) NOT NULL, ATTRIBUTE_NAME VARCHAR(200) NOT NULL, ATTRIBUTE_BYTES BYTEA NOT NULL, - CONSTRAINT SPRING_SESSION_ATTRIBUTES_PK PRIMARY KEY (SESSION_ID, ATTRIBUTE_NAME), - CONSTRAINT SPRING_SESSION_ATTRIBUTES_FK FOREIGN KEY (SESSION_ID) REFERENCES SPRING_SESSION(SESSION_ID) ON DELETE CASCADE + CONSTRAINT SPRING_SESSION_ATTRIBUTES_PK PRIMARY KEY (SESSION_PRIMARY_ID, ATTRIBUTE_NAME), + CONSTRAINT SPRING_SESSION_ATTRIBUTES_FK FOREIGN KEY (SESSION_PRIMARY_ID) REFERENCES SPRING_SESSION(PRIMARY_ID) ON DELETE CASCADE ); -CREATE INDEX SPRING_SESSION_ATTRIBUTES_IX1 ON SPRING_SESSION_ATTRIBUTES (SESSION_ID); +CREATE INDEX SPRING_SESSION_ATTRIBUTES_IX1 ON SPRING_SESSION_ATTRIBUTES (SESSION_PRIMARY_ID); diff --git a/spring-session-jdbc/src/main/resources/org/springframework/session/jdbc/schema-sqlite.sql b/spring-session-jdbc/src/main/resources/org/springframework/session/jdbc/schema-sqlite.sql index c2590c05b..abfd8958a 100644 --- a/spring-session-jdbc/src/main/resources/org/springframework/session/jdbc/schema-sqlite.sql +++ b/spring-session-jdbc/src/main/resources/org/springframework/session/jdbc/schema-sqlite.sql @@ -1,20 +1,22 @@ CREATE TABLE SPRING_SESSION ( + PRIMARY_ID CHARACTER(36) NOT NULL, SESSION_ID CHARACTER(36) NOT NULL, CREATION_TIME INTEGER NOT NULL, LAST_ACCESS_TIME INTEGER NOT NULL, MAX_INACTIVE_INTERVAL INTEGER NOT NULL, PRINCIPAL_NAME VARCHAR(100), - CONSTRAINT SPRING_SESSION_PK PRIMARY KEY (SESSION_ID) + CONSTRAINT SPRING_SESSION_PK PRIMARY KEY (PRIMARY_ID) ); -CREATE INDEX SPRING_SESSION_IX1 ON SPRING_SESSION (LAST_ACCESS_TIME); +CREATE INDEX SPRING_SESSION_IX1 ON SPRING_SESSION (SESSION_ID); +CREATE INDEX SPRING_SESSION_IX2 ON SPRING_SESSION (LAST_ACCESS_TIME); CREATE TABLE SPRING_SESSION_ATTRIBUTES ( - SESSION_ID CHAR(36) NOT NULL, + SESSION_PRIMARY_ID CHAR(36) NOT NULL, ATTRIBUTE_NAME VARCHAR(200) NOT NULL, ATTRIBUTE_BYTES BLOB NOT NULL, - CONSTRAINT SPRING_SESSION_ATTRIBUTES_PK PRIMARY KEY (SESSION_ID, ATTRIBUTE_NAME), - CONSTRAINT SPRING_SESSION_ATTRIBUTES_FK FOREIGN KEY (SESSION_ID) REFERENCES SPRING_SESSION(SESSION_ID) ON DELETE CASCADE + CONSTRAINT SPRING_SESSION_ATTRIBUTES_PK PRIMARY KEY (SESSION_PRIMARY_ID, ATTRIBUTE_NAME), + CONSTRAINT SPRING_SESSION_ATTRIBUTES_FK FOREIGN KEY (SESSION_PRIMARY_ID) REFERENCES SPRING_SESSION(PRIMARY_ID) ON DELETE CASCADE ); -CREATE INDEX SPRING_SESSION_ATTRIBUTES_IX1 ON SPRING_SESSION_ATTRIBUTES (SESSION_ID); +CREATE INDEX SPRING_SESSION_ATTRIBUTES_IX1 ON SPRING_SESSION_ATTRIBUTES (SESSION_PRIMARY_ID); diff --git a/spring-session-jdbc/src/main/resources/org/springframework/session/jdbc/schema-sqlserver.sql b/spring-session-jdbc/src/main/resources/org/springframework/session/jdbc/schema-sqlserver.sql index 16133629c..c651dcdaf 100644 --- a/spring-session-jdbc/src/main/resources/org/springframework/session/jdbc/schema-sqlserver.sql +++ b/spring-session-jdbc/src/main/resources/org/springframework/session/jdbc/schema-sqlserver.sql @@ -1,20 +1,22 @@ CREATE TABLE SPRING_SESSION ( + PRIMARY_ID CHAR(36) NOT NULL, SESSION_ID CHAR(36) NOT NULL, CREATION_TIME BIGINT NOT NULL, LAST_ACCESS_TIME BIGINT NOT NULL, MAX_INACTIVE_INTERVAL INT NOT NULL, PRINCIPAL_NAME VARCHAR(100), - CONSTRAINT SPRING_SESSION_PK PRIMARY KEY (SESSION_ID) + CONSTRAINT SPRING_SESSION_PK PRIMARY KEY (PRIMARY_ID) ); -CREATE INDEX SPRING_SESSION_IX1 ON SPRING_SESSION (LAST_ACCESS_TIME); +CREATE INDEX SPRING_SESSION_IX1 ON SPRING_SESSION (SESSION_ID); +CREATE INDEX SPRING_SESSION_IX2 ON SPRING_SESSION (LAST_ACCESS_TIME); CREATE TABLE SPRING_SESSION_ATTRIBUTES ( - SESSION_ID CHAR(36) NOT NULL, + SESSION_PRIMARY_ID CHAR(36) NOT NULL, ATTRIBUTE_NAME VARCHAR(200) NOT NULL, ATTRIBUTE_BYTES IMAGE NOT NULL, - CONSTRAINT SPRING_SESSION_ATTRIBUTES_PK PRIMARY KEY (SESSION_ID, ATTRIBUTE_NAME), - CONSTRAINT SPRING_SESSION_ATTRIBUTES_FK FOREIGN KEY (SESSION_ID) REFERENCES SPRING_SESSION(SESSION_ID) ON DELETE CASCADE + CONSTRAINT SPRING_SESSION_ATTRIBUTES_PK PRIMARY KEY (SESSION_PRIMARY_ID, ATTRIBUTE_NAME), + CONSTRAINT SPRING_SESSION_ATTRIBUTES_FK FOREIGN KEY (SESSION_PRIMARY_ID) REFERENCES SPRING_SESSION(PRIMARY_ID) ON DELETE CASCADE ); -CREATE INDEX SPRING_SESSION_ATTRIBUTES_IX1 ON SPRING_SESSION_ATTRIBUTES (SESSION_ID); +CREATE INDEX SPRING_SESSION_ATTRIBUTES_IX1 ON SPRING_SESSION_ATTRIBUTES (SESSION_PRIMARY_ID); diff --git a/spring-session-jdbc/src/main/resources/org/springframework/session/jdbc/schema-sybase.sql b/spring-session-jdbc/src/main/resources/org/springframework/session/jdbc/schema-sybase.sql index 1695dde63..1347a5b61 100644 --- a/spring-session-jdbc/src/main/resources/org/springframework/session/jdbc/schema-sybase.sql +++ b/spring-session-jdbc/src/main/resources/org/springframework/session/jdbc/schema-sybase.sql @@ -1,20 +1,22 @@ CREATE TABLE SPRING_SESSION ( + PRIMARY_ID CHAR(36) NOT NULL, SESSION_ID CHAR(36) NOT NULL, CREATION_TIME BIGINT NOT NULL, LAST_ACCESS_TIME BIGINT NOT NULL, MAX_INACTIVE_INTERVAL INT NOT NULL, PRINCIPAL_NAME VARCHAR(100), - CONSTRAINT SPRING_SESSION_PK PRIMARY KEY (SESSION_ID) + CONSTRAINT SPRING_SESSION_PK PRIMARY KEY (PRIMARY_ID) ) LOCK DATAROWS; -CREATE INDEX SPRING_SESSION_IX1 ON SPRING_SESSION (LAST_ACCESS_TIME); +CREATE INDEX SPRING_SESSION_IX1 ON SPRING_SESSION (SESSION_ID); +CREATE INDEX SPRING_SESSION_IX2 ON SPRING_SESSION (LAST_ACCESS_TIME); CREATE TABLE SPRING_SESSION_ATTRIBUTES ( - SESSION_ID CHAR(36) NOT NULL, + SESSION_PRIMARY_ID CHAR(36) NOT NULL, ATTRIBUTE_NAME VARCHAR(200) NOT NULL, ATTRIBUTE_BYTES IMAGE NOT NULL, - CONSTRAINT SPRING_SESSION_ATTRIBUTES_PK PRIMARY KEY (SESSION_ID, ATTRIBUTE_NAME), - CONSTRAINT SPRING_SESSION_ATTRIBUTES_FK FOREIGN KEY (SESSION_ID) REFERENCES SPRING_SESSION(SESSION_ID) ON DELETE CASCADE + CONSTRAINT SPRING_SESSION_ATTRIBUTES_PK PRIMARY KEY (SESSION_PRIMARY_ID, ATTRIBUTE_NAME), + CONSTRAINT SPRING_SESSION_ATTRIBUTES_FK FOREIGN KEY (SESSION_PRIMARY_ID) REFERENCES SPRING_SESSION(PRIMARY_ID) ON DELETE CASCADE ) LOCK DATAROWS; -CREATE INDEX SPRING_SESSION_ATTRIBUTES_IX1 ON SPRING_SESSION_ATTRIBUTES (SESSION_ID); +CREATE INDEX SPRING_SESSION_ATTRIBUTES_IX1 ON SPRING_SESSION_ATTRIBUTES (SESSION_PRIMARY_ID); diff --git a/spring-session-jdbc/src/test/java/org/springframework/session/jdbc/JdbcOperationsSessionRepositoryTests.java b/spring-session-jdbc/src/test/java/org/springframework/session/jdbc/JdbcOperationsSessionRepositoryTests.java index 3ae8ed194..24b97d02d 100644 --- a/spring-session-jdbc/src/test/java/org/springframework/session/jdbc/JdbcOperationsSessionRepositoryTests.java +++ b/spring-session-jdbc/src/test/java/org/springframework/session/jdbc/JdbcOperationsSessionRepositoryTests.java @@ -42,6 +42,7 @@ import org.springframework.security.core.authority.AuthorityUtils; import org.springframework.session.FindByIndexNameSessionRepository; import org.springframework.session.MapSession; +import org.springframework.session.Session; import org.springframework.test.util.ReflectionTestUtils; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.TransactionDefinition; @@ -357,7 +358,7 @@ public void saveNewWithAttributes() { @Test public void saveUpdatedAttributes() { - JdbcOperationsSessionRepository.JdbcSession session = this.repository.new JdbcSession( + JdbcOperationsSessionRepository.JdbcSession session = this.repository.new JdbcSession("primaryKey", new MapSession()); session.setAttribute("testName", "testValue"); @@ -372,7 +373,7 @@ public void saveUpdatedAttributes() { @Test public void saveUpdatedLastAccessedTime() { - JdbcOperationsSessionRepository.JdbcSession session = this.repository.new JdbcSession( + JdbcOperationsSessionRepository.JdbcSession session = this.repository.new JdbcSession("primaryKey", new MapSession()); session.setLastAccessedTime(Instant.now()); @@ -387,7 +388,7 @@ public void saveUpdatedLastAccessedTime() { @Test public void saveUnchanged() { - JdbcOperationsSessionRepository.JdbcSession session = this.repository.new JdbcSession( + JdbcOperationsSessionRepository.JdbcSession session = this.repository.new JdbcSession("primaryKey", new MapSession()); this.repository.save(session); @@ -416,7 +417,7 @@ public void getSessionNotFound() { @Test @SuppressWarnings("unchecked") public void getSessionExpired() { - MapSession expired = new MapSession(); + Session expired = this.repository.new JdbcSession(); expired.setLastAccessedTime(Instant.now().minusSeconds( MapSession.DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS + 1)); given(this.jdbcOperations.query(isA(String.class), @@ -437,7 +438,7 @@ public void getSessionExpired() { @Test @SuppressWarnings("unchecked") public void getSessionFound() { - MapSession saved = new MapSession(); + Session saved = this.repository.new JdbcSession("primaryKey", new MapSession()); saved.setAttribute("savedName", "savedValue"); given(this.jdbcOperations.query(isA(String.class), isA(PreparedStatementSetter.class), isA(ResultSetExtractor.class))) @@ -500,11 +501,11 @@ public void findByIndexNameAndIndexValuePrincipalIndexNameFound() { String principal = "username"; Authentication authentication = new UsernamePasswordAuthenticationToken(principal, "notused", AuthorityUtils.createAuthorityList("ROLE_USER")); - List saved = new ArrayList<>(2); - MapSession saved1 = new MapSession(); + List saved = new ArrayList<>(2); + Session saved1 = this.repository.new JdbcSession(); saved1.setAttribute(SPRING_SECURITY_CONTEXT, authentication); saved.add(saved1); - MapSession saved2 = new MapSession(); + Session saved2 = this.repository.new JdbcSession(); saved2.setAttribute(SPRING_SECURITY_CONTEXT, authentication); saved.add(saved2); given(this.jdbcOperations.query(isA(String.class),