应用系统中针对时效性敏感度比较低的数据,通常会进行缓存,比较流行的缓存系统包括:Redis, Memcache 等,例如:电商中商品的时效敏感度相对较低,商户上线或变更的商品数量和频率相对较大,如果实时变更数据存储,对数据库的冲击比较大;然后,会员对商品变更的的敏感度也有相应的容忍度,这类数据在电商的应用系统中会采取批量存储和查询缓存的策略。ObjectiveSQL 针对数据查询提供了扩展性接口,具体扩展特性如下:
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,然后进行个性化处理。
以Redis 缓存为示例,也是比较常用的缓存处理方式,示例如下:
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,并设置过期时间。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。