淘淘商城_day05_课堂笔记
今日大纲
- 学习Redis
- 使用Redis完成项目中缓存需求
- 实现商品详情页功能
缓存的需求
大广告位数据无需每次查询后台系统的接口,可以在前台系统添加缓存,提高访问首页的速度。
商品类目的数据也可以缓存起来。
实现:
使用Redis实现缓存。
目前缓存的主流技术:
- Redis
- Memcached
二者谁的性能更高?
- 单纯从缓存命中的角度来说,是Memcached要高,Redis和Memcache的差距不大
- 但是,Redis提供的功能更加的强大
二者的区别是什么?
- Memcache是多线程
- Redis是单线程
Redis
NoSQL

主流的NoSQL产品

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



历史与发展

Redis的特性

Redis版本说明

下载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
Redis的安装
安装文件


安装方式一
双机打开redis-server.exe即可:

测试:

安装方式二(安装到系统服务)
先删除原有的系统服务:

安装服务:

32位操作系统安装
只能通过双击打开redis-server.exe启动,不能安装到系统服务。
注意事项

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

限制Redis的最大内存:


Redis-cli使用
redis-cli的使用之发送命令

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

Redis的多数据库

FLUSHALL -- 清空所有数据库的所有数据
FLUSHDB -- 清空当前所在数据库的数据
配置数据库数量

Redis的基本命令
KEYS

EXISTS

DEL

TYPE

HELP
HELP 空格 tab键

Redis的字符串数据类型
字符串类型

GET、SET

INCR

INCRBY

DECR、DECRBY

APPEND

STRLEN

MSET、MGET

Redis的Hash数据结构
数据结构

基本操作

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

Hash的自增长

只获取字段名或字段值

获取字段数量

Redis之生存时间
设置生存时间

TTL返回值:
大于0的数字:剩余生存时间,单位为秒
-1 : 没有生存时间,永久存储
-2 : 数据已经被删除
清除生存时间

设置单位为毫秒

客户端
支持的语言

Jedis


官网:

Jedis的使用
导入itcast-redis

导入依赖

简单示例

连接池使用

分片式集群

存在的问题:无法动态增加减少服务节点。
分片式集群的使用
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();
}
}
将Jedis集成到项目中
添加缓存前的测试

后台系统中添加缓存
在Service中添加依赖

Spring和Jedis的整合

封装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();
}
}
}
}
优化RedisService
定义接口:

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;
}
});
}
}
实现缓存逻辑
- 先从缓存中命中,命中则返回
- 将结果写入到Redis中
测试

原则
原则:缓存逻辑不能影响原有的业务逻辑执行。
优化之后的缓存实现


商品详情页
进入商品详情页地址
http://www.taotao.com/item/{itemId}.html
商品基本数据显示
Controller

Item对象

Service

后台系统提供接口服务

Item.jsp中使用模型数据

显示商品价格:

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

测试

显示商品描述数据
Controller

Service

后台系统中开放接口服务

Item.jsp中显示数据

效果

显示规格参数数据
Controller

Service

Item.jsp

效果

字符串拼接面试题

商品详情页添加缓存
为什么要添加缓存?
加快显示商品 详情页的速度。
在哪里添加缓存?
前台系统? 还是 后台系统? --- 都加。
每个团队都应该为自己的系统功能负责任,保证其性能。
前台系统添加缓存
导入依赖

导入Spring和Jedis的整合文件

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


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;
}
商品数据同步问题
问题
后台系统中将商品修改,前台系统没有进行数据的同步,导致前端系统不能够实时显示最新的数据。
解决
后台系统中商品修改后向其他系统发送通知,其他系统做出对应的处理即可。
怎么通知?
- 在前台系统中开发一个接口
- 在后台系统中调用该接口
ApiService移动至taotao-common

