Redis入门篇(1):涉及到Redis概念、Redis下载安装、命令行操作、Redis数据结构、持久化操作
Redis入门篇(2):了解使用Java客户端操作Redis。Redis连接池、实际应用案例。
五.使用Java客户端操作Redis
介绍Java客户端一款工具 :Jedis。它一款Java操作redis数据库的工具。类似操作MySQL的JDBC工具。
5.1 Jedis使用步骤
使用步骤:
- 下载jedis的jar包,导入工程目录
- 在程序中创建Jedis的实例:
- 获取redis连接
- 使用Jedis的实例操作redis
- 释放资源,关闭连接
jar包:jar包资源.提取码:6379
commons-pool2-2.3.jar:包含Jedis连接池
jedis-2.7.0.jar:Jedis工具
junit-4.10.jar:测试框架
快速入门:
写一个Jedis测试类JedisTest,里面有多个测试方法,测试使用Jedis工具。
/**
* 快速入门:在redis中存储zhangsan字符串数据
*/
@Test
public void test1() {
//1.获取连接
Jedis jedis = new Jedis("localhost", 6379);//参数:主机IP,端口号
//2.数据库操作
jedis.set("username", "zhangsan");
//3.关闭连接
jedis.close();
}
注意:运行程序前,需要先开启本地localhost的redis服务器,如果是连接其它主机的redis服务器,修改成对应主机的IP地址即可。
Jedis方便Java程序操作Redis中的各种数据结构。
5.2 Jedis操作Redis中的数据结构
调用Jedis实例中的各种方法来操作redis中对应的数据结构,方法名基本与redis客户端命令行操作指令一致。
这里就把代码写一遍,直观了解。程序运行的结果在redis客户端获取查看对应的数据进行验证。这里不验证了
1.字符串类型 string
/**
* string 数据结构操作
*/
@Test
public void test2() {
//1.获取连接
Jedis jedis = new Jedis();//如果使用空参构造,默认值就是连接本机的"localhost",6379端口
//2.数据库操作
//存储string
jedis.set("username", "zhangsan");
//获取
String username = jedis.get("username");
System.out.println(username);
//可以使用setex()方法存储可以指定过期实际的 key,value
jedis.setex("activecode", 20, "8888");//将activecode:8888键值对存入redis,并且20秒后自动删除该键值对
//3.关闭连接
jedis.close();
}
2.哈希类型 hash : Map格式
/**
* hash 数据结构操作
*/
@Test
public void test3() {
//1.获取连接
Jedis jedis = new Jedis();//如果使用空参构造,默认值就是连接本机的"localhost",6379端口
//2.数据库操作
//存储hash
jedis.hset("user", "name", "lisi");
jedis.hset("user", "age", "23");
jedis.hset("user", "gender", "male");
//获取hash
String name = jedis.hget("user", "name");
System.out.println(name);
//获取hash的所有map中的数据
Map<String, String> user = jedis.hgetAll("user");
//遍历map
Set<String> set = user.keySet();
for (String key : set) {
//获取value
String value = user.get(key);
System.out.println(key + ":" + value);
}
//可以使用setex()方法存储可以指定过期实际的 key,value
jedis.setex("activecode", 20, "8888");//将activecode:8888键值对存入redis,并且20秒后自动删除该键值对
//3.关闭连接
jedis.close();
}
3.列表类型 list : LinkedList格式。支持重复元素
/**
* list 数据结构操作
*/
@Test
public void test4() {
//1.获取连接
Jedis jedis = new Jedis();
//2.数据库操作
// list 存储
jedis.lpush("myList","a","b","c");//从左边存 cba
jedis.rpush("myList","a","b","c");//从右边存 abc
// list 范围获取
List<String> myList = jedis.lrange("myList", 0, -1);
System.out.println(myList);
// list 弹出
String element1 = jedis.lpop("myList");//c
System.out.println(element1);
String element2 = jedis.rpop("myList");//c
System.out.println(element2);
List<String> myList1 = jedis.lrange("myList", 0, -1);
System.out.println(myList1);
//3.关闭连接
jedis.close();
}
4.集合类型 set : 不允许重复元素
/**
* set 数据结构操作
*/
@Test
public void test5() {
//1.获取连接
Jedis jedis = new Jedis();
//2.数据库操作
// set 存储
jedis.sadd("mySet","java","php","c++");//无序,不允许重复
// set 获取
Set<String> mySet = jedis.smembers("mySet");
System.out.println(mySet);
//3.关闭连接
jedis.close();
}
5.有序集合类型 sortedset:不允许重复元素,且元素有顺序
/**
* sortedset 数据结构操作
*/
@Test
public void test6() {
//1.获取连接
Jedis jedis = new Jedis();
//2.数据库操作
// sortedset 存储
jedis.zadd("mySortedSet",3,"亚瑟");
jedis.zadd("mySortedSet",30,"后裔");
jedis.zadd("mySortedSet",25,"李白");
// sortedset 获取
Set<String> mySortedSet = jedis.zrange("mySortedSet", 0, -1);//有序,不允许重复
System.out.println(mySortedSet);
//3.关闭连接
jedis.close();
}
5.3 Jedis连接池: JedisPool
Jedis连接池,存放Redis连接对象的容器,主要可以复用连接对象,提高性能。数据库连接池的原理可以参考另一篇博文:JDBC(二):数据库连接池(C3P0、Druid)
虽然Redis数据存储在内存中,也会涉及到频繁的IO操作。这里简单说下连接池的好处:
- 节约资源
- 用户访问高效
1.Jedis连接池使用
使用:
- 创建
JedisPool
连接池对象 - 连接池对象调用方法
getResource()
方法获取Jedis连接 - 使用Jedis连接
一般我们会在创建Jedis连接池对象前,会使用配置对象JedisPoolConfig
对连接池进行配置(不配置会使用默认配置)。根据实际需求调整配置,连接池的配置都封装到JedisPoolConfig
了,调用其实例的设置方法即可。
/**
* jedis连接池使用
*/
@Test
public void test7(){
//0.创建一个配置对象
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxTotal(50);//最大活动对象数
config.setMaxIdle(10);//最大能保持idel空闲状态的对象数
//1.创建Jedis连接池对象
//JedisPool jedisPool = new JedisPool();
JedisPool jedisPool = new JedisPool(config,"localhost",6379);
//2.获取连接对象
Jedis jedis = jedisPool.getResource();
//3.使用Jedis对象,进行数据库操作
jedis.set("name","wangwu");
//4.关闭连接,归还到连接池中
jedis.close();
}
来了解下Jedis连接池详细配置的一些属性:
jedis详细配置.properties
#最大活动对象数
redis.pool.maxTotal=1000
#最大能够保持idel状态的对象数
redis.pool.maxIdle=100
#最小能够保持idel状态的对象数
redis.pool.minIdle=50
#当池内没有返回对象时,最大等待时间
redis.pool.maxWaitMillis=10000
#当调用borrow Object方法时,是否进行有效性检查
redis.pool.testOnBorrow=true
#当调用return Object方法时,是否进行有效性检查
redis.pool.testOnReturn=true
#“空闲链接”检测线程,检测的周期,毫秒数。如果为负值,表示不运行“检测线程”。默认为-1.
redis.pool.timeBetweenEvictionRunsMillis=30000
#向调用者输出“链接”对象时,是否检测它的空闲超时;
redis.pool.testWhileIdle=true
# 对于“空闲链接”检测线程而言,每次检测的链接资源的个数。默认为3.
redis.pool.numTestsPerEvictionRun=50
#redis服务器的IP
redis.ip=xxxxxx
#redis服务器的Port
redis1.port=6379
我们只需要配置常用的几个属性就行,需要其它属性的时候再配置。这样在程序里一个一个的配置太麻烦,回想起JDBC的经历,封装成工具类,还世界一片安宁。
2.连接池工具类
连接池常需要配置的属性放在配置文件中,配置时读取文件中的属性:
jedis.properties
host=127.0.0.1
port=6379
maxTotal=50
maxIdle=10
连接池工具类,比较简单的封装,其它可以自由发挥:
JedisPoolutils.java
/**
* JedisPool 工具类
* 1.加载配置文件,配置连接池的参数
* 2.提供获取连接的方法
*/
public class JedisPoolutils {
//声明JedisPool
private static JedisPool jedisPool;
static {
//读取配置文件
InputStream is = JedisPoolutils.class.getClassLoader().getResourceAsStream("jedis.properties");
//创建Properties对象
Properties pro = new Properties();
//关联文件,读取文件
try {
pro.load(is);
} catch (IOException e) {
e.printStackTrace();
}
//获取数据,设置到JedisPoolConfig中
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxTotal(Integer.parseInt(pro.getProperty("maxTotal")));
config.setMaxTotal(Integer.parseInt(pro.getProperty("maxIdle")));
//初始化JedisPool
jedisPool = new JedisPool(config, pro.getProperty("host"), Integer.parseInt(pro.getProperty("port")));
}
/**
* 提供获取连接的方法
* @return
*/
public static Jedis getJedis() {
return jedisPool.getResource();
}
}
再使用一下连接池工具类:
/**
* jedis连接池工具类使用
*/
@Test
public void test8(){
//通过连接池工具类获取
Jedis jedis = JedisPoolutils.getJedis();
//使用Jedis对象
jedis.set("hello","world");
//4.关闭连接,归还到连接池中
jedis.close();
}
简洁直接。最后完成一个Redis的综合练习。
六.Redis案例
1.案例需求
- 1.提供
index.html
页面,页面中有一个**“省份”**下拉列表 - 2.省份数据都在MySQL数据库中
- 3.当页面加载完成后发送
ajax请求
,加载所有省份
一般省份信息是长时间不会发生变化的,如果相同的信息每次都从MySQL数据库中获取出来,从电脑的磁盘中读数据,效率低下,影响系统性能,用户体验较差。像这样的场景,利用缓存的思想来提高系统的性能,我们可以使用redis缓存一些不经常发生变化。
案例效果预览:
需要注意的是:
- 数据库的数据一旦发生改变,则需要更新缓存;
- 像数据库的表执行 “增删改” 的相关操作,需要将redis缓存数据情况,再次存入;
具体操作,在service层对应的增删改方法中,将redis数据删除
。
案例分析:
主要技术点:JQuery+Ajax+Json+Servlet+JdbcTemplate+Druid+MySQL+Redis
2.案例实现
2.1 数据库准备
-- 创建数据库,设置utf-8编码格式
CREATE DATABASE example CHARACTER SET 'utf8' COLLATE 'utf8_general_ci';
USE example; -- 使用数据库
CREATE TABLE province( -- 创建表
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(20) NOT NULL
);
-- 插入数据
INSERT INTO province VALUES(NULL,'北京');
INSERT INTO province VALUES(NULL,'上海');
INSERT INTO province VALUES(NULL,'广州');
INSERT INTO province VALUES(NULL,'陕西');
数据库表:
2.2 创建Web工程,导入jar包
目录结构:
导入相关jar包:
案例jar包资源:jar包资源.提取码:6379
2.3 前端页面
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>redis案例</title>
<!-- 引入Jquery框架 -->
<script type="text/javascript" src="js/jquery-3.3.1.min.js"></script>
<script>
$(function () {
//发送ajax请求,加载所有省份数据
$.get("provinceServlet", {}, function (data) {
//data:[{"id":1,"name":"北京"},{"id":2,"name":"上海"},{"id":3,"name":"广州"},{"id":4,"name":"陕西"}]
//1.获取select标签的对象
var province = $("#province");
//2.遍历json数组
$(data).each(function () {
console.log(data);
//3.创建option标签
var option = "<option name='"+this.id+"'>"+this.name+"</option>";
//4.调用select对象的append方法追加option
province.append(option)
});
})
});
</script>
</head>
<body>
<select id="province">
<option>--请选择省份--</option>
</select>
</body>
</html>
2.3 util层
MySQL
druid.properties
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/example?useSSL=false&characterEncoding=UTF-8
username=root
password=201703457
initialSize=5
maxActive=10
maxWait=3000
JDBCUtils.java
/**
* 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();
}
}
Redis
jedis.properties
host=127.0.0.1
port=6379
maxTotal=50
maxIdle=10
JedisPoolutils.java
/**
* JedisPool 工具类
* 1.加载配置文件,配置连接池的参数
* 2.提供获取连接的方法
*/
public class JedisPoolutils {
//声明JedisPool
private static JedisPool jedisPool;
static {
//读取配置文件
InputStream is = JedisPoolutils.class.getClassLoader().getResourceAsStream("jedis.properties");
//创建Properties对象
Properties pro = new Properties();
//读取文件
try {
pro.load(is);
} catch (IOException e) {
e.printStackTrace();
}
//获取数据,设置到JedisPoolConfig中
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxTotal(Integer.parseInt(pro.getProperty("maxTotal")));
config.setMaxTotal(Integer.parseInt(pro.getProperty("maxIdle")));
//初始化JedisPool
jedisPool = new JedisPool(config, pro.getProperty("host"), Integer.parseInt(pro.getProperty("port")));
}
/**
* 提供获取连接的方法
* @return
*/
public static Jedis getJedis() {
return jedisPool.getResource();
}
}
2.4 domain层
Province.java
public class Province {
private int id; //序号
private String name; //省份名称
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Province{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
2.5 dao层
ProvinceDao.java
/**
* 持久层接口
*/
public interface ProvinceDao {
/**
* 查询所有的方法
* @return
*/
public List<Province> findAll();
}
ProvinceDaoImpl.java
/**
* 持久层接口实现类
*/
public class ProvinceDaoImpl implements ProvinceDao {
//1.声明成员变量 JdbcTemplate
private JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource());
/**
* 查询所有的方法
* @return
*/
@Override
public List<Province> findAll() {
//1.定义sql
String sql = "select * from province ";
//2.执行sql
List<Province> list = template.query(sql, new BeanPropertyRowMapper<Province>(Province.class));
return list;
}
}
2.6 Service层
ProvinceService.java
/**
* 业务成接口
*/
public interface ProvinceService {
/**
* 查询所有的方法
* @return
*/
public List<Province> findAll();
/**
* 查询所有并转换为json
* @return
*/
public String findAllJson();
}
ProvinceServiceImpl.java
/**
* 业务成接口的实现类
*/
public class ProvinceServiceImpl implements ProvinceService {
//声明Dao的引用
private ProvinceDao dao = new ProvinceDaoImpl();
@Override
public List<Province> findAll() {
//调用dao层方法
return dao.findAll();
}
/**
* 使用redis缓存
* @return
*/
@Override
public String findAllJson() {
//1.从redis中查询数据
//1.1 获取redis客户端连接
Jedis jedis = JedisPoolutils.getJedis();
String province_json = jedis.get("province");
//2.判断 province_json 数据是否为Null
if (province_json == null || province_json.length() == 0){
//redis中没有数据
System.out.println("redis中没有数据,查询数据库...");
//2.1 从mysql数据库中查询
List<Province> pro_list = dao.findAll();
//2.2 将list 序列化为json
ObjectMapper mapper = new ObjectMapper();
try {
province_json = mapper.writeValueAsString(pro_list);
//2.3 将json数据存入redis中
jedis.set("province",province_json);
} catch (JsonProcessingException e) {
e.printStackTrace();
}finally {
//归还连接
jedis.close();
}
}else {
System.out.println("redis中有数据,查询缓存...");
}
//返回json格式字符串
return province_json;
}
}
2.7 Web层
ProvinceServlet.java
@WebServlet(name = "ProvinceServlet", urlPatterns = "/provinceServlet")
public class ProvinceServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
this.doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//1.调用service方法查询
ProvinceService service = new ProvinceServiceImpl();
String json = service.findAllJson();
System.out.println(json);
//3.响应结果
response.setContentType("application/json;charset=utf-8");
response.getWriter().write(json);
}
}
3.案例测试
服务器电脑需要启动MySQL服务器和Redis服务器。
启动项目,访问index.html,可以看到:
多刷新几次页面,查看控制台的打印:
第一次访问时,会从数据库中读取数据,并将数据存入缓存。之后再次访问就直接从缓存中拿数据,不会再去查询MySQL数据库了,极大提升了系统性能、响应效率。
查看Redis中的数据:
Redis中也存入了省份数据。案例完成。
以上就是Redis入门篇(2)的全部内容。Redis的强大远不止这些,继续加油。
推荐阅读:
Redis入门篇(1).
Redis入门篇(2).
欢迎点赞评论,指出不足,笔者由衷感谢哦!~