本文简单介绍了在使用jedis操作redis这个nosql数据库过程中,总结的一些问题,例如使用jedis实现形如关系型数据库的数据关联关系处理。
分三个层面:
1:单表数据处理,新增一行数据到数据库中,如果存在主键id是自增情况的条件下,如何新增数据集合到数据库行数据;
2:一对多关联关系,本文举例形如---学生&&成绩; 一个学生包含多个学科的成绩,某一个学科的的成绩属于某个学生;
3:多对多关联关系,本文举例例如---文章&&标签; 一篇文章可以添加多个标签,某一个标签可以被包含于多个文章中;
整体代码链接已经上传git,可以在git上查看:
http://git.oschina.net/alexgaoyh/MutiModule-parent/blob/master/MutiModule-service/src/test/java/com/alexgaoyh/MutiModule/service/unJunit/redis/test2/TestCase.java
1:单表数据处理
/** * [向Redis list压入ID而不是实际的数据] 在上面的例子里 ,我们将“对象”(此例中是简单消息)直接压入Redis list,但通常不应这么做, 由于对象可能被多次引用:例如在一个list中维护其时间顺序,在一个集合中保存它的类别,只要有必要,它还会出现在其他list中,等等。 让我们回到reddit.com的例子,将用户提交的链接(新闻)添加到list中,有更可靠的方法如下所示: $ redis-cli incr next.news.id (integer) 1 $ redis-cli set news:1:title "Redis is simple" OK $ redis-cli set news:1:url "http://code.google.com/p/redis" OK $ redis-cli lpush submitted.news 1 OK 我们自增一个key,很容易得到一个独一无二的自增ID,然后通过此ID创建对象–为对象的每个字段设置一个key。最后将新对象的ID压入submitted.news list。 这只是牛刀小试。在命令参考文档中可以读到所有和list有关的命令。你可以删除元素,旋转list,根据索引获取和设置元素,当然也可以用LLEN得到list的长度。 * * 形如关系型数据库的单表一行数据(主键id为自增) * 自定义一个自增的id , jedis.incr(key),这个key可以形如mysql这种关系型数据库的自增主键id * 形如关系型数据库的一行数据,自增主键id:jedis.incr(key) 他对应的数据内容:jedis.get("ad:adinfo:" + adInfoId + ":title") jedis.get("ad:adinfo:" + adInfoId + ":url") * 这样,在查询这张‘表’结构下的所有数据时,可以匹配查询即可 */ public static void testListStrUsage() { String title = "alexgaoyh"; String url = "http://git.oschina.net/alexgaoyh"; Jedis jedis = RedisUtil.getJedis(IP, PORT); long adInfoId = jedis.incr("ad:adinfo:next.id"); jedis.set("ad:adinfo:" + adInfoId + ":title", title); jedis.set("ad:adinfo:" + adInfoId + ":url", url); jedis.lpush("ad:adinfo", String.valueOf(adInfoId)); String resultTitle = jedis.get("ad:adinfo:" + adInfoId + ":title"); String resultUrl = jedis.get("ad:adinfo:" + adInfoId + ":url"); List<String> ids = jedis.lrange("ad:adinfo", 0, -1); System.out.println(resultTitle); System.out.println(resultUrl); System.out.println(ids); /** * dbsize返回的是所有key的数目,包括已经过期的, 而redis-cli keys "*"查询得到的是有效的key数目 */ System.out.println(jedis.dbSize()); //清空所有的key jedis.flushAll(); }
2:一对多关联关系
/** * sort list * LIST结合hash的排序 * 根据指定的SortingParams排序方式,将符合条件的数据格式进行返回 * 关联关系处理, * 可以理解为studentlist代表学生的整体数据集合 * hset方法,可以将某个学生user:id下的某个域(学科)的成绩(value)进行数据保存 * 根据匹配条件,将相对应的成绩进行输出 */ public static void testSort2() { Jedis jedis = RedisUtil.getJedis(IP, PORT); jedis.del("user:66", "user:55", "user:33", "user:22", "user:11", "userlist"); jedis.lpush("studentlist", "33"); jedis.lpush("studentlist", "22"); jedis.lpush("studentlist", "55"); jedis.lpush("studentlist", "11"); //将哈希表 key 中的域 field 的值设为 value 。 如果 key 不存在,一个新的哈希表被创建并进行 HSET 操作。 如果域 field 已经存在于哈希表中,旧值将被覆盖。 jedis.hset("user:66", "math", "66"); jedis.hset("user:55", "math", "55"); jedis.hset("user:33", "math", "33"); jedis.hset("user:22", "math", "22"); jedis.hset("user:11", "math", "11");//学生user:编号,在field域(某个学科-数学/英语)上的成绩(value) jedis.hset("user:11", "english", "110"); jedis.hset("user:22", "english", "220"); jedis.hset("user:33", "english", "330"); jedis.hset("user:55", "english", "550"); jedis.hset("user:66", "english", "660"); SortingParams sortingParameters = new SortingParams(); // 符号 "->" 用于分割哈希表的键名(key name)和索引域(hash field),格式为 "key->field" 。 sortingParameters.desc(); sortingParameters.get("user:*->math"); sortingParameters.get("user:*->english"); List<String> result = jedis.sort("studentlist", sortingParameters); for (String item : result) { System.out.println("item...." + item); } /** * 对应的redis客户端命令是:sort ml get user*->name sort ml get user:*->name get * user:*->add */ }
/** * sort set * SET结合String的排序 * REL关系相关处理操作 好友列表 好友信息 好友成绩数据信息添加即相应的数据输出 * 输出好友id,好友的详细信息,好友的对应成绩 */ public static void testSort3() { Jedis jedis = RedisUtil. getJedis( IP, PORT); jedis.del( "tom:friend:list" , "score:uid:123" , "score:uid:456" , "score:uid:789" , "score:uid:101" , "uid:123" , "uid:456" , "uid:789" , "uid:101" ); jedis.sadd( "tom:friend:list" , "123" ); // tom的好友列表 jedis.sadd( "tom:friend:list" , "456" ); jedis.sadd( "tom:friend:list" , "789" ); jedis.sadd( "tom:friend:list" , "101" ); jedis.set( "score:uid:123" , "1000" ); // 好友对应的成绩 jedis.set( "score:uid:456" , "6000" ); jedis.set( "score:uid:789" , "100" ); jedis.set( "score:uid:101" , "5999" ); jedis.set( "uid:123" , "{'uid':123,'name':'lucy'}" ); // 好友的详细信息 jedis.set( "uid:456" , "{'uid':456,'name':'jack'}" ); jedis.set( "uid:789" , "{'uid':789,'name':'jay'}" ); jedis.set( "uid:101" , "{'uid':101,'name':'jolin'}" ); SortingParams sortingParameters = new SortingParams(); sortingParameters.desc(); // sortingParameters.limit(0, 2); // 注意GET操作是有序的,GET user_name_* GET user_password_* // 和 GET user_password_* GET user_name_*返回的结果位置不同 sortingParameters.get( "#" );// GET 还有一个特殊的规则—— "GET #" // ,用于获取被排序对象(tom:friend:list)(我们这里的例子是 user_id )的当前元素。 sortingParameters.get( "uid:*" ); sortingParameters.get( "score:uid:*" ); sortingParameters.by( "score:uid:*" ); // 对应的 redis 命令是./redis -cli sort tom:friend:list by score:uid:* get # get // uid :* get score:uid:* List<String> result = jedis.sort( "tom:friend:list" , sortingParameters); for (String item : result) { System. out .println("item..." + item); } }
GET 还有一个特殊的规则—— "GET #" 用于获取被排序对象(tom:friend:list)(我们这里的例子是 user_id )的当前元素。
3:多对多关联关系
/** * 下面是一个简单的方案:对每个想加标签的对象,用一个标签ID集合与之关联,并且对每个已有的标签,一组对象ID与之关联。 例如假设我们的新闻ID * 1000被加了三个标签tag 1,2,5和77,就可以设置下面两个集合: * $ redis-cli sadd news:1000:tags 1 * (integer) 1 * $ redis-cli sadd news:1000:tags 2 * (integer) 1 * $ redis-cli sadd news:1000:tags 5 * (integer) 1 * $ redis-cli sadd news:1000:tags 77 * (integer) 1 * $ redis-cli sadd tag:1:objects 1000 * (integer) 1 * $ redis-cli sadd tag:2:objects 1000 * (integer) 1 * $ redis-cli sadd tag:5:objects 1000 * (integer) 1 * $ redis-cli sadd tag:77:objects 1000 * (integer) 1 * 要获取一个对象的所有标签,如此简单: * $ redis-cli smembers news:1000:tags * 1.5 2.1 3.77 4.2 * 而有些看上去并不简单的操作仍然能使用相应的Redis命令轻松实现。 * 例如我们也许想获得一份同时拥有标签1, 2,10和27的对象列表。这可以用SINTER命令来做,他可以在不同集合之间取出交集。 * 因此为达目的我们只需: $ redis-cli sinter tag:1:objects tag:2:objects tag:10:objects tag:27:objects ... no result * in our dataset composed of just one object ... * 在命令参考文档中可以找到和集合相关的其他命令,令人感兴趣的一抓一大把。一定要留意SORT命令,Redis集合和list都是可排序的。 * * 关系型数据库双向关联操作 一个文章对应多个标签,一个标签可以被多个文章关联 * 多对多的数据库表结构 */ public static void testSetUsage() { Jedis jedis = RedisUtil.getJedis(IP, PORT); //某个文章包含的标签 jedis.sadd("zhongsou:news:1000:tags", "1"); jedis.sadd("zhongsou:news:1000:tags", "2"); jedis.sadd("zhongsou:news:1000:tags", "5"); jedis.sadd("zhongsou:news:1000:tags", "77"); jedis.sadd("zhongsou:news:2000:tags", "1"); jedis.sadd("zhongsou:news:2000:tags", "2"); jedis.sadd("zhongsou:news:2000:tags", "5"); jedis.sadd("zhongsou:news:2000:tags", "77"); jedis.sadd("zhongsou:news:3000:tags", "2"); jedis.sadd("zhongsou:news:4000:tags", "77"); jedis.sadd("zhongsou:news:5000:tags", "1"); jedis.sadd("zhongsou:news:6000:tags", "5"); //某个标签包含的对应的文章id jedis.sadd("zhongsou:tag:1:objects", 1000 + ""); jedis.sadd("zhongsou:tag:2:objects", 1000 + ""); jedis.sadd("zhongsou:tag:5:objects", 1000 + ""); jedis.sadd("zhongsou:tag:77:objects", 1000 + ""); jedis.sadd("zhongsou:tag:1:objects", 2000 + ""); jedis.sadd("zhongsou:tag:2:objects", 2000 + ""); jedis.sadd("zhongsou:tag:5:objects", 2000 + ""); jedis.sadd("zhongsou:tag:77:objects", 2000 + ""); //返回一个集合的全部成员,该集合是所有给定集合的交集 //这四个标签全部都被包含的文章id集合 Set<String> sets = jedis.sinter("zhongsou:tag:1:objects", "zhongsou:tag:2:objects", "zhongsou:tag:5:objects", "zhongsou:tag:77:objects"); System.out.println(sets); jedis.flushAll(); }