实现数据同步存在的问题
通知的实现,代码的耦合度太高了。
怎么解决? -- 消息队列。
淘淘商城_day05_课堂笔记的更多相关文章
- 淘淘商城_day11_课堂笔记
今日大纲 发布前的准备 实施发布 一部分是由我来发布 一部分是由你们来发布 讲解分布式部署架构 测试 功能测试 压力测试 项目实战的准备以及分组 分组 抽取功能 讲解所需要开发的功能 项目部署上线流程 ...
- 淘淘商城_day01_课堂笔记
今日大纲 聊聊电商行业 电商行业发展 11.11 2015双11: 2016年: 预测:2017年的双11交易额将达到:1400亿 电商行业技术特点 淘淘商城简介 淘淘商城的前身 电商行业的概念 B2 ...
- 淘淘商城_day04_课堂笔记
今日大纲 实现首页的大广告位功能 实现内容管理系统 首页的大广告 什么是大广告 JS效果: 点击下面的序号选择查询哪个广告 自动切换 点击图片查询具体的页面 以上是由前端团队来开发. 数据结构 说明: ...
- 淘淘商城_day02_课堂笔记
今日大纲 学习Nginx的使用 实现商品的管理 新增商品 查询商品列表 编辑商品 删除商品 上架和下架商品 学习nginx 开发阶段中的环境 开发环境:自己的电脑 测试环境:提供给测试人员使用的环境 ...
- 淘淘商城_day10_课堂笔记
今日大纲 Dubbo入门学习 使用dubbo优化单点登录系统 系统间服务调用方式 浏览器直接访问 浏览器发起请求,通过ajax或jsonp方式请求: Httpclient方式 系统与系统之间通过Htt ...
- 淘淘商城_day09_课堂笔记
今日大纲 实现购物车 基于Mysql实现读写分离 购物车 需求描述 用户可以在登录状态下将商品添加到购物车 用户可以在未登录状态下将商品添加到购物车 用户可以使用购物车一起结算下单 用户可以查询自己的 ...
- 淘淘商城_day08_课堂笔记
今日大纲 问题,如何实现商品数据的同步? 学习MQ(消息队列) 搭建RabbitMQ的环境 学习RabbitMQ的队列 学习Spring-Rabbit 使用RabbitMQ完成商品数据的同步 如何实现 ...
- 淘淘商城_day07_课堂笔记
今日大纲 讲解订单系统 基于订单系统完成下单功能的开发 使用Solr完成商品的搜索功能 订单系统 说明:订单系统只是做讲解,不做开发. 导入taotao-order 表结构 订单表: 订单商品表: 疑 ...
- 淘淘商城_day06_课堂笔记
今日大纲 实现单点登录系统 基于单点登录系统实现,用户的注册和登录 商品数据同步问题 问题 后台系统中将商品修改,前台系统没有进行数据的同步,导致前端系统不能够实时显示最新的数据. 解决 后台系统中商 ...
随机推荐
- MVC源码解析 - 进入CLR
这一篇是转载自汤姆大叔的一篇随笔. IIS 5 的 ASP.net 请求处理过程 IIS5核心特征是:IIS是允许在一个叫InetInfo.exe的进程上的,所以无论是aspx页面还是html页面都是 ...
- PHP多维数组元素操作类
我的框架里面一个多维数组元素操作类,主要用于读取数组中配置数据,可以通过字符串节点的方式:a.b.c 来获取和设置元素,以及多维数组的覆盖,有需求的可以参考下吧! <?php /** * Cre ...
- Winsock - 1 - Winsock API
Winsock Winsock API Winsock是网络编程接口,而不是协议. 网络原理和协议 建立Winsock规范的主要目的是提供一个与协议无关的传送接口. Winsock将网络编程接口与具体 ...
- HashMap和Hashtable的同和不同
一.综述 可以直接根据hashcode值判断两个对象是否相等吗?肯定是不可以的,因为不同的对象可能会生成相同的hashcode值.虽然不能根据hashcode值判断两个对象是否相等,但是可以直接根据h ...
- QGIS
project(GisFreeMap) set(CMAKE_BUILD_TYPE Debug) find_package(Qt4 REQUIRED QtCore QtGui QtXml) includ ...
- [ An Ac a Day ^_^ ] [kuangbin带你飞]专题八 生成树 UVA 10600 ACM Contest and Blackout 最小生成树+次小生成树
题意就是求最小生成树和次小生成树 #include<cstdio> #include<iostream> #include<algorithm> #include& ...
- javaee 规范技术
J2EE的13种核心技术 一.JDBC(Java Database Connectivity) JDBC API为访问不同的数据库提供了一种统一的途径,象ODBC一样,JDBC对开发者屏蔽了一些细节问 ...
- asp.net MVC漏油配置总结
URL构造 命名参数规范+匿名对象 routes.MapRoute(name: "Default",url: "{controller}/{action}/{id}&qu ...
- iOS ARC与MRC混编的一些解决方法
1. ARC & MRC 混合开发 在项目开发中,遇到使用MRC开发的第三方库怎么办? 例如:ASI 1> 尝试使用Xcode的转换工具(失败率比较高) 2> 在编译选项中,为MR ...
- moodle其他代码
, $sectionnum=false, $strictness=IGNORE_MISSING):给课程模块一个id,找出coursemoudle的描述 get_coursemodule_from_i ...