Collectors.toMap 在批量缓存中的运用

前言

在实际项目中经常有一个需求,就是在本地将对象缓存起来,Java 里面常被作为缓存工具的数据结构就是 Map。关于 Collectors.toMap 的更多说明可以查看 Java 8 特性 - Collectors. toMap

缓存体系

  1. 首先定义个缓存键接口
public interface Cacheable<K> {
   K getCachedKey();
}
  1. 其次构建一个对象类
public static class Person implements Cacheable<Integer> {
    private Integer id;
    private String name;
    private Integer age;

    public Person(Integer id, String name, Integer age) {
        this.id = id;
        this.name = name;
        this.age = age;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return String.format("Person[id = %d, name = %s, age = %d", id, name, age);
    }

    public Integer getCachedKey() {
        return id;
    }
}
  1. 再次,构建一个缓存类
import java.util.Map;
import java.util.HashMap;

public static class Cache {
    // 为了保证缓存类的线程安全性,所以使用了 ThreadLocal
    private static final ThreadLocal<Map<Object, Cacheable>> CACHE_HOLDER = ThreadLocal.withInitial(HashMap::new);

    public static <K> Cacheable getCache(K key) {
        return CACHE_HOLDER.get().get(key);
    }

    public static <K> void setCache(Cacheable<K> cachedObj) {
        CACHE_HOLDER.get()
                .put(cachedObj.getCachedKey(), cachedObj);
    }

	public static void clearCache() {
		CACHE_HOLDER.remove();
	}
	
	public static <T> void print() {
        for (Map.Entry<Object, Cacheable> entry : CACHE_HOLDER.get().entrySet()) {
	        System.out.println(entry);
        }
    }
}
  1. 最后构建一个测试类
 public class CacheClassTest {
 	public static void main(String[] args) {
        Thread thread1 = new Thread(() -> {
            try {
                // 生成待缓存对象
                Person person = new Person(1, "zhangsan", 21);

                // 缓存
                Cache.setCache(person);

                // 访问缓存对象
                System.out.println(Cache.getCache(person.getCachedKey()));
            } finally {
                Cache.clearCache();
            }
        });


        Thread thread2 = new Thread(() -> {
            try {
                // 生成待缓存对象
                Person person = new Person(1, "lisi", 21);

                // 缓存
                Cache.setCache(person);

                // 访问缓存对象
                System.out.println(Cache.getCache(person.getCachedKey()));
            } finally {
                Cache.clearCache();
            }
        });

        thread1.start();
        thread2.start();
    }
}

运行结果为
在这里插入图片描述

可以看出上面的缓存体系能保证线程安全的前提下,正常工作。

缓存体系升级

上面的缓存体系只能对单个对象进行缓存,如果现在从数据库中读取了大量的数据,按照现有的 API ,其调用过程代码为:

public class CacheClassTest {
	public static void main(String[] args) {
        List<Cacheable<Integer>> people = new ArrayList<>();
        people.add(new Person(1, "zhangsan", 21));
        people.add(new Person(2, "lisi", 23));

		// 遍历数据列表进行缓存
        for (Person person : people) {
            Cache.setCache(person);
        }

		Cache.print();
    }
}

在这里插入图片描述
虽然这种迭代数据列表的写法可行,但这样做增加了用户的工作量,显然是不够优雅的,所以需要在缓存体系中增加批量缓存的功能。

新增批量缓存功能的缓存体系最终代码——新增代码主要是通过使用 Java 8 流式计算以及 Collectors.toMap 方法来实现的

public static class Cache {
   // 为了保证缓存类的线程安全性,所以使用了 ThreadLocal
    private static final ThreadLocal<Map<Object, Cacheable>> CACHE_HOLDER = ThreadLocal.withInitial(HashMap::new);

    public static <K> Cacheable getCache(K key) {
        return CACHE_HOLDER.get().get(key);
    }

    public static <K> void setCache(Cacheable<K> cachedObj) {
        CACHE_HOLDER.get()
                .put(cachedObj.getCachedKey(), cachedObj);
    }

	// 批量缓存
    public static <K> void setCache(List<Cacheable<K>> cachedObjs) {
        CACHE_HOLDER.get()
                .putAll(cachedObjs.stream()
                        .collect(Collectors.toMap(Cacheable::getCachedKey,
                                Function.identity(),
                                (oldValue, newValue) -> newValue, HashMap::new)));
    }

    public static void clearCache() {
        CACHE_HOLDER.remove();
    }

    public static <T> void print() {
        for (Map.Entry<Object, Cacheable> entry : CACHE_HOLDER.get().entrySet()) {
            System.out.println(entry);
        }
    }
}

测试代码为

public class CacheClassTest {
	public static void main(String[] args) {
        List<Cacheable<Integer>> people = new ArrayList<>();
        people.add(new Person(1, "zhangsan", 21));
        people.add(new Person(2, "lisi", 23));
        
		Cache.setCache(people);

		Cache.print();
    }
}

测试结果为
在这里插入图片描述

private void checkGoodsStock(Goods goods, Integer buyNum) { //商品为现货商品,判断商品现货可用库存 if (GoodsSaleType.SPOT == GoodsSaleType.findSaleType(goods.getSaleType())) { //单个商品、意向商品 if (GoodsShelveType.SINGLE.getShelveType() == goods.getShelveType() || GoodsShelveType.INTENTION.getShelveType() == goods.getShelveType()) { BaseGoods baseGoods = iBaseGoodsService.getOne(Wrappers.<BaseGoods>lambdaQuery().in(BaseGoods::getModel, goods.getModel()).last("for update")); if (buyNum > baseGoods.getSpotOccupyStock()) { throw new ServiceException(ErrorMessage.STOCK_ERROR); } } //组合商品 if (GoodsShelveType.COMBINATION.getShelveType() == goods.getShelveType()) { //查询组合商品子商品信息 List<GoodsChilds> goodsChildsList = goodsChildsService.lambdaQuery().eq(GoodsChilds::getParentId, goods.getId()).eq(GoodsChilds::getIsGift, 0).list(); if (CollectionUtils.isEmpty(goodsChildsList)) { throw new ServiceException("组合商品子商品信息为空"); } //子商品所有商品型号 List<String> goodsChildsModelList = goodsChildsList.stream().map(GoodsChilds::getModel).collect(Collectors.toList()); List<BaseGoods> baseGoodsList = iBaseGoodsService.list(Wrappers.<BaseGoods>lambdaQuery().in(BaseGoods::getModel, goodsChildsModelList).last("for update")); Map<String, BaseGoods> baseGoodsMap = AppUtils.listToMap(baseGoodsList, BaseGoods::getModel); for (GoodsChilds goodsChilds : goodsChildsList) { BaseGoods baseGoods = baseGoodsMap.get(goodsChilds.getModel()); if (baseGoods == null) { throw new ServiceException("商品型号不存在"); } //子商品总购买数 Integer goodsChildsBuyNum = goodsChilds.getNumberCoefficient().multiply(new BigDecimal(buyNum)).intValue(); if (goodsChildsBuyNum > baseGoods.getSpotOccupyStock()) { throw new ServiceException(ErrorMessage.STOCK_ERROR); } } } } //非现货商品,判断上架库存 if (GoodsSaleType.SPOT != GoodsSaleType.findSaleType(goods.getSaleType()) && buyNum > goods.getStock()) { throw new ServiceException(ErrorMessage.STOCK_ERROR); } }优化该段代码
06-06
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值