Provide database specific JdbcIndexedSessionRepository customizers
This commit provides JdbcIndexedSessionRepository customizers for the following SQL dialects: - PostgreSQL - MySQL (also used by MariaDB) - SQL Server - IBM DB2 - Oracle These customizers are intended to address the concurrency issues occurring on insert of new session attribute by applying SQL dialect specific SQL upsert/merge statement instead of a generic insert. Closes: #1213
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2014-2019 the original author or authors.
|
* Copyright 2014-2020 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -29,8 +29,15 @@ import org.junit.jupiter.api.BeforeEach;
|
|||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.context.ApplicationContext;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.dao.DuplicateKeyException;
|
||||||
|
import org.springframework.jdbc.core.JdbcOperations;
|
||||||
|
import org.springframework.jdbc.core.JdbcTemplate;
|
||||||
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
|
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
|
||||||
|
import org.springframework.jdbc.support.lob.DefaultLobHandler;
|
||||||
|
import org.springframework.jdbc.support.lob.LobCreator;
|
||||||
|
import org.springframework.jdbc.support.lob.LobHandler;
|
||||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.security.core.authority.AuthorityUtils;
|
import org.springframework.security.core.authority.AuthorityUtils;
|
||||||
@@ -38,6 +45,7 @@ import org.springframework.security.core.context.SecurityContext;
|
|||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
import org.springframework.session.FindByIndexNameSessionRepository;
|
import org.springframework.session.FindByIndexNameSessionRepository;
|
||||||
import org.springframework.session.MapSession;
|
import org.springframework.session.MapSession;
|
||||||
|
import org.springframework.session.config.SessionRepositoryCustomizer;
|
||||||
import org.springframework.session.jdbc.JdbcIndexedSessionRepository.JdbcSession;
|
import org.springframework.session.jdbc.JdbcIndexedSessionRepository.JdbcSession;
|
||||||
import org.springframework.session.jdbc.config.annotation.web.http.EnableJdbcHttpSession;
|
import org.springframework.session.jdbc.config.annotation.web.http.EnableJdbcHttpSession;
|
||||||
import org.springframework.test.util.ReflectionTestUtils;
|
import org.springframework.test.util.ReflectionTestUtils;
|
||||||
@@ -45,6 +53,8 @@ import org.springframework.transaction.PlatformTransactionManager;
|
|||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.assertj.core.api.Assertions.assertThatCode;
|
||||||
|
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base class for {@link JdbcIndexedSessionRepository} integration tests.
|
* Base class for {@link JdbcIndexedSessionRepository} integration tests.
|
||||||
@@ -57,15 +67,27 @@ abstract class AbstractJdbcIndexedSessionRepositoryITests {
|
|||||||
|
|
||||||
private static final String INDEX_NAME = FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME;
|
private static final String INDEX_NAME = FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ApplicationContext applicationContext;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private DataSource dataSource;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private JdbcIndexedSessionRepository repository;
|
private JdbcIndexedSessionRepository repository;
|
||||||
|
|
||||||
|
private JdbcOperations jdbcOperations;
|
||||||
|
|
||||||
|
private LobHandler lobHandler;
|
||||||
|
|
||||||
private SecurityContext context;
|
private SecurityContext context;
|
||||||
|
|
||||||
private SecurityContext changedContext;
|
private SecurityContext changedContext;
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
void setUp() {
|
void setUp() {
|
||||||
|
this.jdbcOperations = new JdbcTemplate(this.dataSource);
|
||||||
|
this.lobHandler = new DefaultLobHandler();
|
||||||
this.context = SecurityContextHolder.createEmptyContext();
|
this.context = SecurityContextHolder.createEmptyContext();
|
||||||
this.context.setAuthentication(new UsernamePasswordAuthenticationToken("username-" + UUID.randomUUID(), "na",
|
this.context.setAuthentication(new UsernamePasswordAuthenticationToken("username-" + UUID.randomUUID(), "na",
|
||||||
AuthorityUtils.createAuthorityList("ROLE_USER")));
|
AuthorityUtils.createAuthorityList("ROLE_USER")));
|
||||||
@@ -759,6 +781,32 @@ abstract class AbstractJdbcIndexedSessionRepositoryITests {
|
|||||||
assertThat((byte[]) session.getAttribute(attributeName)).hasSize(arraySize);
|
assertThat((byte[]) session.getAttribute(attributeName)).hasSize(arraySize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test // gh-1213
|
||||||
|
void saveNewSessionAttributeConcurrently() {
|
||||||
|
JdbcSession session = this.repository.createSession();
|
||||||
|
this.repository.save(session);
|
||||||
|
String attributeName = "attribute1";
|
||||||
|
String attributeValue = "value1";
|
||||||
|
try (LobCreator lobCreator = this.lobHandler.getLobCreator()) {
|
||||||
|
this.jdbcOperations.update("INSERT INTO SPRING_SESSION_ATTRIBUTES VALUES (?, ?, ?)", (ps) -> {
|
||||||
|
ps.setString(1, (String) ReflectionTestUtils.getField(session, "primaryKey"));
|
||||||
|
ps.setString(2, attributeName);
|
||||||
|
lobCreator.setBlobAsBytes(ps, 3, "value2".getBytes());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
session.setAttribute(attributeName, attributeValue);
|
||||||
|
if (this.applicationContext.getBeansOfType(SessionRepositoryCustomizer.class).isEmpty()) {
|
||||||
|
// without DB specific upsert configured we're seeing duplicate key error
|
||||||
|
assertThatExceptionOfType(DuplicateKeyException.class).isThrownBy(() -> this.repository.save(session));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// with DB specific upsert configured we're fine
|
||||||
|
assertThatCode(() -> this.repository.save(session)).doesNotThrowAnyException();
|
||||||
|
assertThat((String) this.repository.findById(session.getId()).getAttribute(attributeName))
|
||||||
|
.isEqualTo(attributeValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private String getSecurityName() {
|
private String getSecurityName() {
|
||||||
return this.context.getAuthentication().getName();
|
return this.context.getAuthentication().getName();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2014-2020 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.springframework.session.jdbc;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.test.context.ContextConfiguration;
|
||||||
|
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||||
|
import org.springframework.test.context.web.WebAppConfiguration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Integration tests for {@link JdbcIndexedSessionRepository} using IBM DB2 11.x database
|
||||||
|
* with {@link Db2JdbcIndexedSessionRepositoryCustomizer}.
|
||||||
|
*
|
||||||
|
* @author Vedran Pavic
|
||||||
|
*/
|
||||||
|
@ExtendWith(SpringExtension.class)
|
||||||
|
@WebAppConfiguration
|
||||||
|
@ContextConfiguration
|
||||||
|
class Db211JdbcIndexedSessionRepositoryCustomizerITests extends Db211JdbcIndexedSessionRepositoryITests {
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
static class CustomizerConfig extends Config {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
Db2JdbcIndexedSessionRepositoryCustomizer db2JdbcIndexedSessionRepositoryCustomizer() {
|
||||||
|
return new Db2JdbcIndexedSessionRepositoryCustomizer();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2014-2020 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.springframework.session.jdbc;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.test.context.ContextConfiguration;
|
||||||
|
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||||
|
import org.springframework.test.context.web.WebAppConfiguration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Integration tests for {@link JdbcIndexedSessionRepository} using MariaDB 10.x database
|
||||||
|
* with {@link MySqlJdbcIndexedSessionRepositoryCustomizer}.
|
||||||
|
*
|
||||||
|
* @author Vedran Pavic
|
||||||
|
*/
|
||||||
|
@ExtendWith(SpringExtension.class)
|
||||||
|
@WebAppConfiguration
|
||||||
|
@ContextConfiguration
|
||||||
|
class MariaDb10JdbcIndexedSessionRepositoryCustomizerITests extends MariaDb10JdbcIndexedSessionRepositoryITests {
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
static class CustomizerConfig extends Config {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
MySqlJdbcIndexedSessionRepositoryCustomizer mySqlJdbcIndexedSessionRepositoryCustomizer() {
|
||||||
|
return new MySqlJdbcIndexedSessionRepositoryCustomizer();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2014-2020 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.springframework.session.jdbc;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.test.context.ContextConfiguration;
|
||||||
|
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||||
|
import org.springframework.test.context.web.WebAppConfiguration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Integration tests for {@link JdbcIndexedSessionRepository} using MySQL 8.x database
|
||||||
|
* with {@link MySqlJdbcIndexedSessionRepositoryCustomizer}.
|
||||||
|
*
|
||||||
|
* @author Vedran Pavic
|
||||||
|
*/
|
||||||
|
@ExtendWith(SpringExtension.class)
|
||||||
|
@WebAppConfiguration
|
||||||
|
@ContextConfiguration
|
||||||
|
class MySql8JdbcIndexedSessionRepositoryCustomizerITests extends MySql8JdbcIndexedSessionRepositoryITests {
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
static class CustomizerConfig extends Config {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
MySqlJdbcIndexedSessionRepositoryCustomizer mySqlJdbcIndexedSessionRepositoryCustomizer() {
|
||||||
|
return new MySqlJdbcIndexedSessionRepositoryCustomizer();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2014-2020 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.springframework.session.jdbc;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.test.context.ContextConfiguration;
|
||||||
|
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||||
|
import org.springframework.test.context.web.WebAppConfiguration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Integration tests for {@link JdbcIndexedSessionRepository} using Oracle database with
|
||||||
|
* {@link OracleJdbcIndexedSessionRepositoryCustomizer}.
|
||||||
|
*
|
||||||
|
* @author Vedran Pavic
|
||||||
|
*/
|
||||||
|
@ExtendWith(SpringExtension.class)
|
||||||
|
@WebAppConfiguration
|
||||||
|
@ContextConfiguration
|
||||||
|
class OracleJdbcIndexedSessionRepositoryCustomizerITests extends OracleJdbcIndexedSessionRepositoryITests {
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
static class CustomizerConfig extends Config {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
OracleJdbcIndexedSessionRepositoryCustomizer oracleJdbcIndexedSessionRepositoryCustomizer() {
|
||||||
|
return new OracleJdbcIndexedSessionRepositoryCustomizer();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2014-2020 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.springframework.session.jdbc;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.test.context.ContextConfiguration;
|
||||||
|
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||||
|
import org.springframework.test.context.web.WebAppConfiguration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Integration tests for {@link JdbcIndexedSessionRepository} using PostgreSQL 11.x
|
||||||
|
* database with {@link PostgreSqlJdbcIndexedSessionRepositoryCustomizer}.
|
||||||
|
*
|
||||||
|
* @author Vedran Pavic
|
||||||
|
*/
|
||||||
|
@ExtendWith(SpringExtension.class)
|
||||||
|
@WebAppConfiguration
|
||||||
|
@ContextConfiguration
|
||||||
|
class PostgreSql11JdbcIndexedSessionRepositoryCustomizerITests extends PostgreSql11JdbcIndexedSessionRepositoryITests {
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
static class CustomizerConfig extends Config {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
PostgreSqlJdbcIndexedSessionRepositoryCustomizer postgreSqlJdbcIndexedSessionRepositoryCustomizer() {
|
||||||
|
return new PostgreSqlJdbcIndexedSessionRepositoryCustomizer();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2014-2020 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.springframework.session.jdbc;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.test.context.ContextConfiguration;
|
||||||
|
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||||
|
import org.springframework.test.context.web.WebAppConfiguration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Integration tests for {@link JdbcIndexedSessionRepository} using SQL Server database
|
||||||
|
* with {@link SqlServerJdbcIndexedSessionRepositoryCustomizer}.
|
||||||
|
*
|
||||||
|
* @author Vedran Pavic
|
||||||
|
*/
|
||||||
|
@ExtendWith(SpringExtension.class)
|
||||||
|
@WebAppConfiguration
|
||||||
|
@ContextConfiguration
|
||||||
|
class SqlServerJdbcIndexedSessionRepositoryCustomizerITests extends SqlServerJdbcIndexedSessionRepositoryITests {
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
static class CustomizerConfig extends Config {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
SqlServerJdbcIndexedSessionRepositoryCustomizer sqlServerJdbcIndexedSessionRepositoryCustomizer() {
|
||||||
|
return new SqlServerJdbcIndexedSessionRepositoryCustomizer();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2014-2020 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.springframework.session.jdbc;
|
||||||
|
|
||||||
|
import org.springframework.session.config.SessionRepositoryCustomizer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link SessionRepositoryCustomizer} implementation that applies IBM DB2 specific
|
||||||
|
* optimized SQL statements to {@link JdbcIndexedSessionRepository}.
|
||||||
|
*
|
||||||
|
* @author Vedran Pavic
|
||||||
|
* @since 2.5.0
|
||||||
|
*/
|
||||||
|
public class Db2JdbcIndexedSessionRepositoryCustomizer
|
||||||
|
implements SessionRepositoryCustomizer<JdbcIndexedSessionRepository> {
|
||||||
|
|
||||||
|
// @formatter:off
|
||||||
|
private static final String CREATE_SESSION_ATTRIBUTE_QUERY = ""
|
||||||
|
+ "MERGE INTO %TABLE_NAME%_ATTRIBUTES SA "
|
||||||
|
+ "USING ( "
|
||||||
|
+ " SELECT PRIMARY_ID, ?, ? "
|
||||||
|
+ " FROM %TABLE_NAME% "
|
||||||
|
+ " WHERE SESSION_ID = ? "
|
||||||
|
+ ") A (SESSION_PRIMARY_ID, ATTRIBUTE_NAME, ATTRIBUTE_BYTES) "
|
||||||
|
+ "ON (SA.SESSION_PRIMARY_ID = A.SESSION_PRIMARY_ID and SA.ATTRIBUTE_NAME = A.ATTRIBUTE_NAME) "
|
||||||
|
+ "WHEN MATCHED THEN "
|
||||||
|
+ " UPDATE SET ATTRIBUTE_BYTES = A.ATTRIBUTE_BYTES "
|
||||||
|
+ "WHEN NOT MATCHED THEN "
|
||||||
|
+ " INSERT (SESSION_PRIMARY_ID, ATTRIBUTE_NAME, ATTRIBUTE_BYTES) "
|
||||||
|
+ " VALUES (A.SESSION_PRIMARY_ID, A.ATTRIBUTE_NAME, A.ATTRIBUTE_BYTES)";
|
||||||
|
// @formatter:on
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void customize(JdbcIndexedSessionRepository sessionRepository) {
|
||||||
|
sessionRepository.setCreateSessionAttributeQuery(CREATE_SESSION_ATTRIBUTE_QUERY);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2014-2019 the original author or authors.
|
* Copyright 2014-2020 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -268,7 +268,7 @@ public class JdbcIndexedSessionRepository
|
|||||||
*/
|
*/
|
||||||
public void setCreateSessionQuery(String createSessionQuery) {
|
public void setCreateSessionQuery(String createSessionQuery) {
|
||||||
Assert.hasText(createSessionQuery, "Query must not be empty");
|
Assert.hasText(createSessionQuery, "Query must not be empty");
|
||||||
this.createSessionQuery = createSessionQuery;
|
this.createSessionQuery = getQuery(createSessionQuery);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -277,7 +277,7 @@ public class JdbcIndexedSessionRepository
|
|||||||
*/
|
*/
|
||||||
public void setCreateSessionAttributeQuery(String createSessionAttributeQuery) {
|
public void setCreateSessionAttributeQuery(String createSessionAttributeQuery) {
|
||||||
Assert.hasText(createSessionAttributeQuery, "Query must not be empty");
|
Assert.hasText(createSessionAttributeQuery, "Query must not be empty");
|
||||||
this.createSessionAttributeQuery = createSessionAttributeQuery;
|
this.createSessionAttributeQuery = getQuery(createSessionAttributeQuery);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -286,7 +286,7 @@ public class JdbcIndexedSessionRepository
|
|||||||
*/
|
*/
|
||||||
public void setGetSessionQuery(String getSessionQuery) {
|
public void setGetSessionQuery(String getSessionQuery) {
|
||||||
Assert.hasText(getSessionQuery, "Query must not be empty");
|
Assert.hasText(getSessionQuery, "Query must not be empty");
|
||||||
this.getSessionQuery = getSessionQuery;
|
this.getSessionQuery = getQuery(getSessionQuery);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -295,7 +295,7 @@ public class JdbcIndexedSessionRepository
|
|||||||
*/
|
*/
|
||||||
public void setUpdateSessionQuery(String updateSessionQuery) {
|
public void setUpdateSessionQuery(String updateSessionQuery) {
|
||||||
Assert.hasText(updateSessionQuery, "Query must not be empty");
|
Assert.hasText(updateSessionQuery, "Query must not be empty");
|
||||||
this.updateSessionQuery = updateSessionQuery;
|
this.updateSessionQuery = getQuery(updateSessionQuery);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -304,7 +304,7 @@ public class JdbcIndexedSessionRepository
|
|||||||
*/
|
*/
|
||||||
public void setUpdateSessionAttributeQuery(String updateSessionAttributeQuery) {
|
public void setUpdateSessionAttributeQuery(String updateSessionAttributeQuery) {
|
||||||
Assert.hasText(updateSessionAttributeQuery, "Query must not be empty");
|
Assert.hasText(updateSessionAttributeQuery, "Query must not be empty");
|
||||||
this.updateSessionAttributeQuery = updateSessionAttributeQuery;
|
this.updateSessionAttributeQuery = getQuery(updateSessionAttributeQuery);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -313,7 +313,7 @@ public class JdbcIndexedSessionRepository
|
|||||||
*/
|
*/
|
||||||
public void setDeleteSessionAttributeQuery(String deleteSessionAttributeQuery) {
|
public void setDeleteSessionAttributeQuery(String deleteSessionAttributeQuery) {
|
||||||
Assert.hasText(deleteSessionAttributeQuery, "Query must not be empty");
|
Assert.hasText(deleteSessionAttributeQuery, "Query must not be empty");
|
||||||
this.deleteSessionAttributeQuery = deleteSessionAttributeQuery;
|
this.deleteSessionAttributeQuery = getQuery(deleteSessionAttributeQuery);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -322,7 +322,7 @@ public class JdbcIndexedSessionRepository
|
|||||||
*/
|
*/
|
||||||
public void setDeleteSessionQuery(String deleteSessionQuery) {
|
public void setDeleteSessionQuery(String deleteSessionQuery) {
|
||||||
Assert.hasText(deleteSessionQuery, "Query must not be empty");
|
Assert.hasText(deleteSessionQuery, "Query must not be empty");
|
||||||
this.deleteSessionQuery = deleteSessionQuery;
|
this.deleteSessionQuery = getQuery(deleteSessionQuery);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -331,7 +331,7 @@ public class JdbcIndexedSessionRepository
|
|||||||
*/
|
*/
|
||||||
public void setListSessionsByPrincipalNameQuery(String listSessionsByPrincipalNameQuery) {
|
public void setListSessionsByPrincipalNameQuery(String listSessionsByPrincipalNameQuery) {
|
||||||
Assert.hasText(listSessionsByPrincipalNameQuery, "Query must not be empty");
|
Assert.hasText(listSessionsByPrincipalNameQuery, "Query must not be empty");
|
||||||
this.listSessionsByPrincipalNameQuery = listSessionsByPrincipalNameQuery;
|
this.listSessionsByPrincipalNameQuery = getQuery(listSessionsByPrincipalNameQuery);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -340,7 +340,7 @@ public class JdbcIndexedSessionRepository
|
|||||||
*/
|
*/
|
||||||
public void setDeleteSessionsByExpiryTimeQuery(String deleteSessionsByExpiryTimeQuery) {
|
public void setDeleteSessionsByExpiryTimeQuery(String deleteSessionsByExpiryTimeQuery) {
|
||||||
Assert.hasText(deleteSessionsByExpiryTimeQuery, "Query must not be empty");
|
Assert.hasText(deleteSessionsByExpiryTimeQuery, "Query must not be empty");
|
||||||
this.deleteSessionsByExpiryTimeQuery = deleteSessionsByExpiryTimeQuery;
|
this.deleteSessionsByExpiryTimeQuery = getQuery(deleteSessionsByExpiryTimeQuery);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2014-2020 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.springframework.session.jdbc;
|
||||||
|
|
||||||
|
import org.springframework.session.config.SessionRepositoryCustomizer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link SessionRepositoryCustomizer} implementation that applies MySQL specific
|
||||||
|
* optimized SQL statements to {@link JdbcIndexedSessionRepository}.
|
||||||
|
*
|
||||||
|
* @author Vedran Pavic
|
||||||
|
* @since 2.5.0
|
||||||
|
*/
|
||||||
|
public class MySqlJdbcIndexedSessionRepositoryCustomizer
|
||||||
|
implements SessionRepositoryCustomizer<JdbcIndexedSessionRepository> {
|
||||||
|
|
||||||
|
// @formatter:off
|
||||||
|
private static final String CREATE_SESSION_ATTRIBUTE_QUERY = ""
|
||||||
|
+ "INSERT INTO %TABLE_NAME%_ATTRIBUTES (SESSION_PRIMARY_ID, ATTRIBUTE_NAME, ATTRIBUTE_BYTES) "
|
||||||
|
+ " SELECT PRIMARY_ID, ?, ? "
|
||||||
|
+ " FROM %TABLE_NAME% "
|
||||||
|
+ " WHERE SESSION_ID = ? "
|
||||||
|
+ "ON DUPLICATE KEY UPDATE ATTRIBUTE_BYTES = VALUES(ATTRIBUTE_BYTES)";
|
||||||
|
// @formatter:on
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void customize(JdbcIndexedSessionRepository sessionRepository) {
|
||||||
|
sessionRepository.setCreateSessionAttributeQuery(CREATE_SESSION_ATTRIBUTE_QUERY);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2014-2020 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.springframework.session.jdbc;
|
||||||
|
|
||||||
|
import org.springframework.session.config.SessionRepositoryCustomizer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link SessionRepositoryCustomizer} implementation that applies Oracle specific
|
||||||
|
* optimized SQL statements to {@link JdbcIndexedSessionRepository}.
|
||||||
|
*
|
||||||
|
* @author Vedran Pavic
|
||||||
|
* @since 2.5.0
|
||||||
|
*/
|
||||||
|
public class OracleJdbcIndexedSessionRepositoryCustomizer
|
||||||
|
implements SessionRepositoryCustomizer<JdbcIndexedSessionRepository> {
|
||||||
|
|
||||||
|
// @formatter:off
|
||||||
|
private static final String CREATE_SESSION_ATTRIBUTE_QUERY = ""
|
||||||
|
+ "MERGE INTO %TABLE_NAME%_ATTRIBUTES SA "
|
||||||
|
+ "USING ( "
|
||||||
|
+ " SELECT PRIMARY_ID AS SESSION_PRIMARY_ID, ? AS ATTRIBUTE_NAME, ? AS ATTRIBUTE_BYTES "
|
||||||
|
+ " FROM %TABLE_NAME% "
|
||||||
|
+ " WHERE SESSION_ID = ? "
|
||||||
|
+ ") A "
|
||||||
|
+ "ON (SA.SESSION_PRIMARY_ID = A.SESSION_PRIMARY_ID and SA.ATTRIBUTE_NAME = A.ATTRIBUTE_NAME) "
|
||||||
|
+ "WHEN MATCHED THEN "
|
||||||
|
+ " UPDATE SET ATTRIBUTE_BYTES = A.ATTRIBUTE_BYTES "
|
||||||
|
+ "WHEN NOT MATCHED THEN "
|
||||||
|
+ " INSERT (SESSION_PRIMARY_ID, ATTRIBUTE_NAME, ATTRIBUTE_BYTES) "
|
||||||
|
+ " VALUES (A.SESSION_PRIMARY_ID, A.ATTRIBUTE_NAME, A.ATTRIBUTE_BYTES)";
|
||||||
|
// @formatter:on
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void customize(JdbcIndexedSessionRepository sessionRepository) {
|
||||||
|
sessionRepository.setCreateSessionAttributeQuery(CREATE_SESSION_ATTRIBUTE_QUERY);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2014-2020 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.springframework.session.jdbc;
|
||||||
|
|
||||||
|
import org.springframework.session.config.SessionRepositoryCustomizer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link SessionRepositoryCustomizer} implementation that applies PostgreSQL specific
|
||||||
|
* optimized SQL statements to {@link JdbcIndexedSessionRepository}.
|
||||||
|
*
|
||||||
|
* @author Vedran Pavic
|
||||||
|
* @since 2.5.0
|
||||||
|
*/
|
||||||
|
public class PostgreSqlJdbcIndexedSessionRepositoryCustomizer
|
||||||
|
implements SessionRepositoryCustomizer<JdbcIndexedSessionRepository> {
|
||||||
|
|
||||||
|
// @formatter:off
|
||||||
|
private static final String CREATE_SESSION_ATTRIBUTE_QUERY = ""
|
||||||
|
+ "INSERT INTO %TABLE_NAME%_ATTRIBUTES (SESSION_PRIMARY_ID, ATTRIBUTE_NAME, ATTRIBUTE_BYTES) "
|
||||||
|
+ " SELECT PRIMARY_ID, ?, ? "
|
||||||
|
+ " FROM %TABLE_NAME% "
|
||||||
|
+ " WHERE SESSION_ID = ? "
|
||||||
|
+ "ON CONFLICT (SESSION_PRIMARY_ID, ATTRIBUTE_NAME) "
|
||||||
|
+ "DO UPDATE SET ATTRIBUTE_BYTES = EXCLUDED.ATTRIBUTE_BYTES";
|
||||||
|
// @formatter:on
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void customize(JdbcIndexedSessionRepository sessionRepository) {
|
||||||
|
sessionRepository.setCreateSessionAttributeQuery(CREATE_SESSION_ATTRIBUTE_QUERY);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2014-2020 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.springframework.session.jdbc;
|
||||||
|
|
||||||
|
import org.springframework.session.config.SessionRepositoryCustomizer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link SessionRepositoryCustomizer} implementation that applies SQL Server specific
|
||||||
|
* optimized SQL statements to {@link JdbcIndexedSessionRepository}.
|
||||||
|
*
|
||||||
|
* @author Vedran Pavic
|
||||||
|
* @since 2.5.0
|
||||||
|
*/
|
||||||
|
public class SqlServerJdbcIndexedSessionRepositoryCustomizer
|
||||||
|
implements SessionRepositoryCustomizer<JdbcIndexedSessionRepository> {
|
||||||
|
|
||||||
|
// @formatter:off
|
||||||
|
private static final String CREATE_SESSION_ATTRIBUTE_QUERY = ""
|
||||||
|
+ "MERGE INTO %TABLE_NAME%_ATTRIBUTES SA "
|
||||||
|
+ "USING ( "
|
||||||
|
+ " SELECT PRIMARY_ID, ?, ? "
|
||||||
|
+ " FROM %TABLE_NAME% "
|
||||||
|
+ " WHERE SESSION_ID = ? "
|
||||||
|
+ ") A (SESSION_PRIMARY_ID, ATTRIBUTE_NAME, ATTRIBUTE_BYTES) "
|
||||||
|
+ "ON (SA.SESSION_PRIMARY_ID = A.SESSION_PRIMARY_ID and SA.ATTRIBUTE_NAME = A.ATTRIBUTE_NAME) "
|
||||||
|
+ "WHEN MATCHED THEN "
|
||||||
|
+ " UPDATE SET ATTRIBUTE_BYTES = A.ATTRIBUTE_BYTES "
|
||||||
|
+ "WHEN NOT MATCHED THEN "
|
||||||
|
+ " INSERT (SESSION_PRIMARY_ID, ATTRIBUTE_NAME, ATTRIBUTE_BYTES) "
|
||||||
|
+ " VALUES (A.SESSION_PRIMARY_ID, A.ATTRIBUTE_NAME, A.ATTRIBUTE_BYTES);";
|
||||||
|
// @formatter:on
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void customize(JdbcIndexedSessionRepository sessionRepository) {
|
||||||
|
sessionRepository.setCreateSessionAttributeQuery(CREATE_SESSION_ATTRIBUTE_QUERY);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user