淘淘商城_day05_课堂笔记

时间:2023-03-10 06:23:50
淘淘商城_day05_课堂笔记
  1. 今日大纲

  1. 学习Redis
  2. 使用Redis完成项目中缓存需求
  3. 实现商品详情页功能
    1. 缓存的需求

大广告位数据无需每次查询后台系统的接口,可以在前台系统添加缓存,提高访问首页的速度。

商品类目的数据也可以缓存起来。

实现:

使用Redis实现缓存。

目前缓存的主流技术:

  1. Redis
  2. Memcached

二者谁的性能更高?

  1. 单纯从缓存命中的角度来说,是Memcached要高,Redis和Memcache的差距不大
  2. 但是,Redis提供的功能更加的强大

二者的区别是什么?

  1. Memcache是多线程
  2. Redis是单线程
    1. Redis

      1. NoSQL

淘淘商城_day05_课堂笔记

  1. 主流的NoSQL产品

淘淘商城_day05_课堂笔记

  1. Redis简介

Redis官网: http://redis.io/

淘淘商城_day05_课堂笔记

淘淘商城_day05_课堂笔记

淘淘商城_day05_课堂笔记

  1. 历史与发展

淘淘商城_day05_课堂笔记

  1. Redis的特性

淘淘商城_day05_课堂笔记

  1. Redis版本说明

淘淘商城_day05_课堂笔记

  1. 下载Redis

Linux版本 2.8.11 :

http://download.redis.io/releases/redis-2.8.11.tar.gz

Windows(64位)版本 2.8.9 :

https://github.com/MSOpenTech/redis/blob/2.8/bin/release/redis-2.8.9.zip?raw=true

Windows(32位)版本 2.6 :

https://github.com/MSOpenTech/redis/blob/2.6/bin/release/redisbin.zip?raw=true

  1. Redis的安装

    1. 安装文件

淘淘商城_day05_课堂笔记

淘淘商城_day05_课堂笔记

  1. 安装方式一

双机打开redis-server.exe即可:

淘淘商城_day05_课堂笔记

测试:

淘淘商城_day05_课堂笔记

  1. 安装方式二(安装到系统服务)

先删除原有的系统服务:

淘淘商城_day05_课堂笔记

安装服务:

淘淘商城_day05_课堂笔记

  1. 32位操作系统安装

只能通过双击打开redis-server.exe启动,不能安装到系统服务。

  1. 注意事项

淘淘商城_day05_课堂笔记

由于文件系统非NTFS,导致Redis启动失败:

淘淘商城_day05_课堂笔记

限制Redis的最大内存:

淘淘商城_day05_课堂笔记

淘淘商城_day05_课堂笔记

  1. Redis-cli使用

    1. redis-cli的使用之发送命令

淘淘商城_day05_课堂笔记

  1. redis-cli的使用之命令返回值

淘淘商城_day05_课堂笔记

  1. Redis的多数据库

淘淘商城_day05_课堂笔记

FLUSHALL -- 清空所有数据库的所有数据

FLUSHDB -- 清空当前所在数据库的数据

  1. 配置数据库数量

淘淘商城_day05_课堂笔记

  1. Redis的基本命令

    1. KEYS

淘淘商城_day05_课堂笔记

  1. EXISTS

淘淘商城_day05_课堂笔记

  1. DEL

淘淘商城_day05_课堂笔记

  1. TYPE

淘淘商城_day05_课堂笔记

  1. HELP

HELP 空格 tab键

淘淘商城_day05_课堂笔记

  1. Redis的字符串数据类型

    1. 字符串类型

淘淘商城_day05_课堂笔记

  1. GET、SET

淘淘商城_day05_课堂笔记

  1. INCR

淘淘商城_day05_课堂笔记

  1. INCRBY

淘淘商城_day05_课堂笔记

  1. DECR、DECRBY

淘淘商城_day05_课堂笔记

  1. APPEND

淘淘商城_day05_课堂笔记

  1. STRLEN

淘淘商城_day05_课堂笔记

  1. MSET、MGET

淘淘商城_day05_课堂笔记

  1. Redis的Hash数据结构

    1. 数据结构

淘淘商城_day05_课堂笔记

  1. 基本操作

淘淘商城_day05_课堂笔记

  1. 判断是否存在和选择性插入

淘淘商城_day05_课堂笔记

  1. Hash的自增长

淘淘商城_day05_课堂笔记

  1. 只获取字段名或字段值

淘淘商城_day05_课堂笔记

  1. 获取字段数量

淘淘商城_day05_课堂笔记

  1. Redis之生存时间

    1. 设置生存时间

淘淘商城_day05_课堂笔记

TTL返回值:

大于0的数字:剩余生存时间,单位为秒

-1 : 没有生存时间,永久存储

-2 : 数据已经被删除

  1. 清除生存时间

淘淘商城_day05_课堂笔记

  1. 设置单位为毫秒

淘淘商城_day05_课堂笔记

  1. 客户端

    1. 支持的语言

