Redis是一个基于Key-value结构的Nosql数据库,它支持各种常见的数据结构以及非常方便的操作,
与其说它是一个数据库,不如说它是一个保存各种数据结构的服务器。今天闲来没事,用
Java集合类
实现了Redis的一些基本功能,算是温习下Java了。
1.Redis入门
Redis的Key键值为字符串,但是Value值支持许多种类型,如String字符串,List链表,Set无序集合,
SortedSet有序集合,甚至是Hash表。
各种数据结构通过不同的存取方法来区分。如Set/Get直接将值存为String,LPush/LPop/LRange将
值存到一个链表中,SAdd/ZAdd则区分了无序和有序集合。
下面我们来看下在Java中使用基本的集合类如何实现这些简单而方便的操作。
2.Java版的Redis
代码的组织结构如下图:
package com.cdai.studio.redis; import java.util.HashSet; import java.util.LinkedList; import java.util.TreeSet; @SuppressWarnings("unchecked") public class RedisDB { private Persistence persistence = new Persistence(); private Serializer serializer = new Serializer(); private static final Object[] NULL = new Object[0]; // ================================================= // String value // ================================================= public void Set(String key, Object value) { persistence.put(key, serializer.marshal(value)); } public Object Get(String key) { return serializer.unmarshal(persistence.get(key)); } public Object[] MGet(String... keys) { Object[] values = new Object[keys.length]; for (int i = 0; i < keys.length; i++) values[i] = Get(keys[i]); return values; } public int Incr(String key) { Object value = Get(key); Integer valueRef = (value == null) ? 1 : (Integer) value; Set(key, valueRef + 1); return valueRef; } // ================================================= // List value // ================================================= public void LPush(String key, Object... values) { Object list = persistence.get(key); if (list == null) list = new LinkedList
3.简单的客户端
package com.cdai.studio.redis; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.net.ServerSocket; import java.net.Socket; import java.util.List; public class RedisServer { private RedisDB redis; public RedisServer(RedisDB redis) { this.redis = redis; } @SuppressWarnings("unchecked") public void start() { ServerSocket serverSocket = null; try { serverSocket = new ServerSocket(1234); while (true) { Socket socket = serverSocket.accept(); ObjectInputStream input = new ObjectInputStream(socket.getInputStream()); List request = (List) input.readObject(); Object response = null; if ("Set".equals(request.get(0))) { redis.Set((String) request.get(1), request.get(2)); } else if ("Get".equals(request.get(0))) { response = redis.Get((String) request.get(1)); } ObjectOutputStream output = new ObjectOutputStream(socket.getOutputStream()); output.writeObject(response); input.close(); output.close(); socket.close(); } } catch (Exception e) { e.printStackTrace(); } finally { if (serverSocket != null) { try { serverSocket.close(); } catch (IOException e) { } } } } } package com.cdai.studio.redis; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import java.net.Socket; import java.util.Arrays; import java.util.List; public class RedisClient { public void Set(String key, Object value) { sendRequest(Arrays.asList("Set", key, value)); } public Object Get(String key) { return sendRequest(Arrays.asList("Get", key)); } private Object sendRequest(List payload) { Socket socket = null; try { socket = new Socket("localhost", 1234); ObjectOutputStream output = new ObjectOutputStream(socket.getOutputStream()); output.writeObject(payload); output.flush(); ObjectInputStream input = new ObjectInputStream(socket.getInputStream()); Object response = input.readObject(); output.close(); input.close(); return response; } catch (Exception e) { e.printStackTrace(); } finally { if (socket != null) { try { socket.close(); } catch (Exception e) { } } } return null; } }
4.实现简单的Twitter
package com.cdai.studio.redis; import java.util.Arrays; public class RedisTest { public static void main(String[] args) { RedisDB redis = new RedisDB(); // 1.Create user follow relationship redis.SAdd("users", "A", "B", "C"); // User A follows B, C redis.SAdd("users:A:following", "B", "C"); redis.SAdd("users:B:followers", "A"); redis.SAdd("users:C:followers", "A"); // User C follows B redis.SAdd("users:C:following", "B"); redis.SAdd("users:B:followers", "C"); // 2.1 B send tweet int tid = redis.Incr("tweets:next_id"); redis.Set("tweets:" + tid, "B publish hello"); redis.LPush("global:timeline", tid); redis.LPush("users:B:timeline", tid); for (Object follower : redis.SMembers("users:B:followers")) redis.LPush("users:" + follower + ":timeline", tid); // 2.2 C send tweet tid = redis.Incr("tweets:next_id"); redis.Set("tweets:" + tid, "C publish world"); redis.LPush("global:timeline", tid); redis.LPush("users:C:timeline", tid); for (Object follower : redis.SMembers("users:C:followers")) redis.LPush("users:" + follower + ":timeline", tid); Object[] tids = redis.LRange("global:timeline", 0, 9); String[] tweetids = new String[tids.length]; for (int i = 0; i < tids.length; i++) tweetids[i] = "tweets:" + tids[i]; System.out.println(Arrays.toString(redis.MGet(tweetids))); } }
5.需要注意的问题
byte数组的equals和hashcode默认实现比较对象地址的,要借助于Arrays的equals和hashcode方法。
String字符串序列化和反序列化时要注意编码格式的问题,编码解码时应该使用相同的编码。
HashSet上的操作,removeAll补集,retainAll交集,addAll并集。
6.更加强大的Redis
Redis自己实现了各种数据结构,可以非常方便地增删改查,并且效率很高。这里我们只是用
Java来简单的学习了下Redis基本功能,其实Redis还支持很多其他的高级功能,
如消息订阅、
数据过期设置、事务、数据持久化。想要进一步学习的话可以试着用Java实现它们。