优惠券项目---------------第九章

mysql的存储原理。

-----------------------------------------------------------------------9-1-------------------------------------------------------------------------------

设定缓存的时间是一分钟。在数据库添加数据不会马上生效的。

-----------------------------------------------------------------------9-2-------------------------------------------------------------------------------

缓存怎么做?

异步刷缓存,过期了主动刷新。用户一直拿缓存。优惠券只有十几张。而且用户拿到的优惠券是一样的。

用户触发,查询用户信息。比如几千万人,只有几百个人是热点用户。

-----------------------------------------------------------------------9-3-------------------------------------------------------------------------------

优惠券列表用Google的GauvaCache去缓存。

异步刷缓存。

找个是java的只要是java的程序,就可以接入这套东西。

 LoadingCache<Integer,List<TCoupon>> couponCache = CacheBuilder.newBuilder()
             // 过期时间  隔多久去刷缓存 新建一个cacheloader去load数据
            .expireAfterWrite(10,TimeUnit.MINUTES).refreshAfterWrite(5,TimeUnit.MINUTES)
            .build(new CacheLoader<Integer, List<TCoupon>>() {
                @Override
                public List<TCoupon> load(Integer o) throws Exception {
                    return loadCoupon(o);
                }
            });

-----------------------------------------------------------------------9-4-------------------------------------------------------------------------------

常用的组件:

@GwtCompatible
public interface LoadingCache<K, V> extends Cache<K, V>, Function<K, V> {
    V get(K var1) throws ExecutionException;

    V getUnchecked(K var1); // 报错返回null

    ImmutableMap<K, V> getAll(Iterable<? extends K> var1) throws ExecutionException;

    /** @deprecated */
    @Deprecated
    V apply(K var1);

    void refresh(K var1);// 不常用

    ConcurrentMap<K, V> asMap(); //转化
}

再往下:

@GwtCompatible
public interface Cache<K, V> {
    @Nullable
    V getIfPresent(@CompatibleWith("K") Object var1);// 手动刷新不阻塞 拿不到值直接返回null 不阻塞

    V get(K var1, Callable<? extends V> var2) throws ExecutionException;

    ImmutableMap<K, V> getAllPresent(Iterable<?> var1);

    void put(K var1, V var2);

    void putAll(Map<? extends K, ? extends V> var1);

    void invalidate(@CompatibleWith("K") Object var1);

    void invalidateAll(Iterable<?> var1);

    void invalidateAll();

    long size();

    CacheStats stats();

    ConcurrentMap<K, V> asMap();

    void cleanUp();
}

-----------------------------------------------------------------------9-5-------------------------------------------------------------------------------

经典的案例:

代码:

package com.xdclass.couponapp.service;

import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.Lists;
import com.xdclass.couponapp.constant.Constant;
import com.xdclass.couponapp.domain.TCoupon;
import com.xdclass.couponapp.domain.TCouponExample;
import com.xdclass.couponapp.mapper.TCouponMapper;
import com.xdclass.userapi.service.IUserService;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
public class CouponService {

    @Resource
    private TCouponMapper tCouponMapper;

    @Reference
    private IUserService iUserService;

    LoadingCache<Integer,List<TCoupon>> couponCache = CacheBuilder.newBuilder()
             // 过期时间  隔多久去刷缓存 新建一个cacheloader去load数据
            .expireAfterWrite(10,TimeUnit.MINUTES).refreshAfterWrite(5,TimeUnit.MINUTES)
            .build(new CacheLoader<Integer, List<TCoupon>>() {
                @Override
                public List<TCoupon> load(Integer o) throws Exception {
                    return loadCoupon(o);
                }
            });


    LoadingCache<Integer,TCoupon> couponIdsCache = CacheBuilder.newBuilder()
            .expireAfterWrite(10,TimeUnit.MINUTES).refreshAfterWrite(5,TimeUnit.MINUTES)
            .build(new CacheLoader<Integer,TCoupon>() {
                @Override
                public TCoupon load(Integer o) throws Exception {
                    return loadIdCoupon(o);
                }
            });

