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();
}
}
测试的方法:
结果:第一次进入这个方法
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-------------------------------------------------------------------------------