PostgreSqlJdbcIndexedSessionRepositoryCustomizer makes the JdbcIndexedSessionRepository use a modified SQL query for creating session attributes which handles conflicting inserts better than the original query. In Spring Boot 2.7 all you had to do was adding a PostgreSqlJdbcIndexedSessionRepositoryCustomizer bean to the application context. In Spring Boot 3.0 that no longer seems to work.

Steps to Reproduce

I have pushed a minimal reproducible example to GitHub.

The example contains 2 versions of the same test application, one based on Spring Boot 2.7.6, the other one based on Spring Boot 3.0.0. Both share this configuration:

package org.devopsix.boot.session;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.session.jdbc.PostgreSqlJdbcIndexedSessionRepositoryCustomizer;

@Configuration
public class SessionConfig {

    @Bean
    public PostgreSqlJdbcIndexedSessionRepositoryCustomizer postgreSqlJdbcIndexedSessionRepositoryCustomizer() {
        return new PostgreSqlJdbcIndexedSessionRepositoryCustomizer();
    }
}
  1. Check out the example.
  2. Run mvn -f spring-boot-2.7/pom.xml verify
  3. Run mvn -f spring-boot-3.0/pom.xml verify

The first command will print something like this:

2022-12-05 15:08:07.234 DEBUG 6284 --- [o-auto-1-exec-1] o.s.jdbc.core.JdbcTemplate               : Executing prepared SQL statement [INSERT INTO SPRING_SESSION_ATTRIBUTES (SESSION_PRIMARY_ID, ATTRIBUTE_NAME, ATTRIBUTE_BYTES) VALUES
 (?, ?, ?) ON CONFLICT (SESSION_PRIMARY_ID, ATTRIBUTE_NAME) DO UPDATE SET ATTRIBUTE_BYTES = EXCLUDED.ATTRIBUTE_BYTES]

The presence of ON CONFLICT ... means the modified SQL query is being used.

The second command will print something like this:

2022-12-05T15:08:52.170+01:00 DEBUG 13560 --- [o-auto-1-exec-1] o.s.jdbc.core.JdbcTemplate               : Executing prepared SQL statement [INSERT INTO SPRING_SESSION_ATTRIBUTES (SESSION_PRIMARY_ID, ATTRIBUTE_NAME, ATTRIBUTE_BYTES)
VALUES (?, ?, ?)
]

The absence of ON CONFLICT ... means the modified SQL query is not being used.

Suspected Cause and Potential Work-Arounds

JdbcSessionConfiguration.springBootSessionRepositoryCustomizer adds another customizer to the application context. JdbcHttpSessionConfiguration.sessionRepository happens to apply PostgreSqlJdbcIndexedSessionRepositoryCustomizer before the other customizer. Unfortunately, the other customizer seems to cause JdbcIndexedSessionRepository#prepareQueries to be invoked again which overrides the customized query.

Adding @Order(Ordered.LOWEST_PRECEDENCE) to the PostgreSqlJdbcIndexedSessionRepositoryCustomizer bean has not helped. As far as I understand, the other customizer (implicitly) also has LOWEST_PRECEDENCE and hence that does not change the order of application.

I ended up adding an InitializingBean bean to the application context which in its afterPropertiesSet method applies PostgreSqlJdbcIndexedSessionRepositoryCustomizer to the repository bean again.

Comment From: philwebb

Closing in favor of PR #33514.

Comment From: izeye

The above comment seems to reference a wrong issue. It seems to need to be https://github.com/spring-projects/spring-boot/pull/33514, not https://github.com/spring-projects/spring-boot/pull/33663.

Comment From: wilkinsona

Thanks, @izeye. I've updated Phil's comment.