设为首页 收藏本站
查看: 1271|回复: 0

[经验分享] Java版的Redis

[复制链接]

尚未签到

发表于 2015-7-21 07:32:23 | 显示全部楼层 |阅读模式
  


  


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





代码的组织结构如下图:





DSC0000.png







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 = Get(keys);
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();
else
list = serializer.unmarshal(list);
LinkedList listRef = (LinkedList) list;
for (Object value : values)
listRef.addFirst(value);
persistence.put(key, serializer.marshal(list));
}
public void RPush(String key, Object... values) {
Object list = persistence.get(key);
if (list == null)
list = new LinkedList();
else
list = serializer.unmarshal(list);
LinkedList listRef = (LinkedList) list;
for (Object value : values)
listRef.addLast(value);
persistence.put(key, serializer.marshal(list));
}
public Object[] LRange(String key, int start, int end) {
Object list = persistence.get(key);
if (list == null)
return NULL;
LinkedList listRef = (LinkedList) serializer.unmarshal(list);
if (end > listRef.size())
end = listRef.size();
return listRef.subList(start, end).toArray();
}

// =================================================
//Unsorted Set value
// =================================================
public void SAdd(String key, Object... values) {
Object set = persistence.get(key);
if (set == null)
set = new HashSet();
else
set = serializer.unmarshal(set);
HashSet setRef = (HashSet) set;
for (Object value : values)
setRef.add(value);
persistence.put(key, serializer.marshal(set));
}
public Object[] SMembers(String key) {
Object set = persistence.get(key);
if (set == null)
return NULL;
set = serializer.unmarshal(set);
return ((HashSet) set).toArray();
}
public Object[] SInter(String key1, String key2) {
Object set1 = persistence.get(key1);
Object set2 = persistence.get(key2);
if (set1 == null || set2 == null)
return NULL;
HashSet set1Ref = (HashSet) serializer.unmarshal(set1);
HashSet set2Ref = (HashSet) serializer.unmarshal(set2);
set1Ref.retainAll(set2Ref);
return set1Ref.toArray();
}
public Object[] SDiff(String key1, String key2) {
Object set1 = persistence.get(key1);
Object set2 = persistence.get(key2);
if (set1 == null || set2 == null)
return NULL;
HashSet set1Ref = (HashSet) serializer.unmarshal(set1);
HashSet set2Ref = (HashSet) serializer.unmarshal(set2);
set1Ref.removeAll(set2Ref);
return set1Ref.toArray();
}

// =================================================
//Sorted Set value
// =================================================
public void ZAdd(String key, Object... values) {
Object set = persistence.get(key);
if (set == null)
set = new TreeSet();
else
set = serializer.unmarshal(set);
TreeSet setRef = (TreeSet) set;
for (Object value : values)
setRef.add(value);
persistence.put(key, serializer.marshal(set));
}
public Object[] SRange(String key, Object from) {
Object set = persistence.get(key);
if (set == null)
return NULL;
set = serializer.unmarshal(set);
return ((TreeSet) set).tailSet(from).toArray();
}

}
package com.cdai.studio.redis;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.Arrays;
class Serializer {
Object marshal(Object object) {
if (object == null)
return null;
return new BytesWrapper((Serializable) object);
}
Object unmarshal(Object object) {
if (object == null)
return null;
return ((BytesWrapper) object).readObject();
}

}

class BytesWrapper {
private byte[] bytes;
BytesWrapper(T object) {
writeBytes(object);
}
void writeBytes(T object) {
try {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
ObjectOutputStream output = new ObjectOutputStream(buffer);
output.writeObject(object);
output.flush();
bytes = buffer.toByteArray();
output.close();
}
catch (IOException e) {
e.printStackTrace();
throw new IllegalStateException(e);
}
}
Object readObject() {
try {
ObjectInputStream input = new ObjectInputStream(new ByteArrayInputStream(bytes));
Object object = input.readObject();
input.close();
return object;
}
catch (Exception e) {
e.printStackTrace();
throw new IllegalStateException(e);
}
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + Arrays.hashCode(bytes);
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
BytesWrapper other = (BytesWrapper) obj;
if (!Arrays.equals(bytes, other.bytes))
return false;
return true;
}

}package com.cdai.studio.redis;
import java.util.HashMap;
class Persistence {
private HashMap storage =
new HashMap();

void put(String key, Object value) {
storage.put(key, value);
}
Object get(String key) {
return storage.get(key);
}

}




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(&quot;unchecked&quot;)
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 (&quot;Set&quot;.equals(request.get(0))) {
redis.Set((String) request.get(1), request.get(2));
}
else if (&quot;Get&quot;.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(&quot;Set&quot;, key, value));
}
public Object Get(String key) {
return sendRequest(Arrays.asList(&quot;Get&quot;, key));
}
private Object sendRequest(List payload) {
Socket socket = null;
try {
socket = new Socket(&quot;localhost&quot;, 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(&quot;users&quot;, &quot;A&quot;, &quot;B&quot;, &quot;C&quot;);
// User A follows B, C
redis.SAdd(&quot;users:A:following&quot;, &quot;B&quot;, &quot;C&quot;);
redis.SAdd(&quot;users:B:followers&quot;, &quot;A&quot;);
redis.SAdd(&quot;users:C:followers&quot;, &quot;A&quot;);
// User C follows B
redis.SAdd(&quot;users:C:following&quot;, &quot;B&quot;);
redis.SAdd(&quot;users:B:followers&quot;, &quot;C&quot;);

// 2.1 B send tweet
int tid = redis.Incr(&quot;tweets:next_id&quot;);
redis.Set(&quot;tweets:&quot; + tid, &quot;B publish hello&quot;);
redis.LPush(&quot;global:timeline&quot;, tid);
redis.LPush(&quot;users:B:timeline&quot;, tid);
for (Object follower : redis.SMembers(&quot;users:B:followers&quot;))
redis.LPush(&quot;users:&quot; + follower + &quot;:timeline&quot;, tid);
// 2.2 C send tweet
tid = redis.Incr(&quot;tweets:next_id&quot;);
redis.Set(&quot;tweets:&quot; + tid, &quot;C publish world&quot;);
redis.LPush(&quot;global:timeline&quot;, tid);
redis.LPush(&quot;users:C:timeline&quot;, tid);
for (Object follower : redis.SMembers(&quot;users:C:followers&quot;))
redis.LPush(&quot;users:&quot; + follower + &quot;:timeline&quot;, tid);

Object[] tids = redis.LRange(&quot;global:timeline&quot;, 0, 9);
String[] tweetids = new String[tids.length];
for (int i = 0; i < tids.length; i++)
tweetids = &quot;tweets:&quot; + tids;
System.out.println(Arrays.toString(redis.MGet(tweetids)));
}
}




5.需要注意的问题





byte数组的equals和hashcode默认实现比较对象地址的,要借助于Arrays的equals和hashcode方法。





String字符串序列化和反序列化时要注意编码&#26684;式的问题,编码解码时应该使用相同的编码。





HashSet上的操作,removeAll补集,retainAll交集,addAll并集。









6.更加强大的Redis





Redis自己实现了各种数据结构,可以非常方便地增删改查,并且效率很高。这里我们只是用

Java来简单的学习了下Redis基本功能,其实Redis还支持很多其他的高级功能,如消息订阅、

数据过期设置、事务、数据持久化。想要进一步学习的话可以试着用Java实现它们。



  

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-88814-1-1.html 上篇帖子: redis源码笔记 下篇帖子: MySQL to Redis
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表