Add custom SQL JdbcOperationsSessionRepository

This commit allows custom SQL queries for
JdbcOperationsSessionRepository.

Fixes gh-609
This commit is contained in:
Vedran Pavic
2016-08-02 09:48:44 +02:00
committed by Rob Winch
parent 6335894e13
commit 26eca5b448
3 changed files with 271 additions and 11 deletions

View File

@@ -1080,6 +1080,7 @@ However, you can override the default `ConversionService` by providing a Bean na
By default, this implementation uses `SPRING_SESSION` and `SPRING_SESSION_ATTRIBUTES` tables to store sessions.
Note that the table name can be easily customized as already described. In that case the table used to store attributes will be named using the provided table name, suffixed with `_ATTRIBUTES`.
If further customizations are needed, SQL queries used by the repository can be customized using `set*Query` setter methods. In this case you need to manually configure the `sessionRepository` bean.
Due to the differences between the various database vendors, especially when it comes to storing binary data, make sure to use SQL script specific to your database.
Scripts for most major database vendors are packaged as `org/springframework/session/jdbc/schema-\*.sql`, where `*` is the target database type.

View File

@@ -196,6 +196,24 @@ public class JdbcOperationsSessionRepository implements
*/
private String tableName = DEFAULT_TABLE_NAME;
private String createSessionQuery;
private String createSessionAttributeQuery;
private String getSessionQuery;
private String updateSessionQuery;
private String updateSessionAttributeQuery;
private String deleteSessionAttributeQuery;
private String deleteSessionQuery;
private String listSessionsByPrincipalNameQuery;
private String deleteSessionsByLastAccessTimeQuery;
/**
* If non-null, this value is used to override the default value for
* {@link JdbcSession#setMaxInactiveIntervalInSeconds(int)}.
@@ -229,6 +247,7 @@ public class JdbcOperationsSessionRepository implements
this.jdbcOperations = jdbcOperations;
this.transactionOperations = createTransactionTemplate(transactionManager);
this.conversionService = createDefaultConversionService();
prepareQueries();
}
/**
@@ -238,6 +257,88 @@ public class JdbcOperationsSessionRepository implements
public void setTableName(String tableName) {
Assert.hasText(tableName, "Table name must not be empty");
this.tableName = tableName.trim();
prepareQueries();
}
/**
* Set the custom SQL query used to create the session.
* @param createSessionQuery the SQL query string
*/
public void setCreateSessionQuery(String createSessionQuery) {
Assert.hasText(createSessionQuery, "Query must not be empty");
this.createSessionQuery = createSessionQuery;
}
/**
* Set the custom SQL query used to create the session attribute.
* @param createSessionAttributeQuery the SQL query string
*/
public void setCreateSessionAttributeQuery(String createSessionAttributeQuery) {
Assert.hasText(createSessionAttributeQuery, "Query must not be empty");
this.createSessionAttributeQuery = createSessionAttributeQuery;
}
/**
* Set the custom SQL query used to retrieve the session.
* @param getSessionQuery the SQL query string
*/
public void setGetSessionQuery(String getSessionQuery) {
Assert.hasText(getSessionQuery, "Query must not be empty");
this.getSessionQuery = getSessionQuery;
}
/**
* Set the custom SQL query used to update the session.
* @param updateSessionQuery the SQL query string
*/
public void setUpdateSessionQuery(String updateSessionQuery) {
Assert.hasText(updateSessionQuery, "Query must not be empty");
this.updateSessionQuery = updateSessionQuery;
}
/**
* Set the custom SQL query used to update the session attribute.
* @param updateSessionAttributeQuery the SQL query string
*/
public void setUpdateSessionAttributeQuery(String updateSessionAttributeQuery) {
Assert.hasText(updateSessionAttributeQuery, "Query must not be empty");
this.updateSessionAttributeQuery = updateSessionAttributeQuery;
}
/**
* Set the custom SQL query used to delete the session attribute.
* @param deleteSessionAttributeQuery the SQL query string
*/
public void setDeleteSessionAttributeQuery(String deleteSessionAttributeQuery) {
Assert.hasText(deleteSessionAttributeQuery, "Query must not be empty");
this.deleteSessionAttributeQuery = deleteSessionAttributeQuery;
}
/**
* Set the custom SQL query used to delete the session.
* @param deleteSessionQuery the SQL query string
*/
public void setDeleteSessionQuery(String deleteSessionQuery) {
Assert.hasText(deleteSessionQuery, "Query must not be empty");
this.deleteSessionQuery = deleteSessionQuery;
}
/**
* Set the custom SQL query used to retrieve the sessions by principal name.
* @param listSessionsByPrincipalNameQuery the SQL query string
*/
public void setListSessionsByPrincipalNameQuery(String listSessionsByPrincipalNameQuery) {
Assert.hasText(listSessionsByPrincipalNameQuery, "Query must not be empty");
this.listSessionsByPrincipalNameQuery = listSessionsByPrincipalNameQuery;
}
/**
* Set the custom SQL query used to delete the sessions by last access time.
* @param deleteSessionsByLastAccessTimeQuery the SQL query string
*/
public void setDeleteSessionsByLastAccessTimeQuery(String deleteSessionsByLastAccessTimeQuery) {
Assert.hasText(deleteSessionsByLastAccessTimeQuery, "Query must not be empty");
this.deleteSessionsByLastAccessTimeQuery = deleteSessionsByLastAccessTimeQuery;
}
/**
@@ -278,7 +379,7 @@ public class JdbcOperationsSessionRepository implements
protected void doInTransactionWithoutResult(TransactionStatus status) {
JdbcOperationsSessionRepository.this.jdbcOperations.update(
getQuery(CREATE_SESSION_QUERY),
JdbcOperationsSessionRepository.this.createSessionQuery,
new PreparedStatementSetter() {
public void setValues(PreparedStatement ps) throws SQLException {
@@ -293,7 +394,7 @@ public class JdbcOperationsSessionRepository implements
if (!session.getAttributeNames().isEmpty()) {
final List<String> attributeNames = new ArrayList<String>(session.getAttributeNames());
JdbcOperationsSessionRepository.this.jdbcOperations.batchUpdate(
getQuery(CREATE_SESSION_ATTRIBUTE_QUERY),
JdbcOperationsSessionRepository.this.createSessionAttributeQuery,
new BatchPreparedStatementSetter() {
public void setValues(PreparedStatement ps, int i) throws SQLException {
@@ -319,7 +420,7 @@ public class JdbcOperationsSessionRepository implements
protected void doInTransactionWithoutResult(TransactionStatus status) {
if (session.isChanged()) {
JdbcOperationsSessionRepository.this.jdbcOperations.update(
getQuery(UPDATE_SESSION_QUERY),
JdbcOperationsSessionRepository.this.updateSessionQuery,
new PreparedStatementSetter() {
public void setValues(PreparedStatement ps)
@@ -337,7 +438,7 @@ public class JdbcOperationsSessionRepository implements
for (final Map.Entry<String, Object> entry : delta.entrySet()) {
if (entry.getValue() == null) {
JdbcOperationsSessionRepository.this.jdbcOperations.update(
getQuery(DELETE_SESSION_ATTRIBUTE_QUERY),
JdbcOperationsSessionRepository.this.deleteSessionAttributeQuery,
new PreparedStatementSetter() {
public void setValues(PreparedStatement ps) throws SQLException {
@@ -349,7 +450,7 @@ public class JdbcOperationsSessionRepository implements
}
else {
int updatedCount = JdbcOperationsSessionRepository.this.jdbcOperations.update(
getQuery(UPDATE_SESSION_ATTRIBUTE_QUERY),
JdbcOperationsSessionRepository.this.updateSessionAttributeQuery,
new PreparedStatementSetter() {
public void setValues(PreparedStatement ps) throws SQLException {
@@ -361,7 +462,7 @@ public class JdbcOperationsSessionRepository implements
});
if (updatedCount == 0) {
JdbcOperationsSessionRepository.this.jdbcOperations.update(
getQuery(CREATE_SESSION_ATTRIBUTE_QUERY),
JdbcOperationsSessionRepository.this.createSessionAttributeQuery,
new PreparedStatementSetter() {
public void setValues(PreparedStatement ps) throws SQLException {
@@ -387,7 +488,7 @@ public class JdbcOperationsSessionRepository implements
public ExpiringSession doInTransaction(TransactionStatus status) {
List<ExpiringSession> sessions = JdbcOperationsSessionRepository.this.jdbcOperations.query(
getQuery(GET_SESSION_QUERY),
JdbcOperationsSessionRepository.this.getSessionQuery,
new PreparedStatementSetter() {
public void setValues(PreparedStatement ps) throws SQLException {
@@ -421,7 +522,7 @@ public class JdbcOperationsSessionRepository implements
protected void doInTransactionWithoutResult(TransactionStatus status) {
JdbcOperationsSessionRepository.this.jdbcOperations.update(
getQuery(DELETE_SESSION_QUERY), id);
JdbcOperationsSessionRepository.this.deleteSessionQuery, id);
}
});
@@ -437,7 +538,7 @@ public class JdbcOperationsSessionRepository implements
public List<ExpiringSession> doInTransaction(TransactionStatus status) {
return JdbcOperationsSessionRepository.this.jdbcOperations.query(
getQuery(LIST_SESSIONS_BY_PRINCIPAL_NAME_QUERY),
JdbcOperationsSessionRepository.this.listSessionsByPrincipalNameQuery,
new PreparedStatementSetter() {
public void setValues(PreparedStatement ps) throws SQLException {
@@ -479,7 +580,7 @@ public class JdbcOperationsSessionRepository implements
public Integer doInTransaction(TransactionStatus transactionStatus) {
return JdbcOperationsSessionRepository.this.jdbcOperations.update(
getQuery(DELETE_SESSIONS_BY_LAST_ACCESS_TIME_QUERY),
JdbcOperationsSessionRepository.this.deleteSessionsByLastAccessTimeQuery,
sessionsValidFromTime);
}
@@ -515,10 +616,24 @@ public class JdbcOperationsSessionRepository implements
return converter;
}
protected String getQuery(String base) {
private String getQuery(String base) {
return StringUtils.replace(base, "%TABLE_NAME%", this.tableName);
}
private void prepareQueries() {
this.createSessionQuery = getQuery(CREATE_SESSION_QUERY);
this.createSessionAttributeQuery = getQuery(CREATE_SESSION_ATTRIBUTE_QUERY);
this.getSessionQuery = getQuery(GET_SESSION_QUERY);
this.updateSessionQuery = getQuery(UPDATE_SESSION_QUERY);
this.updateSessionAttributeQuery = getQuery(UPDATE_SESSION_ATTRIBUTE_QUERY);
this.deleteSessionAttributeQuery = getQuery(DELETE_SESSION_ATTRIBUTE_QUERY);
this.deleteSessionQuery = getQuery(DELETE_SESSION_QUERY);
this.listSessionsByPrincipalNameQuery =
getQuery(LIST_SESSIONS_BY_PRINCIPAL_NAME_QUERY);
this.deleteSessionsByLastAccessTimeQuery =
getQuery(DELETE_SESSIONS_BY_LAST_ACCESS_TIME_QUERY);
}
private void serialize(PreparedStatement ps, int paramIndex, Object attributeValue)
throws SQLException {
this.lobHandler.getLobCreator().setBlobAsBytes(ps, paramIndex,

View File

@@ -139,6 +139,150 @@ public class JdbcOperationsSessionRepositoryTests {
this.repository.setTableName(" ");
}
@Test
public void setCreateSessionQueryNull() {
this.thrown.expect(IllegalArgumentException.class);
this.thrown.expectMessage("Query must not be empty");
this.repository.setCreateSessionQuery(null);
}
@Test
public void setCreateSessionQueryEmpty() {
this.thrown.expect(IllegalArgumentException.class);
this.thrown.expectMessage("Query must not be empty");
this.repository.setCreateSessionQuery(" ");
}
@Test
public void setCreateSessionAttributeQueryNull() {
this.thrown.expect(IllegalArgumentException.class);
this.thrown.expectMessage("Query must not be empty");
this.repository.setCreateSessionAttributeQuery(null);
}
@Test
public void setCreateSessionAttributeQueryEmpty() {
this.thrown.expect(IllegalArgumentException.class);
this.thrown.expectMessage("Query must not be empty");
this.repository.setCreateSessionAttributeQuery(" ");
}
@Test
public void setGetSessionQueryNull() {
this.thrown.expect(IllegalArgumentException.class);
this.thrown.expectMessage("Query must not be empty");
this.repository.setGetSessionQuery(null);
}
@Test
public void setGetSessionQueryEmpty() {
this.thrown.expect(IllegalArgumentException.class);
this.thrown.expectMessage("Query must not be empty");
this.repository.setGetSessionQuery(" ");
}
@Test
public void setUpdateSessionQueryNull() {
this.thrown.expect(IllegalArgumentException.class);
this.thrown.expectMessage("Query must not be empty");
this.repository.setUpdateSessionQuery(null);
}
@Test
public void setUpdateSessionQueryEmpty() {
this.thrown.expect(IllegalArgumentException.class);
this.thrown.expectMessage("Query must not be empty");
this.repository.setUpdateSessionQuery(" ");
}
@Test
public void setUpdateSessionAttributeQueryNull() {
this.thrown.expect(IllegalArgumentException.class);
this.thrown.expectMessage("Query must not be empty");
this.repository.setUpdateSessionAttributeQuery(null);
}
@Test
public void setUpdateSessionAttributeQueryEmpty() {
this.thrown.expect(IllegalArgumentException.class);
this.thrown.expectMessage("Query must not be empty");
this.repository.setUpdateSessionAttributeQuery(" ");
}
@Test
public void setDeleteSessionAttributeQueryNull() {
this.thrown.expect(IllegalArgumentException.class);
this.thrown.expectMessage("Query must not be empty");
this.repository.setDeleteSessionAttributeQuery(null);
}
@Test
public void setDeleteSessionAttributeQueryEmpty() {
this.thrown.expect(IllegalArgumentException.class);
this.thrown.expectMessage("Query must not be empty");
this.repository.setDeleteSessionAttributeQuery(" ");
}
@Test
public void setDeleteSessionQueryNull() {
this.thrown.expect(IllegalArgumentException.class);
this.thrown.expectMessage("Query must not be empty");
this.repository.setDeleteSessionQuery(null);
}
@Test
public void setDeleteSessionQueryEmpty() {
this.thrown.expect(IllegalArgumentException.class);
this.thrown.expectMessage("Query must not be empty");
this.repository.setDeleteSessionQuery(" ");
}
@Test
public void setListSessionsByPrincipalNameQueryNull() {
this.thrown.expect(IllegalArgumentException.class);
this.thrown.expectMessage("Query must not be empty");
this.repository.setListSessionsByPrincipalNameQuery(null);
}
@Test
public void setListSessionsByPrincipalNameQueryEmpty() {
this.thrown.expect(IllegalArgumentException.class);
this.thrown.expectMessage("Query must not be empty");
this.repository.setListSessionsByPrincipalNameQuery(" ");
}
@Test
public void setDeleteSessionsByLastAccessTimeQueryNull() {
this.thrown.expect(IllegalArgumentException.class);
this.thrown.expectMessage("Query must not be empty");
this.repository.setDeleteSessionsByLastAccessTimeQuery(null);
}
@Test
public void setDeleteSessionsByLastAccessTimeQueryEmpty() {
this.thrown.expect(IllegalArgumentException.class);
this.thrown.expectMessage("Query must not be empty");
this.repository.setDeleteSessionsByLastAccessTimeQuery(" ");
}
@Test
public void setLobHandlerNull() {
this.thrown.expect(IllegalArgumentException.class);