概念:redis是一款高性能的NOSQL系列的非关系性数据库
什么是NOSQL
NoSQL(NoSQL = Not Only SQL),意即“不仅仅是SQL”,是一项全新的数据库理念,泛指非关系型的数据库。
随着互联网web2.0网站的兴起,传统的关系数据库在应付web2.0网站,特别是超大规模和高并发的SNS类型的web2.0纯动态网站已经显得力不从心,暴露了很多难以克服的问题,而非关系型的数据库则由于其本身的特点得到了非常迅速的发展。NoSQL数据库的产生就是为了解决大规模数据集合多重数据种类带来的挑战,尤其是大数据应用难题。
NOSQL和关系型数据库比较
优点:
缺点:
维护的工具和资料有限,因为nosql是属于新的技术,不能和关系型数据库10几年的技术同日而语。
不提供对sql的支持,如果不支持sql这样的工业标准,将产生一定用户的学习和使用成本。
不提供关系型数据库对事务的处理。
非关系型数据库的优势:
关系型数据库的优势:
总结
关系型数据库与NoSQL数据库并非对立而是互补的关系,即通常情况下使用关系型数据库,在适合使用NoSQL的时候使用NoSQL数据库,让NoSQL数据库对关系型数据库的不足进行弥补。一般会将数据存储在关系型数据库中,在nosql数据库中备份存储关系型数据库的数据
主流的NOSQL产品
? 键值(Key-Value)存储数据库
相关产品: Tokyo Cabinet/Tyrant、Redis、Voldemort、Berkeley DB
典型应用: 内容缓存,主要用于处理大量数据的高访问负载。
数据模型: 一系列键值对
优势: 快速查询
劣势: 存储的数据缺少结构化
? 列存储数据库
相关产品:Cassandra, HBase, Riak
典型应用:分布式的文件系统
数据模型:以列簇式存储,将同一列数据存在一起
优势:查找速度快,可扩展性强,更容易进行分布式扩展
劣势:功能相对局限
? 文档型数据库
相关产品:CouchDB、MongoDB
典型应用:Web应用(与Key-Value类似,Value是结构化的)
数据模型: 一系列键值对
优势:数据结构要求不严格
劣势: 查询性能不高,而且缺乏统一的查询语法
? 图形(Graph)数据库
相关数据库:Neo4J、InfoGrid、Infinite Graph
典型应用:社交网络
数据模型:图结构
优势:利用图结构相关算法。
劣势:需要对整个图做计算才能得出结果,不容易做分布式的集群方案。
什么是Redis
Redis是用C语言开发的一个开源的高性能键值对(key-value)数据库,官方提供测试数据,50个并发执行100000个请求,读的速度是110000次/s,写的速度是81000次/s ,且Redis通过提供多种键值数据类型来适应不同场景下的存储需求,目前为止Redis支持的键值数据类型如下:
redis的应用场景
官网:https://redis.io
中文网:http://www.redis.net.cn/
解压直接可以使用:
redis.windows.conf
:配置文件redis-cli.exe
:redis的客户端redis-server.exe
:redis服务器端redis的数据结构:
redis存储的是:key,value格式的数据,其中key都是字符串,value有5种不同的数据结构
String
hash:map格式
list:linkedlist格式
set
sortedset
字符串类型 String
存储:set key value
set username zhangsan
获取:get key
返回键对应的值
get username
删除:del key
del username
哈希类型hash
存储:hset key field value
hset myhash username lisi
获取:
hget key field
:获取指定的field对象的值
hget myhash username
返回值:lisi
hgetall key
:获取所有的field和value
hgetall myhash
返回值:
username
lisi
password
123
删除:hdel key field
hdel myhash username
列表类型list:简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)
lpush key value
:从左边存入列表rpush key value
:从右边存入列表lrange key start end
:返回获取lpop key
:从列表的最左边移除一个元素,并将元素返回rpop key
:从列表的最右边移除一个元素,并将元素返回集合类型 set :不允许重复元素
sadd key value
smembers key
:获取set集合中所有的元素srem key value
:删除set集合中的某个元素有序集合类型:sortedset
:不允许重复元素,且元素有顺序
zadd key score value
score:就是一个分数可以是任意值zrange key start end
zrange key 0 -1
zrange key 0 -1 withscores
zrem key value
keys *
:查询所有的键type key
:获取键对应的value的类型del key
:删除指定的key valueredis是一个内存数据库,当redis服务器重启,获取电脑重启,数据会丢失,我们可以将redis内存中的数据持久化保存到硬盘文件中。
redis持久化机制:RDB、AOF
RDB:默认方式,不需要进行配置,默认就是使用这种机制
编辑redis.windwos.conf
文件
save 900 1
:每15分钟后有一个键发生改变就持久化一次
save 300 10
:每5分钟后有十个键发生改变就持久化一次
save 60 10000
:每1分钟有一万个键发生改变就持久化一次
通过cmd命令行的方式重启redis服务器,并制定配置文件名称
D:\redis\windows-64\redis-2.8.9>redis-server.exe redis.windows.conf
AOF:日志记录的方式,可以记录每一条命令的操作。可以每一次命令操作后,持久化数据
编辑redis.windwos.conf
文件
appendonly on(关闭aof) --> appendonly yes(开启aof)
appendfsync always
:每次操作都进行持久化
appendfsync everyesc
:每隔一秒进行一次持久化
appendfsync no
:不进行持久化
Jedis:一款Java操作redis数据库的工具
使用步骤:
@Test
public void test1(){
//创建连接
Jedis jedis = new Jedis("localhost",6379);
//操作redis
jedis.set("password","123");
//关闭连接
jedis.close();
}
字符串类型 String
get、set
@Test
public void test1(){
//创建连接
Jedis jedis = new Jedis();//如果使用空参构造,默认值"localhost",6379端口
//存储
jedis.set("password","123");
//获取
String password = jedis.get("password");
System.out.println(password);
//可以使用setex()方法存储可以指定过期时间的 key value
jedis.setex("activecode",20,"hehe");//将activecode:hehe键值对存入redis,并且20秒后自动删除该键值对
//关闭连接
jedis.close();
}
哈希类型 hash:map格式
hset、hget、hgetAll
//Jedis操作hash类型数据
@Test
public void test2(){
//创建连接
Jedis jedis = new Jedis();//如果使用空参构造,默认值"localhost",6379端口
//存储
jedis.hset("user","name","zhangsan");
jedis.hset("user","age","18");
jedis.hset("user","sex","nan");
//获取
String name = jedis.hget("user", "name");
System.out.println(name);
//获取所有的键值对
Map<String, String> map = jedis.hgetAll("user");
//遍历集合获取所有的键值对
Set<String> keys = map.keySet();
//根据key找值
for (String key : keys) {
String value = map.get(key);
System.out.println(key + ":" +value);
}
//关闭连接
jedis.close();
}
列表类型 list:linkedlist格式。支持重复元素
lpush/rpush、lpop/rpop、lrange start end :范围获取
//Jedis操作list类型数据
@Test
public void test3(){
//创建连接
Jedis jedis = new Jedis();//如果使用空参构造,默认值"localhost",6379端口
//存储
jedis.lpush("mylist","a","b","c");//从左边存
jedis.rpush("mylist","a","b","c");//从右边存
//获取列表的数据
List<String> mylist = jedis.lrange("mylist", 0, -1);
System.out.println(mylist);
//删除列表中的数据(弹出)
String mylist1 = jedis.lpop("mylist");
System.out.println(mylist1);
String mylist2 = jedis.rpop("mylist");
System.out.println(mylist2);
//获取列表的数据
List<String> mylist3 = jedis.lrange("mylist", 0, -1);
System.out.println(mylist3);
//关闭连接
jedis.close();
}
集合类型 set:不允许重复元素
sadd、smembers:获取所有元素
//Jedis操作set类型数据
@Test
public void test4(){
//创建连接
Jedis jedis = new Jedis();//如果使用空参构造,默认值"localhost",6379端口
//存储
jedis.sadd("person","son","man","min");
//获取所有的值
Set<String> person = jedis.smembers("person");
System.out.println(person);
//关闭连接
jedis.close();
}
有序集合类型 sortedset:不允许重复元素,且元素有顺序
zadd/zrange:获取数据
//Jedis操作sortedset类型数据
@Test
public void test5(){
//创建连接
Jedis jedis = new Jedis();//如果使用空参构造,默认值"localhost",6379端口
//存储
jedis.zadd("son",3,"亚瑟");
jedis.zadd("son",20,"后裔");
jedis.zadd("son",55,"孙悟空");
//获取数据
Set<String> son = jedis.zrange("son", 0, -1);
System.out.println(son);
//关闭连接
jedis.close();
}
Jedis连接池:JedisPool
getResource()
方法获取Jedis连接 //jedis连接池
@Test
public void test6(){
//可以通过对象对Jedis连接池对象进行配置
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
//配置连接池的最大连接数
jedisPoolConfig.setMaxTotal(50);
//配置连接池的最大空余连接
jedisPoolConfig.setMaxIdle(10);
//创建Jedis链接池对象
JedisPool jedisPool = new JedisPool(jedisPoolConfig,"localhost");
//通过链接池方法获取连接对象
Jedis jedis = jedisPool.getResource();
//存储数据
jedis.set("hello","hhhh");
//归还资源
jedis.close();
}
package com.example.utils;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
public class JedisUtils {
//定义一个jedisPool成员变量
private static JedisPool jedisPool;
//定义一个静态代码块实现配置文件的加载
static {
InputStream is = JedisUtils.class.getClassLoader().getResourceAsStream("jedis.properties");
//创建peoperties集合对象加载文件
Properties properties = new Properties();
try {
properties.load(is);
} catch (IOException e) {
e.printStackTrace();
}
//创建配置连接池对象
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
String maxIdle = (String) properties.get("maxIdle");
System.out.println(maxIdle);
String maxTotal = (String) properties.get("maxTotal");
System.out.println(maxTotal);
jedisPoolConfig.setMaxIdle(Integer.parseInt(maxIdle));
jedisPoolConfig.setMaxTotal(Integer.parseInt(maxTotal));
jedisPool = new JedisPool(jedisPoolConfig,properties.getProperty("host"));
}
//获取jedis对象
public static Jedis getJedis(){
return jedisPool.getResource();
}
}
案例需求:
注意:使用redis缓存一些不经常发生变化的数据。
package cn.itcast.web.servlet;
import cn.itcast.service.ProvinceService;
import cn.itcast.service.impl.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 {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
/* //1.调用service查询
ProvinceService service = new ProvinceServiceImpl();
List<Province> list = service.findAll();
//2.序列化list为json
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(list);*/
//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);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
}
package cn.itcast.service.impl;
import cn.itcast.dao.ProvinceDao;
import cn.itcast.dao.impl.ProvinceDaoImpl;
import cn.itcast.domain.Province;
import cn.itcast.jedis.util.JedisPoolUtils;
import cn.itcast.service.ProvinceService;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import redis.clients.jedis.Jedis;
import java.util.List;
public class ProvinceServiceImpl implements ProvinceService {
//声明dao
private ProvinceDao dao = new ProvinceDaoImpl();
@Override
public List<Province> findAll() {
return dao.findAll();
}
/**
使用redis缓存
*/
@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从数据中查询
List<Province> ps = dao.findAll();
//2.2将list序列化为json
ObjectMapper mapper = new ObjectMapper();
try {
province_json = mapper.writeValueAsString(ps);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
//2.3 将json数据存入redis
jedis.set("province",province_json);
//归还连接
jedis.close();
}else{
System.out.println("redis中有数据,查询缓存...");
}
return province_json;
}
}
package cn.itcast.dao.impl;
import cn.itcast.dao.ProvinceDao;
import cn.itcast.domain.Province;
import cn.itcast.util.JDBCUtils;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import java.util.List;
public class ProvinceDaoImpl implements ProvinceDao {
//1.声明成员变量 jdbctemplement
private JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource());
@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;
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="js/jquery-3.3.1.min.js"></script>
<script>
$(function () {
//发送ajax请求,加载所有省份数据
$.get("provinceServlet",{},function (data) {
//[{"id":1,"name":"北京"},{"id":2,"name":"上海"},{"id":3,"name":"广州"},{"id":4,"name":"陕西"}]
//1.获取select
var province = $("#province");
//2.遍历json数组
$(data).each(function () {
//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>