淘淘商城_day05_课堂笔记

  1. Jedis

淘淘商城_day05_课堂笔记

淘淘商城_day05_课堂笔记

官网:

淘淘商城_day05_课堂笔记

  1. Jedis的使用

    1. 导入itcast-redis

淘淘商城_day05_课堂笔记

  1. 导入依赖

淘淘商城_day05_课堂笔记

  1. 简单示例

淘淘商城_day05_课堂笔记

  1. 连接池使用

淘淘商城_day05_课堂笔记

  1. 分片式集群

淘淘商城_day05_课堂笔记

存在的问题:无法动态增加减少服务节点。

  1. 分片式集群的使用

public
class ShardedJedisPoolDemo {

public
static
void main(String[] args) {

// 构建连接池配置信息

JedisPoolConfig poolConfig = new JedisPoolConfig();

// 设置最大连接数

poolConfig.setMaxTotal(50);

// 定义集群信息

List<JedisShardInfo> shards = new ArrayList<JedisShardInfo>();

shards.add(new JedisShardInfo("127.0.0.1", 6379));

shards.add(new JedisShardInfo("192.168.29.112", 6379));

// 定义集群连接池

ShardedJedisPool shardedJedisPool = new ShardedJedisPool(poolConfig, shards);

ShardedJedis shardedJedis = null;

try {

// 从连接池中获取到jedis分片对象

shardedJedis = shardedJedisPool.getResource();

// for (int i = 0; i < 100; i++) {

// shardedJedis.set("key_" + i, "value_" + i);

// }

System.out.println(shardedJedis.get("key_49"));

System.out.println(shardedJedis.get("key_7"));

} catch (Exception e) {

e.printStackTrace();

} finally {

if (null != shardedJedis) {

// 关闭,检测连接是否有效,有效则放回到连接池中,无效则重置状态

shardedJedis.close();

}

}

// 关闭连接池

shardedJedisPool.close();

}

}

  1. 将Jedis集成到项目中

    1. 添加缓存前的测试

淘淘商城_day05_课堂笔记

  1. 后台系统中添加缓存

    1. 在Service中添加依赖

淘淘商城_day05_课堂笔记

  1. Spring和Jedis的整合

淘淘商城_day05_课堂笔记

  1. 封装RedisService

package com.taotao.manage.service;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Service;

import redis.clients.jedis.ShardedJedis;

import redis.clients.jedis.ShardedJedisPool;

@Service

public
class RedisService {

@Autowired

private ShardedJedisPool shardedJedisPool;

/**

* 执行set操作

*

* @param key

* @param value

* @return

*/

public String set(String key, String value) {

ShardedJedis shardedJedis = null;

try {

// 从连接池中获取到jedis分片对象

shardedJedis = shardedJedisPool.getResource();

return
shardedJedis.set(key, value);

} finally {

if (null != shardedJedis) {

// 关闭,检测连接是否有效,有效则放回到连接池中,无效则重置状态

shardedJedis.close();

}

}

}

/**

* 执行get操作

*

* @param key

* @return

*/

public String get(String key) {

ShardedJedis shardedJedis = null;

try {

// 从连接池中获取到jedis分片对象

shardedJedis = shardedJedisPool.getResource();

return
shardedJedis.get(key);

} finally {

if (null != shardedJedis) {

// 关闭,检测连接是否有效,有效则放回到连接池中,无效则重置状态

shardedJedis.close();

}

}

}

}

  1. 优化RedisService

定义接口:

淘淘商城_day05_课堂笔记

RedisService的实现:

package com.taotao.manage.service;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Service;

import redis.clients.jedis.ShardedJedis;

import redis.clients.jedis.ShardedJedisPool;

@Service

public
class RedisService {

@Autowired

private ShardedJedisPool shardedJedisPool;

private <T> T execute(Function<T, ShardedJedis> fun) {

ShardedJedis shardedJedis = null;

try {

// 从连接池中获取到jedis分片对象

shardedJedis = shardedJedisPool.getResource();

return
fun.callback(shardedJedis);

} finally {

if (null != shardedJedis) {

// 关闭,检测连接是否有效,有效则放回到连接池中,无效则重置状态

shardedJedis.close();

}

}

}

/**

* 执行set操作

*

* @param key

* @param value

* @return

*/

public String set(final String key, final String value) {

return
this.execute(new Function<String, ShardedJedis>() {

@Override

public String callback(ShardedJedis e) {

return
e.set(key, value);

}

});

}

/**

* 执行get操作

*

* @param key

* @return

*/

public String get(final String key) {

return
this.execute(new Function<String, ShardedJedis>() {

@Override

public String callback(ShardedJedis e) {

return
e.get(key);

}

});

}

/**

* 执行删除操作

*

* @param key

* @return

*/

public Long del(final String key) {

return
this.execute(new Function<Long, ShardedJedis>() {

@Override

public Long callback(ShardedJedis e) {

return
e.del(key);

}

});

}

/**

* 设置生存时间,单位为:秒

*

* @param key

* @param seconds

* @return

*/

public Long expire(final String key, final Integer seconds) {

return
this.execute(new Function<Long, ShardedJedis>() {

@Override

public Long callback(ShardedJedis e) {

return
e.expire(key, seconds);

}

});

}

/**

* 执行set操作并且设置生存时间,单位为:秒

*

* @param key

* @param value

* @return

*/

public String set(final String key, final String value, final Integer seconds) {

return
this.execute(new Function<String, ShardedJedis>() {

@Override

public String callback(ShardedJedis e) {

String str = e.set(key, value);

e.expire(key, seconds);

return
str;

}

});

}

}

  1. 实现缓存逻辑

  1. 先从缓存中命中,命中则返回
    淘淘商城_day05_课堂笔记
  2. 将结果写入到Redis中
    淘淘商城_day05_课堂笔记
  1. 测试

