Redis概述
redis是以【键-值】形式存储数据的非型数据库,相较于关系型数据库性能更高。可以用于缓存、消息中间件等。
Redis 与其他 key - value 缓存产品有以下三个特点:
- Redis支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用。
- Redis不仅仅支持简单的key-value类型的数据,同时还提供list,set,zset,hash等数据结构的存储。
- Redis支持数据的备份,即master-slave模式的数据备份。
Windows安装Redis
下载地址:https://github.com/MSOpenTech/redis/releases。
把下载好的Redis-x64-xxx.zip压缩包解压到C:\develop文件夹下,内容如下。
接下来,把redis的安装目录配置到系统环境变量(参考Java环境变量配置),方便在控制台打开。
启动redis服务 :打开cmd窗口 ,运行如下命令。
redis-server
打开redis客户端: 打开另一个cmd窗口,输入命令
redis-cli
Linux安装Redis
下载地址:http://redis.io/download,下载最新稳定版本。
$ wget http://download.redis.io/releases/redis-2.8.17.tar.gz
$ tar xzf redis-2.8.17.tar.gz
$ cd redis-2.8.17
$ make
make完后 redis-2.8.17目录下会出现编译后的redis服务程序redis-server,还有用于测试的客户端程序redis-cli,两个程序位于安装目录 src 目录下:
启动redis服务.
$ cd src
$ ./redis-server
打开redis客户端
$ cd src
$ ./redis-cli
redis>
Ubuntu 安装Redis
在 Ubuntu 系统安装 Redis 可以使用以下命令:
$sudo apt-get update
$sudo apt-get install redis-server
启动 Redis
$ redis-server
打开客户端
$ redis-cli
Redis命令
Redis数据是以 key value 形式存储,key全都是字符串,value有5种不同的数据结构可供选择。
String 字符串
List 列表(类似于LinkedList)
Set 集合(类似于HashSet)
SortedSet 有序集合(类似于LinkedHashSet)
字符串(String)
1.存储:set key value
2.获取:get key
3.删除:del key
哈希(Hash)
1.存储:hset name key value
2.获取:
hget key field 获取指定field对应的value
hgetall key 获取所有filed对应的value
3.删除:hdel key field
列表(List)
可以添加一个元素到列表的头部或者尾部
1.存储
lpush key element //从左边添加元素:
rpush key element //从右边添加元素
2.获取
lindex mylist index //通过索引获取元素
lrange key start end //获取指定范围的元素
3.修改
lset key index value //通过索引修改列表中的元素
4.删除
lpop key //删除最左边的元素
rpop key //删除最右边的元素
集合(Set)
不能存储重复元素
1.存储: sadd key value
2.获取:smembers key //获取所有元素
3.删除:srem key value //删除集合中某一个元素
有序集合(sorted set)
不允许元素重复,也能保证元素有序。
1.存储:zadd key score value
2.获取: zrange key start end
3.删除: zrem key value
通用命令
keys * :查询所有的键
type key : 获取键对应值的数据类型
del key : 删除指定的key-value
Redis持久化
Redis数据是存储在内存的,当redis服务器重启时,或者电脑重启时,数据就会丢失。Redis提供了持久化机制,可以把redis的数据存储到硬盘中。
RDB持久化
RDB是Redis的默认持久化方式,在Redis根目录下有一个redis.windows.conf配置文件,可以用来配置持久化时机。
找到redis.windows.conf文件,用记事本打开,找到以下配置信息。
# after 900 sec (15 min) if at least 1 key changed
save 900 1
# after 300 sec (5 min) if at least 10 keys changed
save 300 10
# after 60 sec if at least 10000 keys changed
save 60 10000
使用cd命令进入redis根目录,开启redis服务并读取配置文件
redis-server.exe redis.windws.conf
AOF持久化
日志记录的方式,可以记录每一条命令的操作。可以每一次命令,都进行持久化。
1.使用记事本编辑redis.windows.conf文件,找到appendonly把后面的no 改为 yes
appendonly no --> appendonly yes
2.相关配置说明
# appendsync always //每一次操作都进行持久化
appendsync everysec //每一秒进行持久化
# appendsync no //不尽兴持久化
使用cd命令进入redis根目录,开启redis服务并读取配置文件
redis-server.exe redis.windws.conf
Jedis使用
Jedis是一款Java语言操作Redis的工具,类似于Jdbc操作Mysql数据库。
Jedis下载:
Jedis快速入门
//获取连接
Jedis jedis=new Jedis("localhost",6379);
//操作
jedis.set("username","zhangsan");
//关闭资源
jedis.close();
Jedis操作String
//获取连接
Jedis jedis=new Jedis("localhost",6379);
//添加数据
jedis.set("username","zhangsan");
jedis.set("password","123");
jedis.set("gender","男");
jedis.setex("age",5,"30"); //天就age=30,5秒后失效。
//删除数据
jedis.del("username");
//修改数据
jedis.set("password","666");
//获取数据
String password = jedis.get("password");
System.out.println(password);
//关闭资源
jedis.close();
Jedis操作Hash
//获取连接
Jedis jedis = new Jedis("localhost", 6379);
//添加数据
jedis.hset("user","username","zhangsan");
jedis.hset("user","password","123");
jedis.hset("user","gender","women");
//删除数据
jedis.hdel("user","gender");
//修改数据
jedis.hset("user","password","666");
//获取数据
String password = jedis.hget("user","password");
System.out.println(password);
//获取所有数据
Map<String, String> user = jedis.hgetAll("user");
System.out.println(user);
//关闭资源
jedis.close();
Jedis操作Lis
//获取连接
Jedis jedis = new Jedis("localhost", 6379);
jedis.del("mylist");
//添加元素到list
jedis.lpush("mylist","张三","李四","王五");
jedis.lpush("mylist","赵六","周七","刘八");
//删除元素第一个
jedis.lpop("mylist");
//删除最后一个
jedis.rpop("mylist");
//获取指定索引位置的元素
String name = jedis.lindex("mylist", 0);
System.out.println("0索引的元素:"+name);
//获取所有元素
List<String> users = jedis.lrange("mylist", 0, -1);
for (String user : users) {
System.out.println(user);
}
//修改指定索引的元素
String n = jedis.lset("mylist", 2, "网吧");
System.out.println("被修改的元素:"+n);
List<String> mylist = jedis.lrange("mylist", 0, -1);
System.out.println(mylist);
//关闭资源
jedis.close();
Jedis操作Set
//获取连接
Jedis jedis = new Jedis("localhost", 6379);
//添加元素
jedis.sadd("myset","孙悟空");
jedis.sadd("myset","猪八戒");
jedis.sadd("myset","沙和尚");
jedis.sadd("myset","唐三藏");
jedis.sadd("myset","白龙马");
//删除元素
jedis.srem("myset","白龙马");
//获取元素
Set<String> myset = jedis.smembers("myset");
System.out.println(myset);
//关闭资源
jedis.close();
Jedis操作SortedSet
//获取连接
Jedis jedis = new Jedis("localhost", 6379);
//添加元素
jedis.zadd("sortedSet",1,"孙悟空");
jedis.zadd("sortedSet",2,"猪八戒");
jedis.zadd("sortedSet",3,"沙和尚");
jedis.zadd("sortedSet",4,"唐三藏");
jedis.zadd("sortedSet",5,"白龙马");
//删除元素
jedis.zrem("sortedSet","白龙马");
//获取元素
Set<String> myset = jedis.zrange("sortedSet",0,-1);
System.out.println(myset);
//关闭资源
jedis.close();
Jedis连接池
Jedis连接池类似于Jdbc连接池,当需要Jedis连接时从连接池获取连接,使用完毕后再归还给连接池。下面是jedis连接池的相关配置。
jedis配置文件
#redis服务器的IP
redis.ip=127.0.0.1
#redis服务器的Port
redis.port=6379
#最大连接数
redis.pool.maxTotal=10
#最大空闲的连接数
redis.pool.maxIdle=8
#最小空闲连接数
redis.pool.minIdle=2
#当池内没有返回对象时,最大等待时间
redis.pool.maxWaitMillis=3000
JedisPoolUtils
为了获取连接方便,自定义一个Jedis连接池的工具类
package com.jedispool;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import java.io.IOException;
import java.util.Properties;
public class JedisPoolUtils {
static JedisPool jedisPool=null;
static {
Properties properties=new Properties();
try {
properties.load(JedisPoolUtils.class.getClassLoader().getResourceAsStream("jedis.properties"));
} catch (IOException e) {
e.printStackTrace();
}
//获取reids的主机地址
String ip = properties.getProperty("redis.ip");
//获取redis的端口号
String port = properties.getProperty("redis.port");
//获取最大活动数
String maxTotal = properties.getProperty("redis.pool.maxTotal");
String maxIdle = properties.getProperty("redis.pool.maxIdle");
String minIdle = properties.getProperty("redis.pool.minIdle");
String maxWaitMillis = properties.getProperty("redis.pool.maxWaitMillis");
//设置连接池参数
JedisPoolConfig config=new JedisPoolConfig();
config.setMaxTotal(Integer.parseInt(maxTotal));
config.setMaxIdle(Integer.parseInt(maxIdle));
config.setMinIdle(Integer.parseInt(minIdle));
config.setMaxWaitMillis(Integer.parseInt(maxWaitMillis));
jedisPool=new JedisPool(config,ip,Integer.parseInt(port));
}
//获取Jedis连接
public static Jedis getJedis(){
return jedisPool.getResource();
}
}
综合案例
需求: 使用ajax访问服务器查询省份列表
1.先从redis缓存中获取数据
2.存储中有就使用缓存的,缓存没有就从数据库查询
准备数据库
-- 创建数据库
CREATE DATABASE redis;
-- 使用数据库
USE redis;
-- 创建表格
CREATE TABLE province(
id INT PRIMARY KEY AUTO_INCREMENT,
province VARCHAR(20) NOT NULL
);
-- 添加数据
INSERT INTO province(id,province) VALUE(1,"北京");
INSERT INTO province(id,province) VALUE(2,"上海");
INSERT INTO province(id,province) VALUE(3,"深圳");
INSERT INTO province(id,province) VALUE(4,"广州");
INSERT INTO province(id,province) VALUE(5,"武汉");
INSERT INTO province(id,province) VALUE(6,"南京");
INSERT INTO province(id,province) VALUE(7,"长沙");
INSERT INTO province(id,province) VALUE(8,"郑州");
INSERT INTO province(id,province) VALUE(9,"合肥");
搭建环境
把相关jar包,复制到web\WEB-INF\lib目录下
commons-beanutils-1.8.3.jar
commons-logging-1.1.1.jar
commons-pool2-2.3.jar
druid-1.0.9.jar
jackson-annotations-2.2.3.jar
jackson-core-2.2.3.jar
jackson-databind-2.2.3.jar
javax.servlet.jsp.jstl.jar
jedis-2.7.0.jar
jstl-impl.jar
mysql-connector-java-5.1.18-bin.jar
spring-beans-4.2.4.RELEASE.jar
spring-core-4.2.4.RELEASE.jar
spring-jdbc-4.2.4.RELEASE.jar
spring-tx-4.2.4.RELEASE.jar
jedis.properties
在src目录下创建jedis.properties配置文件,用于配置reids的相关参数。
#redis服务器的IP
redis.ip=127.0.0.1
#redis服务器的Port
redis.port=6379
#最大连接数
redis.pool.maxTotal=10
#最大空闲的连接数
redis.pool.maxIdle=8
#最小空闲连接数
redis.pool.minIdle=2
#当池内没有返回对象时,最大等待时间
redis.pool.maxWaitMillis=3000
druid.properties
在src目录下创建druid.properties配置文件,用户配置数据库的相关参数。
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/redis
username=root
password=root
# 初始化连接数量
initialSize=5
# 最大连接数
maxActive=10
# 最大等待时间
maxWait=3000
JdbcUtils.java
创建utils包,把JdbcUtis.java文件复制到utils包下
package com.itheima.utils;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;
/**
* JDBC工具类 使用Durid连接池
*/
public class JdbcUtils {
private static DataSource ds ;
static {
try {
//1.加载配置文件
Properties pro = new Properties();
//使用ClassLoader加载配置文件,获取字节输入流
InputStream is = JdbcUtils.class.getClassLoader().getResourceAsStream("druid.properties");
pro.load(is);
//2.初始化连接池对象
ds = DruidDataSourceFactory.createDataSource(pro);
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 获取连接池对象
*/
public static DataSource getDataSource(){
return ds;
}
/**
* 获取连接Connection对象
*/
public static Connection getConnection() throws SQLException {
return ds.getConnection();
}
}
JedisPoolUtils.java
把JedisPoolUtils.java文件复制到utils包下
package com.itheima.utils;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;
/**
* JDBC工具类 使用Durid连接池
*/
public class JdbcUtils {
private static DataSource ds ;
static {
try {
//1.加载配置文件
Properties pro = new Properties();
//使用ClassLoader加载配置文件,获取字节输入流
InputStream is = JdbcUtils.class.getClassLoader().getResourceAsStream("druid.properties");
pro.load(is);
//2.初始化连接池对象
ds = DruidDataSourceFactory.createDataSource(pro);
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 获取连接池对象
*/
public static DataSource getDataSource(){
return ds;
}
/**
* 获取连接Connection对象
*/
public static Connection getConnection() throws SQLException {
return ds.getConnection();
}
}
数据访问层
在dao包下,创建ProvinceDaoImpl
import java.util.List;
public class ProvinceDaoImpl implements ProvinceDao {
JdbcTemplate jdbcTemplate=new JdbcTemplate(JdbcUtils.getDataSource());
@Override
public List<Province> findAllProvince() {
String sql="select * from province";
List<Province> list = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(Province.class));
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
return list;
}
}
业务逻辑层
package com.itheima.service;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.itheima.dao.ProvinceDao;
import com.itheima.dao.ProvinceDaoImpl;
import com.itheima.domain.Province;
import com.itheima.utils.JedisPoolUtils;
import redis.clients.jedis.Jedis;
import java.util.List;
public class ProvinceServiceImpl implements ProvinceService{
ProvinceDao provinceDao=new ProvinceDaoImpl();
@Override
public List<Province> findAll() {
List<Province> allProvince = provinceDao.findAllProvince();
return allProvince;
}
@Override
public String findAllJson() {
//先从缓存中获取
Jedis jedis = JedisPoolUtils.getJedis();
String province_json = jedis.get("province");
//如果缓存没有,就查询数据库
if(province_json==null||province_json.length()==0){
List<Province> list = findAll();
//把list转换为json
ObjectMapper mapper=new ObjectMapper();
try {
province_json = mapper.writeValueAsString(list);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
//将json数据存入缓存
jedis.set("province",province_json);
}else {
System.out.println("从缓存获取数据");
}
return province_json;
}
}
Web层
package com.itheima.web;
import com.itheima.service.ProvinceService;
import com.itheima.service.ProvinceServiceImpl;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/provinceServlet")
public class ProvinceServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("utf-8");
resp.setContentType("application/json;charset=utf-8");
ProvinceService provinceService=new ProvinceServiceImpl();
String provinceJson = provinceService.findAllJson();
resp.getWriter().write(provinceJson);
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req, resp);
}
}
province.html
在web目录下创建html页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="js/jquery-2.1.0.min.js"></script>
<script>
$(function () {
$.get("provinceServlet",{},function (data) {
$(data).each(function () {
//{"id":3,"province":"深圳"}
$("#b1").append("<option id='"+this.id+"'>"+this.province+"</option>");
});
},"json");
})
</script>
</head>
<body>
<select id="b1">
<option>-请选择省份-</option>
</select>
</body>
</html>