1. Redis入门案例

=============

1.1 Redis常见用法

1.1.1 setex学习

`/**     * 2.需要:     *      1.向redis中插入数据  k-v     *      2.为key设定超时工夫  60秒后生效.     *      3.线程sleep 3秒     *      4.获取key的残余的存活工夫.     *     *   问题形容: 数据肯定会被删除吗??????     *   问题阐明: 如果应用redis 并且须要增加超时工夫时 个别须要满足原子性要求.     *   原子性:   操作时要么胜利 要么失败.然而必须同时实现.     */    @Test    public void test02() throws InterruptedException {        Jedis jedis = new Jedis("192.168.126.129",6379);        jedis.setex("宝可梦", 60, "小火龙 妙蛙种子");        System.out.println(jedis.get("宝可梦"));       /* Jedis jedis = new Jedis("192.168.126.129",6379);        jedis.set("宝可梦", "小火龙 妙蛙种子");        int a = 1/0;    //可能会出异样        jedis.expire("宝可梦", 60);        Thread.sleep(3000);        System.out.println(jedis.ttl("宝可梦"));*/    }` 

1.1.2 setnx

`/**     * 3.需要如果发现key曾经存在时 不批改数据.如果key不存在时才会批改数据.     *     */    @Test    public void test03() throws InterruptedException {        Jedis jedis = new Jedis("192.168.126.129", 6379);        jedis.setnx("aaaa", "测试nx的办法");        /*if(jedis.exists("aaa")){            System.out.println("key曾经存在 不做批改");        }else {            jedis.set("aaa", "测试数据");        }*/        System.out.println(jedis.get("aaaa"));    }` 

1.1.3 set 超时工夫原子性操作

 `/**     * 需要:     *  1.要求用户赋值时,如果数据存在则不赋值.  setnx     *  2.要求在赋值操作时,必须设定超时的工夫 并且要求满足原子性 setex     */    @Test    public void test04() throws InterruptedException {        Jedis jedis = new Jedis("192.168.126.129", 6379);        SetParams setParams = new SetParams();        setParams.nx().ex(20);        jedis.set("bbbb", "实现业务操作AAAA", setParams);        System.out.println(jedis.get("bbbb"));    }` 

1.1.4 list汇合练习

 `@Test    public void testList() throws InterruptedException {        Jedis jedis = new Jedis("192.168.126.129", 6379);        jedis.lpush("list", "1","2","3");        System.out.println(jedis.rpop("list"));    }` 

1.1.5 redis事务管制

 `@Test    public void testTx() throws InterruptedException {        Jedis jedis = new Jedis("192.168.126.129", 6379);        //1.开启事务        Transaction transaction = jedis.multi();        try {            transaction.set("aa", "aa");            //提交事务            transaction.exec();        }catch (Exception e){            e.printStackTrace();            //回滚事务            transaction.discard();        }    }` 

2.秒杀业务逻辑—分布式锁机制

6988 —1块 1部手机 20显示抢购胜利 并且领取了1块钱…
问题:
1.tomcat服务器有多台
2.数据库数据只有1份
3.必然会呈现高并发的景象.
如何实现抢购…

2.1惯例锁操作

2.1.1 超卖的起因

2.1.2 同步锁的问题

阐明:同步锁只能解决tomcat外部的问题,不能解决多个tomcat并发问题

2.1.3 分布式锁机制

思维:
1.锁应该应用第三方操作 ,锁应该专用.
2.准则:如果锁被人正在应用时,其余的用户不能操作.
3.策略: 用户向redis中保留一个key,如果redis中有key示意有人正在应用这把锁 其余用户不容许操作.如果redis中没有key ,则示意我能够应用这把锁.
4.危险: 如何解决死锁问题. 设定超时工夫.

  1. SpringBoot整合Redis

=====================

3.1 编辑配置文件 redis.pro

阐明:因为该配置被其余的我的项目独特应用,则应该写到jt-common中.

3.2 编辑配置类

阐明: 编辑redis配置类.将Jedis对象交给Spring容器进行治理.

`@Configuration@PropertySource("classpath:/properties/redis.properties")public class JedisConfig {    @Value("${redis.host}")    private String host;    @Value("${redis.port}")    private Integer port;    @Bean    public Jedis jedis(){        return new Jedis(host,port);    }}` 

3.3 对象与JSON转化 ObjectMapper介绍

3.3.1 简略对象转化

`/**     * 测试简略对象的转化     */    @Test    public void test01() throws JsonProcessingException {        ObjectMapper objectMapper = new ObjectMapper();        ItemDesc itemDesc = new ItemDesc();        itemDesc.setItemId(100L).setItemDesc("商品详情信息")                .setCreated(new Date()).setUpdated(new Date());        //对象转化为json        String json = objectMapper.writeValueAsString(itemDesc);        System.out.println(json);        //json转化为对象        ItemDesc itemDesc2 = objectMapper.readValue(json, ItemDesc.class);        System.out.println(itemDesc2.getItemDesc());    }` 

