适用版本:v3.3.6+;

dependency

<dependency>
    <groupId>net.oschina.j2cache</groupId>
    <artifactId>j2cache-core</artifactId>
    <version>${j2cache-core.version}</version>
</dependency>

<dependency>
    <groupId>net.oschina.j2cache</groupId>
    <artifactId>j2cache-mybatis</artifactId>
    <version>${j2cache.version}</version>
</dependency>

配置说明

j2cache.properties配置说明:

配置文件位于platform/business服务下的config/j2cache.properties文件

# 缓存广播方法,支持 jgroups/redis/lettuce/rabbitmq/rocketmq
j2cache.broadcast = lettuce

# 第一二级缓存实现方式,一级支持 ehcache/caffeine, 二级支持 redis/lettuce/memcached
j2cache.L1.provider_class = caffeine
j2cache.L2.provider_class = lettuce

# 在redis缓存数据中启用/禁用ttl(如果禁用,redis中的对象将永远不会过期,默认值:true)
j2cache.sync_ttl_to_redis = true

# 默认情况下是否缓存空对象(默认为false)
j2cache.default_cache_null_object = true

# 缓存序列化方式,支持 fst/kryo/fastjson/java/json/fse
j2cache.serialization = kryo

# caffeine配置文件
caffeine.properties = /config/caffeine.properties

# 缓存名称空间可选,默认为[空]
# redis存储模式 支持 generic/hash
# 发布/订阅频道名称
lettuce.namespace =
lettuce.storage = generic
lettuce.channel = j2cache.platform

caffeine.properties配置说明:

配置文件位于platform/business服务下的config/caffeine.properties文件

 #########################################
  # Caffeine configuration
  # [name] = size, xxxx[s|m|h|d]
  #########################################
  // 默认缓存,大小是 1000 个对象,TTL 是 30 分钟
  // default 是当我们调用如下方法时:
  //public void set(String region, String key, Object value)
  //如果我们传入的 region 参数(假设为:region1)没有在 caffeine.properties 中定义的话,那 J2Cache 会自动创建一个名为 region1 的缓存 Region,其配置和 default 的配置一致。
  default = 1000, 30m

  ifrom.context = 10000, 10m

  ifrom.sys = 10000, 1h
  ifrom.res = 10000, 1h
  ifrom.client = 3000, 1h
  ifrom.category = 10000, 2h
  ifrom.desktop = 1000, 8h

  ifrom.group = 1000, 1h
  ifrom.attr = 10000, 1h
  ifrom.level = 100, 1h
  ifrom.party = 10000, 1h

API说明

缓存的相关操作是在Domain和Repository层实现的,具体代码可以在 IBase,IRepository,AbstracDomain,AbstracRepository 中查看。

IBase

// 对象缓存是否启用
default boolean isCacheOpenning()

// 对象缓存是否启用空对象缓存,v3.2.4配置
default boolean isCacheNullObject()

// 返回缓存名称
default String getCacheName()

// 返回内部缓存名称
default String getInternalCacheName()

// 根据pk清除对应缓存
default void evict(PK pk)

// 根据pk和data存入缓存
default void caching(PK pk, P data)

// 返回内部类型
default String getInternalType()

// 根据pk值返回存入缓存中的key值
default String getPKString(PK pk)

IRepository

// 列表缓存是否启用
default boolean isCacheListOpenning()

// 是否跳过内部方法
default Boolean isSkipInternal()

// 是否跳过缓存
default Boolean isSkipCache()

AbstracRepository

// 根据id值从缓存中获取到对应对象完整信息
public P get(PK id)

// originSqlKey:查询所有字段的SqlKey,cacheSqlKey:只查询id字段的SqlKey,queryFilter:查询条件
public List<P> queryByKey(String originSqlKey, String cacheSqlKey, QueryFilter queryFilter)

使用示例

以 DefaultPartyUser 的仓库和领域类为例子

  • 仓库
// DefaultPartyUserRepositoryImpl

