乐趣区

关于java:ObjectiveSQL-扩展之Redis-缓存

利用零碎中针对时效性敏感度比拟低的数据,通常会进行缓存,比拟风行的缓存零碎包含: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,并设置过期工夫。

退出移动版