什么是NoSQL
NoSQL,泛指非关系型的数据库,NoSQL即Not-Only SQL,它可以作为关系型数据库的良好补充。随着互联网web2.0网站的兴起,非关系型的数据库现在成了一个极其热门的新领域,非关系数据库产品的发展非常迅速。而传统的关系数据库在应付web2.0网站,特别是超大规模和高并发的SNS类型的web2.0纯动态网站已经显得力不从心,暴露了很多难以克服的问题,例如:
1、 对数据库高并发读写的需求
web2.0网站要根据用户个性化信息来实时生成动态页面和提供动态信息,所以基本上无法使用动态页面静态化技术,因此数据库并发负载非常高,往往要达到每秒上万次读写请求。关系数据库应付上万次SQL查询还勉强顶得住,但是应付上万次SQL写数据请求,硬盘IO就已经无法承受了。
2、对海量数据的高效率存储和访问的需求
类似Facebook,twitter,Friendfeed这样的SNS网站,每天用户产生海量的用户动态,以Friendfeed为例,一个月就达到了2.5亿条用户动态,对于关系数据库来说,在一张2.5亿条记录的表里面进行SQL查询,效率是极其低下乃至不可忍受的。再例如大型web网站的用户登录系统,例如腾讯,盛大,动辄数以亿计的帐号,关系数据库也很难应付。
3、对数据库的高可扩展性和高可用性的需求
在基于web的架构当中,数据库是最难进行横向扩展的,当一个应用系统的用户量和访问量与日俱增的时候,你的数据库却没有办法像web server和app server那样简单的通过添加更多的硬件和服务节点来扩展性能和负载能力。对于很多需要提供24小时不间断服务的网站来说,对数据库系统进行升级和扩展是非常痛苦的事情,往往需要停机维护和数据迁移,为什么数据库不能通过不断的添加服务器节点来实现扩展呢?
NoSQL数据库的产生就是为了解决大规模数据集合多重数据种类带来的挑战,尤其是大数据应用难题。
什么是redis
Redis是用C语言开发的一个开源的高性能键值对(key-value)数据库。它通过提供多种键值数据类型来适应不同场景下的存储需求,目前为止Redis支持的键值数据类型如下:
字符串类型
散列类型
列表类型
集合类型
有序集合类型。
redis的应用场景
缓存(数据查询、短连接、新闻内容、商品内容等等)。
分布式集群架构中的session分离。
聊天室的在线好友列表。
任务队列。(秒杀、抢购、12306等等)
应用排行榜。
网站访问统计。
数据过期处理(可以精确到毫秒)
redis安装:
实际使用的一般都是linux版,这里只是随便玩玩,所以我只安装了windows版的。到官网https://redis.io/下载解压后目录如下:
打开其中服务端redis-server.exe
打开客户端redis-cli.exe,并运行几个简单的命令:
在java中访问redis
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import redis.clients.jedis.Jedis;
import org.junit.Before;
import org.junit.Test;
public class RedisDemo {
private Jedis jedis;
@Before
public void init(){
jedis = new Jedis("127.0.0.1");
}
/**
* Redis存储初级的字符串 CRUD
*/
@Test
public void testBasicString() {
// -----添加数据----------
jedis.set("name", "minxr");// 向key-->name中放入了value-->minxr
System.out.println(jedis.get("name"));// 执行结果:minxr
// -----修改数据-----------
// 1、在原来基础上修改 ,append到已经有的value之后
jedis.append("name", "jarorwar");
System.out.println(jedis.get("name"));// 执行结果:minxrjarorwar
// 2、直接覆盖原来的数据
jedis.set("name", "tony");
System.out.println(jedis.get("name"));// 执行结果:tony
// 删除key对应的记录
jedis.del("name");
System.out.println(jedis.get("name"));// 执行结果:null
//mset相当于 jedis.set("name","minxr"); jedis.set("jarorwar","tony");
jedis.mset("name", "minxr", "jarorwar", "tony");
System.out.println(jedis.mget("name", "jarorwar"));
}
/**
* jedis操作Set
*/
@Test
public void testSet() {
// 添加
jedis.sadd("sname", "minxr");
jedis.sadd("sname", "jarorwar");
jedis.sadd("sname", "tony");
jedis.sadd("sanme", "noname");
// 移除noname
jedis.srem("sname", "noname");
System.out.println(jedis.smembers("sname"));// 获取所有加入的value
System.out.println(jedis.sismember("sname", "minxr"));// 判断 minxr
// 是否是sname集合的元素
System.out.println(jedis.srandmember("sname"));
System.out.println(jedis.scard("sname"));// 返回集合的元素个数
}
/**
* jedis操作Map
*/
@Test
public void testMap() {
Map<String, String> user = new HashMap<String, String>();
user.put("name", "minxr");
user.put("pwd", "password");
jedis.hmset("user", user);
// 取出user中的name,执行结果:[minxr]-->注意结果是一个泛型的List
// 第一个参数是存入redis中map对象的key,后面跟的是放入map中的对象的key,后面的key可以跟多个,是可变参数
List<String> rsmap = jedis.hmget("user", "name");
System.out.println(rsmap);
// 删除map中的某个键值
// jedis.hdel("user","pwd");
System.out.println(jedis.hmget("user", "pwd")); // 因为删除了,所以返回的是null
System.out.println(jedis.hlen("user")); // 返回key为user的键中存放的值的个数1
System.out.println(jedis.exists("user"));// 是否存在key为user的记录 返回true
System.out.println(jedis.hkeys("user"));// 返回map对象中的所有key [pwd, name]
System.out.println(jedis.hvals("user"));// 返回map对象中的所有value [minxr,
// password]
Iterator<String> iter = jedis.hkeys("user").iterator();
while (iter.hasNext()) {
String key = iter.next();
System.out.println(key + ":" + jedis.hmget("user", key));
}
}
/**
* jedis操作List
*/
@Test
public void testList() {
// 开始前,先移除所有的内容
jedis.del("java framework");
System.out.println(jedis.lrange("java framework", 0, -1));
// 先向key java framework中存放三条数据
jedis.lpush("java framework", "spring");
jedis.lpush("java framework", "struts");
jedis.lpush("java framework", "hibernate");
// 再取出所有数据jedis.lrange是按范围取出,
// 第一个是key,第二个是起始位置,第三个是结束位置,jedis.llen获取长度 -1表示取得所有
System.out.println(jedis.lrange("java framework", 0, -1));
}
@Test
public void test() throws InterruptedException {
// keys中传入的可以用通配符
System.out.println(jedis.keys("*")); // 返回当前库中所有的key
System.out.println(jedis.keys("*name"));// 返回的sname [sname, name]
System.out.println(jedis.del("sanmdde"));// 删除key为sanmdde的对象 删除成功返回1
// 删除失败(或者不存在)返回 0
System.out.println(jedis.ttl("sname"));// 返回给定key的有效时间,如果是-1则表示永远有效
jedis.setex("timekey", 10, "min");// 通过此方法,可以指定key的存活(有效时间) 时间为秒
Thread.sleep(5000);// 睡眠5秒后,剩余时间将为<=5
System.out.println(jedis.ttl("timekey")); // 输出结果为5
jedis.setex("timekey", 1, "min"); // 设为1后,下面再看剩余时间就是1了
System.out.println(jedis.ttl("timekey")); // 输出结果为1
System.out.println(jedis.exists("key"));// 检查key是否存在
// System.out.println(jedis.rename("timekey","time"));
System.out.println(jedis.get("timekey"));// 因为移除,返回为null
System.out.println(jedis.get("time")); // 因为将timekey 重命名为time 所以可以取得值
// min
// jedis 排序
// 注意,此处的rpush和lpush是List的操作。是一个双向链表(但从表现来看的)
jedis.del("a");// 先清除数据,再加入数据进行测试
jedis.rpush("a", "1");
jedis.lpush("a", "6");
jedis.lpush("a", "3");
jedis.lpush("a", "9");
System.out.println(jedis.lrange("a", 0, -1));// [9, 3, 6, 1]
System.out.println(jedis.sort("a")); // [1, 3, 6, 9] //输入排序后结果
System.out.println(jedis.lrange("a", 0, -1));
System.out.println(jedis.blpop(0, "a"));
}
}