應用系統中針對時效性敏感度比較低的數據,一般會進行緩存,比較流行的緩存系統包括:Redis, Memcache 等,例如:電商中商品的時效敏感度相對較低,商戶上線或變動的商品數量和頻率相對較大,若是實時變動數據存儲,對數據庫的衝擊比較大;而後,會員對商品變動的的敏感度也有相應的容忍度,這類數據在電商的應用系統中會採起批量存儲和查詢緩存的策略。ObjectiveSQL 針對數據查詢提供了擴展性接口,具體擴展特性以下:java
public interface SQLExecutor<T> { List<T> query(Connection connection, String sql, TableRowAdapter tableRowAdapter, Object... params) throws SQLException; default T insert(Connection connection, String sql, TableRowAdapter tableRowAdapter, Object... params) throws SQLException { throw new UnsupportedOperationException("The insert is unsupported"); }; default int[] insert(Connection connection, String sql, TableRowAdapter tableRowAdapter, Object[][] params) throws SQLException { throw new UnsupportedOperationException("The insert is unsupported"); } default int execute(Connection connection, String sql, Object... params) throws SQLException { throw new UnsupportedOperationException("The execute is unsupported"); }; }
SQLExecutor 是ObjectiveSQL 的一個擴展接口,主要的做用有兩點:1)針對SQL 的執行過程進行干預,缺省使用的是Apache DBUtils 的形式進行JDBC 操做,主要也就是將關係數據轉換成Java Bean,若是若是經過自身高性的的方式進行轉換能夠實現該接口,並將其注入ObjectiveSQL;2)不改變具體的處理邏輯,但須要將查詢出的數據進行緩期或其它形式的處理,也能夠實現該接口,但須要extends
DefaultSQLExecutor,而後進行個性化處理。git
以Redis 緩存爲示例,也是比較經常使用的緩存處理方式,示例以下:github
import com.github.braisdom.example.model.Member; import com.github.braisdom.objsql.DefaultSQLExecutor; import com.github.braisdom.objsql.TableRowAdapter; import org.springframework.util.SerializationUtils; import redis.clients.jedis.Jedis; import redis.clients.jedis.params.SetParams; import java.io.Serializable; import java.math.BigInteger; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.sql.Connection; import java.sql.SQLException; import java.util.Arrays; import java.util.List; public class CacheableSQLExecutor<T> extends DefaultSQLExecutor<T> { private static final List<Class<? extends Serializable>> CACHEABLE_CLASSES = Arrays.asList(new Class[]{Member.class}); private static final Integer CACHED_OBJECT_EXPIRED = 60; private static final String KEY_SHA = "SHA"; private Jedis jedis = new Jedis("127.0.0.1", 6379); private MessageDigest messageDigest; public CacheableSQLExecutor() { try { messageDigest = MessageDigest.getInstance(KEY_SHA); } catch (NoSuchAlgorithmException e) { throw new IllegalArgumentException(e.getMessage(), e); } } @Override public List<T> query(Connection connection, String sql, TableRowAdapter tableRowAdapter, Object... params) throws SQLException { Class<?> domainClass = tableRowAdapter.getDomainModelClass(); if (CACHEABLE_CLASSES.contains(domainClass)) { if(!Serializable.class.isAssignableFrom(domainClass)) throw new IllegalArgumentException(String.format("The %s cannot be serialized")); messageDigest.update(sql.getBytes()); String hashedSqlId = new BigInteger(messageDigest.digest()).toString(64); byte[] rawObjects = jedis.get(hashedSqlId.getBytes()); if (rawObjects != null) { return (List<T>) SerializationUtils.deserialize(rawObjects); } else { List<T> objects = super.query(connection, sql, tableRowAdapter, params); byte[] encodedObjects = SerializationUtils.serialize(objects); SetParams expiredParams = SetParams.setParams().ex(CACHED_OBJECT_EXPIRED); jedis.set(hashedSqlId.getBytes(), encodedObjects, expiredParams); return objects; } } return super.query(connection, sql, tableRowAdapter, params); } }
原理很簡單,以SQL 爲基礎,轉換爲SHA KEY 的形式存儲進Redis,並設置過時時間。redis