...
@Override
    public String getInternalCacheName() {
        return CacheKeyConstants.Region.REGION_IBPS_PARTY; // 返回对应的region名称
    }

    @Override
    public String getInternalType() {
        return "DefaultPartyUser"; // 返回对应的类型名称,一般为类的名称即可
    }

    @Override
    public void getInternal(DefaultPartyUserPo p) {
        if(BeanUtils.isEmpty(p)) {
            return;
        }
        partyEmployeeRepository.setSkipInternal();
        PartyEmployeePo employeePo = partyEmployeeRepository.get(p.getId());
        partyEmployeeRepository.removeSkipInternal();
        if(BeanUtils.isEmpty(employeePo)) {
            return;
        }

        p.setFullname(employeePo.getName());
        p.setName(employeePo.getName());
        p.setStatus(employeePo.getStatus());
        p.setGender(employeePo.getGender());
        p.setMobile(employeePo.getMobile());
        p.setEmail(employeePo.getEmail());
        p.setAddress(employeePo.getAddress());
        p.setQq(employeePo.getQq());
        p.setPhoto(employeePo.getPhoto());
        p.setWcAccount(employeePo.getWcAccount());
    }

    @Override
    public List<DefaultPartyUserPo> findByParams(Map<String, Object> params) {
        return findByKey("findByParams", "findIdsByParams", params);
    }
...
  • 领域
// DefaultPartyUser
...
@Override
    public String getInternalCacheName() {
        return CacheKeyConstants.Region.REGION_IBPS_PARTY; // 返回对应的region名称
    }

    @Override
    public String getInternalType() {
        return "DefaultPartyUser"; // 返回对应的类型名称,一般为类的名称即可
    }
...
  • Provider
// PartyUserProvider
...
    @ApiOperation(value = "查询", notes = "根据id查询")
    @Override
    public APIResult<PartyUserPo> get(
            @ApiParam(name = "userId", value = "用户ID", required = true)  
            @RequestParam(name = "userId", required = true)String userId) {
        APIResult<PartyUserPo> result = new APIResult<>();
        try {
            PartyUserPo partyUserPo = defaultPartyUserRepository.get(userId);
            result.setData(partyUserPo);
        } catch (Exception e) {
            setExceptionResult(result, StateEnum.ERROR_EMPLOYEE.getCode(), I18nUtil.getMessage(StateEnum.ERROR_EMPLOYEE.getCode()+""), e);
        }
        return result;
    }
...
  • 映射文件
// DefaultPartyUser.map

    <sql id="querySql">
        SELECT * FROM IFORM_PARTY_USER
        left join 
        (
            select ID_ USER_ID_, NAME_, NAME_ FULL_NAME_,STATUS_,GENDER_,EMAIL_,WC_ACCOUNT_,ADDRESS_,MOBILE_,QQ_,PHOTO_ from IBPS_PARTY_EMPLOYEE
        )A on USER_ID_ = ID_
        <where>
            USER_ID_ != '-1' AND A.STATUS_ != 'deleted'
            <if test="@o.Ognl@isNotEmpty(whereSql)">
                and ${whereSql}
            </if>
        </where>
        <if test="@o.Ognl@isNotEmpty(orderBySql)">
            ORDER BY ${orderBySql}
        </if>
        <if test="@o.Ognl@isEmpty(orderBySql)">
            ORDER BY CREATE_TIME_ DESC
        </if>
    </sql>

    <select id="query" parameterType="java.util.Map" resultMap="DefaultPartyUser">
        <include refid="querySql"/>
    </select>

    <select id="queryIds" parameterType="java.util.Map" resultMap="DefaultPartyUser">
        SELECT ID_ FROM (<include refid="querySql"/>) T
    </select>

    <select id="findDialogUserByParam" parameterType="java.util.Map" resultMap="DefaultPartyUser">
        <include refid="findDialogUserByParamSql"/>
    </select>

    <select id="findDialogUserIdsByParamNew" parameterType="java.util.Map" resultMap="DefaultPartyUser">
        SELECT ID_ FROM (<include refid="findDialogUserByParamSql"/>) T
    </select>

缓存中对象是根据id值进行区分,映射文件中,除了常规的query方法,还应该有只查询id字段的queryIds方法,提供给缓存使用。findByKey和queryByKey方法同理,但非必须,写法参考如上代码。

仓库和领域类需要重写getInternalCacheName方法,参考如上写法,返回对应的缓存分区。setSkipInternal 和 removeSkipInternal 方法为设置是否跳过内部方法,即是否跳过getInternal方法,具体可查看AbstracReposity类中的get方法。

通过如上配置后,通过仓库的get方法,传入对象的id值,会先去缓存中查找对象,缓存中没有,才会到数据库中查询。

作者:caoyl  创建时间:2024-02-29 18:01
最后编辑:caoyl  更新时间:2024-11-25 19:17