淘淘商城_day05_课堂笔记

  1. 原则

原则:缓存逻辑不能影响原有的业务逻辑执行。

  1. 优化之后的缓存实现

淘淘商城_day05_课堂笔记

淘淘商城_day05_课堂笔记

  1. 商品详情页

    1. 进入商品详情页地址

http://www.taotao.com/item/{itemId}.html

  1. 商品基本数据显示

    1. Controller

淘淘商城_day05_课堂笔记

  1. Item对象

淘淘商城_day05_课堂笔记

  1. Service

淘淘商城_day05_课堂笔记

  1. 后台系统提供接口服务

淘淘商城_day05_课堂笔记

  1. Item.jsp中使用模型数据

淘淘商城_day05_课堂笔记

显示商品价格:

淘淘商城_day05_课堂笔记

<fmt:formatNumber groupingUsed="false" maxFractionDigits="2" minFractionDigits="2" value="${item.price / 100 }"/>

淘淘商城_day05_课堂笔记

  1. 测试

淘淘商城_day05_课堂笔记

  1. 显示商品描述数据

    1. Controller

淘淘商城_day05_课堂笔记

  1. Service

淘淘商城_day05_课堂笔记

  1. 后台系统中开放接口服务

淘淘商城_day05_课堂笔记

  1. Item.jsp中显示数据

淘淘商城_day05_课堂笔记

  1. 效果

淘淘商城_day05_课堂笔记

  1. 显示规格参数数据

    1. Controller

淘淘商城_day05_课堂笔记

  1. Service

淘淘商城_day05_课堂笔记

  1. Item.jsp

淘淘商城_day05_课堂笔记

  1. 效果

淘淘商城_day05_课堂笔记

  1. 字符串拼接面试题

淘淘商城_day05_课堂笔记

  1. 商品详情页添加缓存

    1. 为什么要添加缓存?

加快显示商品 详情页的速度。

  1. 在哪里添加缓存?

前台系统? 还是 后台系统? --- 都加。

每个团队都应该为自己的系统功能负责任,保证其性能。

  1. 前台系统添加缓存

    1. 导入依赖

淘淘商城_day05_课堂笔记

  1. 导入Spring和Jedis的整合文件

淘淘商城_day05_课堂笔记

  1. 将RedisService和Function接口移动至taotao-common

淘淘商城_day05_课堂笔记

淘淘商城_day05_课堂笔记

  1. Service中添加缓存逻辑

private
static
final
String
REDIS_KEY = "TAOTAO_WEB_ITEM_DETAIL_";

private
static
final Integer REDIS_TIME = 60 * 60 * 24;

public Item queryItemById(Long itemId) {

// 从缓存中命中

String key = REDIS_KEY + itemId;

try {

String cacheData = this.redisService.get(key);

if (StringUtils.isNotEmpty(cacheData)) {

return
MAPPER.readValue(cacheData, Item.class);

}

} catch (Exception e1) {

e1.printStackTrace();

}

try {

String url = TAOTAO_MANAGE_URL + "/rest/item/" + itemId;

String jsonData = this.apiService.doGet(url);

if (StringUtils.isEmpty(jsonData)) {

return
null;

}

try {

// 将数据写入到缓存中

this.redisService.set(key, jsonData, REDIS_TIME);

} catch (Exception e) {

e.printStackTrace();

}

return
MAPPER.readValue(jsonData, Item.class);

} catch (Exception e) {

e.printStackTrace();

}

return
null;

}

  1. 商品数据同步问题

    1. 问题

后台系统中将商品修改,前台系统没有进行数据的同步,导致前端系统不能够实时显示最新的数据。

  1. 解决

后台系统中商品修改后向其他系统发送通知,其他系统做出对应的处理即可。

  1. 怎么通知?

  1. 在前台系统中开发一个接口
    淘淘商城_day05_课堂笔记
  2. 在后台系统中调用该接口
    淘淘商城_day05_课堂笔记
  1. ApiService移动至taotao-common

淘淘商城_day05_课堂笔记

  1. 实现数据同步存在的问题

通知的实现,代码的耦合度太高了。

怎么解决? -- 消息队列。