Spring sessions in a Separate Database
Storing session details in Redis or database is usually a good idea. However, the default implementation of spring-session-jdbc uses the primary data source to store and retrieve data from the session related tables. This can be a problem when there is a large amount of session related operations to the database.
To avoid these situations, it is a good idea to move the session related schema to a separate database. In this example we will see how we can use two separate databases, one for the application and one for storing sessions.
Before going further I would like you to take a look at spring session using JDBC for a little background on how to implement JDBC session store.
The easiest way we can supply data source to the sessions related auto-configuration is by defining a DataSource
bean with @SpringSessionDataSource
annotation. At first, it may seem easy, but it is not. When you define your own DataSource
bean, It will mess up the default autowiring. To safely provide a second data source, you need to follow these instructions.
Storing sessions in a different Database
First, create two sets of properties for each database. In my case, I’m using two separate in-memory h2 databases for the demo.
debug=true
# Properties for primary database
spring.datasource.url=jdbc:h2:mem:test
spring.datasource.username=root
spring.datasource.password=root
spring.h2.console.enabled=true
# Properties for session database
session.datasource.url=jdbc:h2:mem:sessions
session.datasource.username=sessions
session.datasource.password=sessions
Code language: PHP (php)
Then manually create both the data source using DataSourceProperties
properties. The spring.datasource
configurations will be used to create the primary data source. The session.datasource
properties will be used for creating the session data source.
@Configuration
public class DataSourceConfig {
@Bean
@Primary
@ConfigurationProperties("spring.datasource")
@Qualifier("dataSource")
public DataSourceProperties dataSourceProperties() {
return new DataSourceProperties();
}
@Bean
@Primary
public DataSource primaryDataSource(@Qualifier("dataSource") DataSourceProperties dataSourceProperties) {
return dataSourceProperties
.initializeDataSourceBuilder()
.type(HikariDataSource.class)
.build();
}
@Bean
@ConfigurationProperties("session.datasource")
@Qualifier("sessionDataSourceProperties")
public DataSourceProperties sessionDataSourceProperties() {
return new DataSourceProperties();
}
@Bean
@Qualifier("sessionDataSource")
@SpringSessionDataSource
public DataSource sessionDataSource(@Qualifier("sessionDataSourceProperties") DataSourceProperties sessionDataSourceProperties) {
return sessionDataSourceProperties
.initializeDataSourceBuilder()
.type(HikariDataSource.class)
.build();
}
}
Code language: CSS (css)
In the above configuration class, notice how I marked sessionDataSource
as @SpringSessionDataSource
. Also, I have made sure both the data sources and their properties are distinguishable by their names using @Qualifier
.
Initializing session schema
If you are using a database like Oracle or MySQL, You are already done. Create the session related tables (SPRING_SESSION
,SPRING_SESSION_ATTRIBUTES
) in the database pointed by sessionDataSource
and you are good to go. But if you want to use an embedded data source like in this demo or if you set the spring.session.jdbc.initialize-schema
to always
, then you have a problem.
The default auto-configuration does not know which dataSource to autowire for JdbcSessionDataSourceInitializer
. So it may end up creating session tables in the primary data source. To avoid this you need to provide your own JdbcSessionDataSourceInitializer
bean as shown below.
@Configuration
@EnableConfigurationProperties(JdbcSessionProperties.class)
public class JdbcSessionConfig {
@Bean
public JdbcSessionDataSourceInitializer
jdbcSessionDataSourceInitializer(@Qualifier("sessionDataSource") DataSource sessionDataSource,
ResourceLoader resourceLoader,
JdbcSessionProperties properties) {
return new JdbcSessionDataSourceInitializer(sessionDataSource, resourceLoader, properties);
}
}
Code language: PHP (php)
In the above configuration note how I have used @Qualifier
to load the sessionDataSource
. Also, note that you need to EnableConfigurationProperties
for autowiring JdbcSessionProperties
.
If we do all of this right, You can see that the session database having two tables, and the primary database will be used by the application.
You can find this example in this GitHub Repository. Feel free to take a look.