From 93aee206fbc20c849559fd512aef333489e36c46 Mon Sep 17 00:00:00 2001 From: Vedran Pavic Date: Tue, 25 Sep 2018 18:45:02 +0200 Subject: [PATCH] Configure default LobHandler to use temporary LOBs on Oracle JdbcOperationsSessionRepository recently introduced validation when inserting new session attributes in order to prevent data integrity violations in highly concurrent environments. This is done by using INSERT INTO ... SELECT statement to verify existence of session record in parent table. Such arrangement causes problems with Oracle if inserted attribute is of size 4 kb or more. This commit enhances JdbcHttpSessionConfiguration to detect Oracle database is used, and set createTemporaryLob option on default LobHandler to true. Resolves: #1203 See also: #1031 --- ...JdbcOperationsSessionRepositoryITests.java | 15 +++++++++++++++ .../http/JdbcHttpSessionConfiguration.java | 19 +++++++++++++++++++ 2 files changed, 34 insertions(+) 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 555ceef2..267862cf 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 @@ -811,6 +811,21 @@ public abstract class AbstractJdbcOperationsSessionRepositoryITests { .isEqualTo("value2"); } + @Test // gh-1203 + public void saveWithLargeAttribute() { + String attributeName = "largeAttribute"; + int arraySize = 4000; + + JdbcOperationsSessionRepository.JdbcSession session = this.repository + .createSession(); + session.setAttribute(attributeName, new byte[arraySize]); + this.repository.save(session); + session = this.repository.findById(session.getId()); + + assertThat(session).isNotNull(); + assertThat((byte[]) session.getAttribute(attributeName)).hasSize(arraySize); + } + private String getSecurityName() { return this.context.getAuthentication().getName(); } diff --git a/spring-session-jdbc/src/main/java/org/springframework/session/jdbc/config/annotation/web/http/JdbcHttpSessionConfiguration.java b/spring-session-jdbc/src/main/java/org/springframework/session/jdbc/config/annotation/web/http/JdbcHttpSessionConfiguration.java index 45f35ee7..cc5d156d 100644 --- a/spring-session-jdbc/src/main/java/org/springframework/session/jdbc/config/annotation/web/http/JdbcHttpSessionConfiguration.java +++ b/spring-session-jdbc/src/main/java/org/springframework/session/jdbc/config/annotation/web/http/JdbcHttpSessionConfiguration.java @@ -35,6 +35,9 @@ import org.springframework.core.serializer.support.DeserializingConverter; import org.springframework.core.serializer.support.SerializingConverter; import org.springframework.core.type.AnnotationMetadata; import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.support.JdbcUtils; +import org.springframework.jdbc.support.MetaDataAccessException; +import org.springframework.jdbc.support.lob.DefaultLobHandler; import org.springframework.jdbc.support.lob.LobHandler; import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.scheduling.annotation.SchedulingConfigurer; @@ -102,6 +105,11 @@ public class JdbcHttpSessionConfiguration extends SpringHttpSessionConfiguration if (this.lobHandler != null) { sessionRepository.setLobHandler(this.lobHandler); } + else if (requiresTemporaryLob(this.dataSource)) { + DefaultLobHandler lobHandler = new DefaultLobHandler(); + lobHandler.setCreateTemporaryLob(true); + sessionRepository.setLobHandler(lobHandler); + } if (this.springSessionConversionService != null) { sessionRepository.setConversionService(this.springSessionConversionService); } @@ -115,6 +123,17 @@ public class JdbcHttpSessionConfiguration extends SpringHttpSessionConfiguration return sessionRepository; } + private static boolean requiresTemporaryLob(DataSource dataSource) { + try { + String productName = JdbcUtils.extractDatabaseMetaData(dataSource, + "getDatabaseProductName"); + return "Oracle".equalsIgnoreCase(JdbcUtils.commonDatabaseName(productName)); + } + catch (MetaDataAccessException ex) { + return false; + } + } + public void setMaxInactiveIntervalInSeconds(Integer maxInactiveIntervalInSeconds) { this.maxInactiveIntervalInSeconds = maxInactiveIntervalInSeconds; }