3.3.2 汇合对象转化

 `/**     * 测试汇合对象的转化     */    @Test    public void test02() throws JsonProcessingException {        ObjectMapper objectMapper = new ObjectMapper();        ItemDesc itemDesc = new ItemDesc();        itemDesc.setItemId(100L).setItemDesc("商品详情信息1")                .setCreated(new Date()).setUpdated(new Date());        ItemDesc itemDesc2 = new ItemDesc();        itemDesc2.setItemId(100L).setItemDesc("商品详情信息2")                .setCreated(new Date()).setUpdated(new Date());        List<ItemDesc> lists = new ArrayList<>();        lists.add(itemDesc);        lists.add(itemDesc2);        //[{key:value},{}]        String json = objectMapper.writeValueAsString(lists);        System.out.println(json);        //将json串转化为对象        List<ItemDesc> list2 = objectMapper.readValue(json, lists.getClass());        System.out.println(list2);    }` 

3.4 编辑工具API

`package com.jt.util;import com.fasterxml.jackson.core.JsonProcessingException;import com.fasterxml.jackson.databind.ObjectMapper;import com.jt.pojo.ItemDesc;import org.springframework.util.StringUtils;public class ObjectMapperUtil {    /**     * 1.将用户传递的数据转化为json串     * 2.将用户传递的json串转化为对象     */    private static final ObjectMapper MAPPER = new ObjectMapper();     //1.将用户传递的数据转化为json串    public static String toJSON(Object object){        if(object == null) {            throw new RuntimeException("传递的数据为null.请查看");        }        try {            String json = MAPPER.writeValueAsString(object);            return json;        } catch (JsonProcessingException e) {            //将查看异样,转化为运行时异样            e.printStackTrace();            throw new RuntimeException(e);        }    }    //需要: 要求用户传递什么样的类型,我返回什么样的对象  泛型的常识    public static <T> T toObj(String json,Class<T> target){        if(StringUtils.isEmpty(json) || target ==null){            throw new RuntimeException("参数不能为null");        }        try {           return  MAPPER.readValue(json, target);        } catch (JsonProcessingException e) {            e.printStackTrace();            throw new RuntimeException(e);        }    }}` 

3.5 商品分类的缓存实现

3.5.1 实现步骤

1.定义Redis中的key key必须惟一不能反复. 存 取 key = “ITEM_CAT_PARENTID::70”
2.依据key 去redis中进行查问 有数据 没有数据
3.没有数据 则查询数据库获取记录 之后将数据保留到redis中 不便后续应用.
4.有数据 示意用户不是第一次查问 能够将缓存数据间接返回即可.

3.5.2 编辑ItemCatController

3.5.3 编辑ItemCatService

`@Override    public List<EasyUITree> findItemCatListCache(Long parentId) {        //0.定义公共的返回值对象        List<EasyUITree> treeList = new ArrayList<>();        //1.定义key        String key = "ITEM_CAT_PARENTID::"+parentId;        //2.检索redis服务器,是否含有该key        //记录时间        Long startTime = System.currentTimeMillis();        if(jedis.exists(key)){            //数据存在            String json = jedis.get(key);            Long endTime = System.currentTimeMillis();            //须要将json串转化为对象            treeList = ObjectMapperUtil.toObj(json,treeList.getClass());            System.out.println("从redis中获取数据 耗时:"+(endTime-startTime)+"毫秒");        }else{            //3.数据不存在  查询数据库            treeList = findItemCatList(parentId);            Long endTime = System.currentTimeMillis();            //3.将数据保留到缓存中            String json = ObjectMapperUtil.toJSON(treeList);            jedis.set(key, json);            System.out.println("查询数据库 耗时:"+(endTime-startTime)+"毫秒");        }        return treeList;    }` 

3.5.4 应用Redis的速度差

  1. AOP实现Redis缓存

================

4.1 如何了解AOP

名称: 面向切面编程
作用: 升高零碎中代码的耦合性,并且在不扭转原有代码的条件下对原有的办法进行性能的扩大.
公式: AOP = 切入点表达式 + 告诉办法

4.2 告诉类型

1.前置告诉 指标办法执行之前执行
2.后置告诉 指标办法执行之后执行
3.异样告诉 指标办法执行过程中抛出异样时执行
4.最终告诉 无论什么时候都要执行的告诉
特点: 上述的四大告诉类型 不能干涉指标办法是否执行.个别用来做程序运行状态的记录.监控

5.盘绕告诉 在指标办法执行前后都要执行的告诉办法 该办法能够控制目标办法是否运行.joinPoint.proceed(); 性能作为弱小的.

4.3 切入点表达式

了解: 切入点表达式就是一个程序是否进入告诉的一个判断(IF)
作用: 当程序运行过程中 ,满足了切入点表达式时才会去执行告诉办法,实现业务的扩大.
品种(写法):

  1. bean(bean的名称 bean的ID) 只能拦挡具体的某个bean对象 只能匹配一个对象

lg: bean(“itemServiceImpl”)

  1. within(包名.类名) within(“com.jt.service.*”) 能够匹配多个对象

粗粒度的匹配准则 按类匹配

 3. execution(返回值类型 包名.类名.办法名(参数列表))   最为弱小的用法      lg : execution(* com.jt.service..*.*(..))              返回值类型任意  com.jt.service包下的所有的类的所有的办法都会被拦挡.      4.@annotation(包名.注解名称)  依照注解匹配.