参考了其他博主的博文加上自己实践所写,不足之处尽请谅解,我的另一篇博文会有redis的安装以及对应的资源~
1、什么是NoSql
NoSQL(NoSQL = Not Only SQL ),意即“不仅仅是SQL”,是一种基于内存的数据库,并且提供一定的持久化功能;
NoSQL:非关系型的数据库。随着互联网web2.0网站的兴起,传统的关系数据库在应付web2.0网站,特别是超大规模和高并发的SNS类型的web2.0纯动态网站已经显得力不从心,暴露了很多难以克服的问题,而非关系型的数据库则由于其本身的特点得到了非常迅速的发展。NoSQL数据库的产生就是为了解决大规模数据集合多重数据种类带来的挑战,尤其是大数据应用难题,包括超大规模数据的存储。
- 非关系型的数据库:它的存储方式与我们的传统的数据库(二元关系来进行存储)不同;
2、主流使用的四大类非关系型数据库
2.1 键值(Key-Value)存储数据库(一个键对应一个值)
这一类数据库主要会使用到一个哈希表,这个表中有一个特定的键和一个指针指向特定的数据。Key/value模型对于IT系统来说的优势在于简单、易部署;举例如:Tokyo Cabinet/Tyrant, Redis, Voldemort, Oracle BDB
- 在使用范围:redis—做缓存的时候;
2.2 列存储数据库(一个键对应多个值)
这部分数据库通常是用来应对分布式存储的海量数据。键仍然存在,但是它们的特点是指向了多个列。这些列是由列家族来安排的。如:Cassandra, HBase, Riak.
- 在使用的范围:在大数据处理的时候,储存数据的时候使用列存储;一个键对应多个值;
2.3 文档型数据库
它同第一种键值存储相类似。该类型的数据模型是版本化的文档,半结构化的文档以特定的格式存储,比如JSON。文档型数据库可 以看作是键值数据库的升级版,允许之间嵌套键值。而且文档型数据库比键值数据库的查询效率更高。如:CouchDB, MongoDb. 国内也有文档型数据库SequoiaDB,已经开源;
- 使用范围: 单车(他会生成你的轨迹),共享汽车(轨迹);百度(走路跑,步都会生成轨迹); 他会把你的每秒的坐标通过gps(定位 他是二维左边)上传到对方服务器中;服务器要存储你的坐标值;我们就可以使用文档想的数据库存储;
2.4 图形(Graph)数据库
- 图形结构的数据库同其他行列以及刚性结构的SQL数据库不同,它是使用灵活的图形模型,并且能够扩展到多个服务器上。NoSQL数据库没有标准的查询语言(SQL),因此进行数据库查询需要制定数据模型。许多NoSQL数据库都有REST式的数据接口或者查询API。如:Neo4J, InfoGrid, Infinite Graph。
3、 Redis
3.1 Redis中的数据类型
Redis支持5中数据类型,分别为:
- String:string是redis最基本的类型,是一个key对应一个value的,string的类型是二进制安全的,意思是redis的string可以包含任意数据,比如jpg图片或者序列化的对象; 一个键最大可以存储512MB;
- Hash(哈希): reids中hash是一个键名对集合,是一个string类型的filed和value的映射表,hash特别适合用于存储对象;
- List(列表):redis列表是简单的字符串列表,按照插入顺序你可以添加一个元素到列表的头部(左边)或者尾部(右边);
- Set(集合):string类型的无序集合, 集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是 O(1)。
- Zset: Zset(sorted set)是string类型的有序集合,同set一样,不允许重复的成员,不同的是每个元素都会关联一个double类型的分数,redis正是通过分数来为集合元素进行从小到大排序的; zset的成员是唯一的,但分数(score)却可以重复。
3.2 Redis 在 Java Web 中的主要应用:
- 存储 缓存 用的数据;
- 需要高速读/写的场合使用它快速读/写
缓存:在日常对数据库的访问中,读操作的次数远超写操作,所以需要读的可能性是比写的可能大得多的。当我们使用SQL语句去数据库进行读写操作时,数据库就会去磁盘把对应的数据索引取回来,这是一个相对较慢的过程。
-
如果我们把数据放在 Redis 中,也就是直接放在内存之中,让服务端直接去读取内存中的数据,那么这样速度明显就会快上不少,并且会极大减小数据库的压力,但是使用内存进行数据存储开销也是比较大的,限于成本的原因,一般我们只是使用 Redis 存储一些常用和主要的数据,比如用户登录的信息等。
-
在日常使用中,读操作的可能性是远大于写操作的,所以使用 Redis 来处理日常中需要经常读取的数据,速度提升是显而易见的,同时也降低了对数据库的依赖,使得数据库的压力大大减少。
高速读/写的场合
- 在如今的互联网中,越来越多的存在高并发的情况,比如天猫双11、抢红包、抢演唱会门票等,这些场合都是在某一个瞬间或者是某一个短暂的时刻有成千上万的请求到达服务器,如果单纯的使用数据库来进行处理,就算不崩,也会很慢的,轻则造成用户体验极差用户量流失,重则数据库瘫痪,服务宕机,而这样的场合都是不允许的!
- 当一个请求到达服务器时,只是把业务数据在 Redis 上进行读写,而没有对数据库进行任何的操作,这样就能大大提高读写的速度,从而满足高速响应的需求;
3.3 在Java中对redis的基本操作
3.3.1 在spring中使用redis
-
使用maven创建spring,然后导入redis的相关依赖
<!--spring中redis依赖--> <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-redis</artifactId> <version>1.7.2.RELEASE</version> </dependency> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.9.1</version> </dependency>
-
然后创建spring-core.xml配置文件,在配置文件中对实现redis的相关功能进行配置
-
首先配置工具类jedis的连接池JedisPoolConfig
<!--首先配置JedisPoolConfig对象 配置连接池--> <bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig"> <!--最大空闲数--> <property name="maxIdle" value="30"/> <!--最大连接数--> <property name="maxTotal" value="8"/> <!--最大等待时间--> <property name="maxWaitMillis" value="1000"/> </bean>
-
其次使用工厂模式,为连接池配置工厂模型
<!--为连接池配置工厂模型--> <bean id="connectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"> <!--Redis服务地址--> <property name="hostName" value="localhost"/> <!--端口号--> <property name="port" value="6379"/> <!--如果有密码则需要配置密码--> <!--<property name="password" value="password"/>--> <!--连接池配置--> <property name="poolConfig" ref="poolConfig"/> </bean>
-
然后需要配置将java对象转换为redis可存储数据的序列转换对象
<!--配置序列转换 可将java对象转为可在redis中存储的数据--> <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate"> <property name="connectionFactory" ref="connectionFactory"></property> </bean>
3、至此spring的配置文件完成,然后若需要存储对象,则对象类需要实现Serializable
import lombok.AllArgsConstructor; import lombok.Data; //使用了lombok插件 import java.io.Serializable; @Data @AllArgsConstructor public class Student implements Serializable { private String name; private int age; }
- 创建读取配置文件的工具类
public class AcUtils { //创建一个静态方法来返回ApplicationContext的实现对象 public static ApplicationContext getApplicationContext(String path){ //使用ApplicationContext接口来读取对应的bean配置文件 ApplicationContext ac=new ClassPathXmlApplicationContext(path); //返回接口实现对象 return ac; } }
-
测试类如下:
import com.heihei.entity.Student; import com.heihei.utils.AcUtils; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.data.redis.core.RedisTemplate; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; public class RedisTest { @Test public void redisTest(){ ApplicationContext ac = AcUtils.getApplicationContext("spring-core.xml"); //获取可以将java对象转换为redis键值的对象 RedisTemplate redisTemplate = (RedisTemplate) ac.getBean("redisTemplate"); /*Student student=new Student("zz",21); redisTemplate.opsForValue().set("student02",student);*/ /*Student student01 =(Student) redisTemplate.opsForValue().get("student01"); System.out.println(student01);*/ Student student02=new Student("青锋",32); Student student01=new Student("zz",21); //向redis中添加set类型的数据 redisTemplate.opsForSet().add("stu",student02,student01); Set<Student> stu =(Set) redisTemplate.opsForSet().members("stu"); //遍历所得到的set集合 for (Student s:stu ) { System.out.println(s); } } //测试存储list @Test public void listTest(){ ApplicationContext ac = AcUtils.getApplicationContext("spring-core.xml"); //获取可以将java对象转换为redis键值的对象 RedisTemplate redisTemplate = (RedisTemplate) ac.getBean("redisTemplate"); /*redisTemplate.opsForList().leftPush("mylist","xx"); redisTemplate.opsForList().leftPush("mylist","ff"); redisTemplate.opsForList().leftPush("mylist","zz");*/ redisTemplate.opsForList().rightPush("mylist","刘十六"); redisTemplate.opsForList().rightPush("mylist","米裕"); redisTemplate.opsForList().rightPush("mylist","裴钱"); List<String> mylist = redisTemplate.opsForList().range("mylist", 0, 7); for (String s:mylist ) { //System.out.println("leftpushi添加数据的查询结果为:"+s); System.out.println("righypush添加数据的查询结果为:"+s); } } //测试存储hash @Test public void hashTest(){ ApplicationContext ac = AcUtils.getApplicationContext("spring-core.xml"); //获取可以将java对象转换为redis键值的对象 RedisTemplate redisTemplate = (RedisTemplate) ac.getBean("redisTemplate"); Map<String,String> map=new HashMap<String, String>(); map.put("key1","value1"); map.put("key2","value2"); map.put("key3","value3"); redisTemplate.opsForHash().putAll("mykey",map); //获取指定键中存储的所有值 Map mykey = redisTemplate.opsForHash().entries("mykey"); //获取指定键对应的map集合中指定的值 Object o = redisTemplate.opsForHash().get("mykey", "key2"); //获取指定键对应的集合中的所有的键 Set mykey1 = redisTemplate.opsForHash().keys("mykey"); System.out.println("指定键中的所有值"+mykey); System.out.println("指定键对应的map集合中的指定值:"+o); System.out.println("获取指定键对应的集合中的所有的键:"+mykey1); } }
-
3.3.2 在SpringBoot中使用Redis
1、(我用的是IDEA)首先创建项目:
2、SpringBoot中所添加的依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
3、在Spring项目中我们需要手动配置jedis连接池等,而在SpringBoot项目中却不需要我们自己配置,因为SpringBoot的自动配置会帮我们自动配置好所需要配置的信息:
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(RedisOperations.class)
@EnableConfigurationProperties(RedisProperties.class)
@Import({ LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class })
public class RedisAutoConfiguration {
//自动配置的redisTemplate
@Bean
@ConditionalOnMissingBean(name = "redisTemplate")
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory)
throws UnknownHostException {
RedisTemplate<Object, Object> template = new RedisTemplate<>();
template.setConnectionFactory(redisConnectionFactory);
return template;
}
//自动配置的StringRedisTemplate
@Bean
@ConditionalOnMissingBean
public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory)
throws UnknownHostException {
StringRedisTemplate template = new StringRedisTemplate();
template.setConnectionFactory(redisConnectionFactory);
return template;
}
}
我们只需要在使用的时候直接创建对象使用即可;
4、也可以自己配置一些信息,如jedis连接池的相关信息:
spring:
redis:
database: 0 #redis数据库索引默认为0
host: localhost
port: 6379
password:
jedis:
pool:
max-active: 8 #连接池最大连接数
max-wait: -1 #连接池阻塞最大等待时间,负值表示没有限制
max-idle: 8 #连接池最大空闲连接数
min-idle: 0 #最小空闲连接数
5、在SpringBoot所提供的测试类中进行测试(实体类的创建与Spring中相同),包含5中数据的基本操作,对应的操作我都写有注解
import com.example.springbootredis.entity.Teacher;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.ListOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.SetOperations;
import java.util.*;
@SpringBootTest
class SpringbootRedisApplicationTests {
/*其实在启动spring IoC时,容器自动装载了一个AutowiredAnnotationBeanPostProcessor后置处理器,
当容器扫描到@Autowied、@Resource或@Inject时,就会在IoC容器自动查找需要的bean,并装配给该对象的属性
在使用@Autowired时,首先在容器中查询对应类型的bean */
@Autowired
//因为springboot已经帮我们自动配置了类RedisTemplate,所以可以直接注入使用
private RedisTemplate redisTemplate;
@Test
//测试对string类型数据的操作
void stringTest() {
redisTemplate.opsForValue().set("string01","言念君子,温如其玉");
//一个字符型只能存储一个数据,再次存储会覆盖掉前面设定的值
//redisTemplate.opsForValue().set("string01",",温如其玉");
//redisTemplate.delete("string01"); 删除指定数据
String string01 = (String)redisTemplate.opsForValue().get("string01");
System.out.println(string01);
}
//测试对set类型数据的操作
@Test
void setTest(){
SetOperations set = redisTemplate.opsForSet();
set.add("set01","多多","程程","嘿嘿");
set.add("set01","菲菲");
set.add("set01","菲菲");
//移除指定键对应的数据
// redisTemplate.delete("set01");
//获取指定键对应的所有值
Set set01 = set.members("set01");
//使用迭代器进行遍历输出
Iterator iterator = set01.iterator();
while (iterator.hasNext()){
System.out.println("set中存储的数据为:"+iterator.next());
}
}
//测试对list型数据的操作
@Test
public void listTest(){
ListOperations listOperations = redisTemplate.opsForList();
/* //rightpush 从右边依次添加
listOperations.rightPush("list001","一号");
listOperations.rightPush("list001","二号");
listOperations.rightPush("list001","三号");
listOperations.rightPush("list001","四号");
//leftpush 从左边依次添加*/
listOperations.rightPush("list001","零号");
//删除所有的零号元素
//listOperations.remove("list001",0,"零号");
//删除先进入的零号元素
listOperations.remove("list001",1,"零号");
//从redis数据库中获取所有数据并输出
List list001 = listOperations.range("list001", 0, -1);
//查询前三个元素
//List list001 = listOperations.range("list001", 0, 2);
System.out.println(list001);
}
//测试对hash型数据的操作
@Test
public void hashTest(){
HashOperations hashOperations = redisTemplate.opsForHash();
//可以存储map集合以及对象
Map<String, Teacher> map=new HashMap<>();
/*map.put("一号",new Teacher("张娜",45,"女"));
map.put("二号",new Teacher("张丽",42,"女"));
map.put("三号",new Teacher("张丽娜",43,"女"));
hashOperations.putAll("map01",map);*/
//根据指定键删除指定值
hashOperations.delete("map01","一号");
//获取所有存储的值
Map map01 = hashOperations.entries("map01");
System.out.println(map01);
}
}
一些示例:
String类型的数据读写:
List类型的数据读写:
来源:CSDN
作者:做一个好的程序猿
链接:https://blog.csdn.net/qq_46083013/article/details/104696243