    private TCoupon loadIdCoupon(Integer id) {
        return tCouponMapper.selectByPrimaryKey(id);
    }

    public List<TCoupon> getCouponListByIds(String ids){
        String[] idStr = ids.split(",");
        List<Integer> loadFromDB = Lists.newArrayList();
        List<TCoupon> tCoupons = Lists.newArrayList();
        List<String> idList = Lists.newArrayList(idStr);
        for (String id:idList) {
            TCoupon tCoupon =  couponIdsCache.getIfPresent(id);
            if (tCoupon==null){
                loadFromDB.add(Integer.parseInt(id));
            }else {
                tCoupons.add(tCoupon);
            }
        }
        List<TCoupon> tCoupons1 = couponByIds(loadFromDB);
        Map<Integer,TCoupon> tCouponMap = tCoupons1.stream().collect(Collectors.toMap(TCoupon::getId, TCoupon->TCoupon));
        tCoupons.addAll(tCoupons1);
        //将返回结果会写到缓存里面
        couponIdsCache.putAll(tCouponMap);
        return tCoupons;
    }


    /**
     * 范围id的优惠券
     * @param ids
     * @return
     */
    private List<TCoupon> couponByIds(List<Integer> ids) {
        TCouponExample example = new TCouponExample();
        example.createCriteria().andIdIn(ids);
        return tCouponMapper.selectByExample(example);
    }

    //1,2,3
    //1,2,4
    //1,2
    //1,2,3,4

    /**
     * 获取指定日期内有效的优惠券
     * @param o
     * @return
     */
    private List<TCoupon> loadCoupon(Integer o) {
        TCouponExample example = new TCouponExample();
        example.createCriteria().andStatusEqualTo(Constant.USERFUL)
                .andStartTimeLessThan(new Date()).andEndTimeGreaterThan(new Date());
        return tCouponMapper.selectByExample(example);
    }

    /***
     * 在缓存获取有效时间的可用优惠券列表
     * @return
     */
    public List<TCoupon> getCouponList(){
        List<TCoupon> tCoupons = Lists.newArrayList();
        try {
            tCoupons =  couponCache.get(1);
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        return tCoupons;
        // 1、是否存在远程调用 HTTP、RPC Metrics
        // 2、大量内存处理  list.contain() ==>set.contain
    }


    public void print(){
        System.err.println("enter coupon service");
    }

    // 通过优惠券码查优惠券
    public String query(){
        TCouponExample example = new TCouponExample();
        example.createCriteria().andCodeEqualTo("0057da3c-f2ad-42bd-b6d2-8bb58b6dbc90");
        List<TCoupon> tCoupon =  tCouponMapper.selectByExample(example);
        return tCoupon.get(0).toString();
    }

    // 通过id查找user
    public String getUserById(int id){
        return iUserService.getUserById(id).toString();
    }


}

测试的方法:

http://localhost:8088/test1

结果:第一次进入这个方法

   LoadingCache<Integer,List<TCoupon>> couponCache = CacheBuilder.newBuilder()
             // 过期时间  隔多久去刷缓存 新建一个cacheloader去load数据
            .expireAfterWrite(10,TimeUnit.MINUTES).refreshAfterWrite(5,TimeUnit.MINUTES)
            .build(new CacheLoader<Integer, List<TCoupon>>() {
                @Override
                public List<TCoupon> load(Integer o) throws Exception {
                    return loadCoupon(o);
                }
            });

传入参数为1。

第二次直接返回。属于主动的。

这句话:

tCoupons =  couponCache.get(1);

http://localhost:8088/test2?ids=1,2

结果:没有直接返回,查出来就putAll属于被动的。

-----------------------------------------------------------------------9-6-------------------------------------------------------------------------------

发布了374 篇原创文章 · 获赞 12 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_28764557/article/details/104783300