Skip to content

Commit 5cb6ac1

Browse files
committed
JdbcOperationsSessionRepository: deserialize lazily
Instead of deserializing all of the session attributes as they are read from the database, deserialize as getAttribute(String) requests them. For applications which store a lot of data in the session but only use some of it for each requests, this change results in a lot less time being spent doing deserialization of objects that won't be used. For other applications, no harm is done.
1 parent 5277d94 commit 5cb6ac1

File tree

1 file changed

+56
-12
lines changed

1 file changed

+56
-12
lines changed

spring-session-jdbc/src/main/java/org/springframework/session/jdbc/JdbcOperationsSessionRepository.java

Lines changed: 56 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import java.util.Map;
2929
import java.util.Set;
3030
import java.util.UUID;
31+
import java.util.function.Supplier;
3132
import java.util.stream.Collectors;
3233

3334
import org.apache.commons.logging.Log;
@@ -530,7 +531,7 @@ private void insertSessionAttributes(JdbcSession session, List<String> attribute
530531
public void setValues(PreparedStatement ps, int i) throws SQLException {
531532
String attributeName = attributeNames.get(i);
532533
ps.setString(1, attributeName);
533-
serialize(ps, 2, session.getAttribute(attributeName));
534+
bytesToLob(ps, 2, serialize(session.getAttribute(attributeName)));
534535
ps.setString(3, session.getId());
535536
}
536537

@@ -545,7 +546,7 @@ public int getBatchSize() {
545546
this.jdbcOperations.update(this.createSessionAttributeQuery, (ps) -> {
546547
String attributeName = attributeNames.get(0);
547548
ps.setString(1, attributeName);
548-
serialize(ps, 2, session.getAttribute(attributeName));
549+
bytesToLob(ps, 2, serialize(session.getAttribute(attributeName)));
549550
ps.setString(3, session.getId());
550551
});
551552
}
@@ -559,7 +560,7 @@ private void updateSessionAttributes(JdbcSession session, List<String> attribute
559560
@Override
560561
public void setValues(PreparedStatement ps, int i) throws SQLException {
561562
String attributeName = attributeNames.get(i);
562-
serialize(ps, 1, session.getAttribute(attributeName));
563+
bytesToLob(ps, 1, serialize(session.getAttribute(attributeName)));
563564
ps.setString(2, session.primaryKey);
564565
ps.setString(3, attributeName);
565566
}
@@ -574,7 +575,7 @@ public int getBatchSize() {
574575
else {
575576
this.jdbcOperations.update(this.updateSessionAttributeQuery, (ps) -> {
576577
String attributeName = attributeNames.get(0);
577-
serialize(ps, 1, session.getAttribute(attributeName));
578+
bytesToLob(ps, 1, serialize(session.getAttribute(attributeName)));
578579
ps.setString(2, session.primaryKey);
579580
ps.setString(3, attributeName);
580581
});
@@ -657,18 +658,26 @@ private void prepareQueries() {
657658
getQuery(DELETE_SESSIONS_BY_EXPIRY_TIME_QUERY);
658659
}
659660

660-
private void serialize(PreparedStatement ps, int paramIndex, Object attributeValue)
661+
private void bytesToLob(PreparedStatement ps, int paramIndex, byte[] bytes)
661662
throws SQLException {
662663
this.lobHandler.getLobCreator().setBlobAsBytes(ps, paramIndex,
663-
(byte[]) this.conversionService.convert(attributeValue,
664+
bytes);
665+
}
666+
667+
private byte[] serialize(Object attributeValue) {
668+
return (byte[]) this.conversionService.convert(attributeValue,
664669
TypeDescriptor.valueOf(Object.class),
665-
TypeDescriptor.valueOf(byte[].class)));
670+
TypeDescriptor.valueOf(byte[].class));
666671
}
667672

668-
private Object deserialize(ResultSet rs, String columnName)
673+
private byte[] lobToBytes(ResultSet rs, String columnName)
669674
throws SQLException {
675+
return this.lobHandler.getBlobAsBytes(rs, columnName);
676+
}
677+
678+
private Object deserialize(byte[] bytes) {
670679
return this.conversionService.convert(
671-
this.lobHandler.getBlobAsBytes(rs, columnName),
680+
bytes,
672681
TypeDescriptor.valueOf(byte[].class),
673682
TypeDescriptor.valueOf(Object.class));
674683
}
@@ -679,6 +688,34 @@ private enum DeltaValue {
679688

680689
}
681690

691+
static final <Z> Supplier<Z> constantSupplier(Z value) {
692+
if (value == null) {
693+
return null;
694+
}
695+
else {
696+
return () -> value;
697+
}
698+
}
699+
700+
static final <Z> Supplier<Z> lazily(Supplier<Z> supplier) {
701+
if (supplier == null) {
702+
return null;
703+
}
704+
else {
705+
return new Supplier<Z>() {
706+
private Z value;
707+
708+
@Override
709+
public Z get() {
710+
if (this.value == null) {
711+
this.value = supplier.get();
712+
}
713+
return this.value;
714+
}
715+
};
716+
}
717+
}
718+
682719
/**
683720
* The {@link Session} to use for {@link JdbcOperationsSessionRepository}.
684721
*
@@ -748,7 +785,13 @@ public String changeSessionId() {
748785

749786
@Override
750787
public <T> T getAttribute(String attributeName) {
751-
return this.delegate.getAttribute(attributeName);
788+
Supplier<T> supplier = this.delegate.getAttribute(attributeName);
789+
if (supplier == null) {
790+
return null;
791+
}
792+
else {
793+
return supplier.get();
794+
}
752795
}
753796

754797
@Override
@@ -783,7 +826,7 @@ public void setAttribute(String attributeName, Object attributeValue) {
783826
? oldDeltaValue
784827
: DeltaValue.UPDATED));
785828
}
786-
this.delegate.setAttribute(attributeName, attributeValue);
829+
this.delegate.setAttribute(attributeName, constantSupplier(attributeValue));
787830
if (PRINCIPAL_NAME_INDEX_NAME.equals(attributeName) ||
788831
SPRING_SECURITY_CONTEXT.equals(attributeName)) {
789832
this.changed = true;
@@ -875,7 +918,8 @@ public List<JdbcSession> extractData(ResultSet rs) throws SQLException, DataAcce
875918
}
876919
String attributeName = rs.getString("ATTRIBUTE_NAME");
877920
if (attributeName != null) {
878-
session.delegate.setAttribute(attributeName, deserialize(rs, "ATTRIBUTE_BYTES"));
921+
byte[] bytes = lobToBytes(rs, "ATTRIBUTE_BYTES");
922+
session.delegate.setAttribute(attributeName, lazily(() -> deserialize(bytes)));
879923
}
880924
sessions.add(session);
881925
}

0 commit comments

Comments
 (0)