前排说一下,这是一个十分简陋的KV内存数据库,作为笔者实现redis的第一章,大佬可以走了,因为真的很简陋。仅供学习。
心血来潮,看到了开源项目godis,但自己对go又没有很熟悉,一开始去看了godis,一头雾水,索性想到为什么不用java来实现一个redis呢?说干就干
第一步,我们来实现一个简单的运行在单机的内存型的KV数据库,严格来说这不是redis,和redis差了十万八千里。就是将一个字典,通过网络的方式提供了出去。但毕竟第一步,我们就来实现一个简单一点的(十分的简陋)。
我们主要来实现几个部分
- 客户端——负责发起请求
- 服务端——负责接收客户端的请求并处理
- 存储——负责存储具体的KV键值对(这里我们暂定只能存的KV均为String类型)
客户端
客户端负责根据用户输入发起请求,通过网络的方式向服务端发送命令,并接受服务端的返回的结果,我们这里使用最原生的socket来实现。
public class Client {
public static void main(String[] args) {
try {
Socket socket = new Socket("127.0.0.1", 8888);
OutputStream outputStream = socket.getOutputStream();
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream));
new Thread(new Read(socket)).start(); //读取服务端返回结果,单独启动一个线程,防止阻塞
Scanner input = new Scanner(System.in);
while(input.hasNext()){
String command = input.nextLine(); //接受用户输入
bufferedWriter.write(command+"\n");
bufferedWriter.flush();
}
}catch (Exception e){
e.printStackTrace();
}
}
}
/**
* 服务读取服务器的结果,为了防止阻塞,所以新起了线程进行读
*/
class Read implements Runnable{
private Socket socket;
Read(Socket socket){
this.socket = socket;
}
@Override
public void run() {
try {
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String info;
while((info = bufferedReader.readLine())!=null){
System.out.println(info);
}
} catch (IOException e) {
e.printStackTrace();
}
}
服务端
服务端负责接收用户的请求,并对请求进行解析,存储,返回结果,这里假设只有set和get两种结果
public class Server {
public static void main(String[] args) {
try {
ServerSocket serverSocket = new ServerSocket(8888);
while(true) {
Socket socket = serverSocket.accept();
new Thread(new Handler(socket)).start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 负责对请求进行处理
*/
class Handler implements Runnable{
private Socket socket;
Handler(Socket socket){
this.socket = socket;
}
@Override
public void run() {
try {
InputStream inputStream = socket.getInputStream();
OutputStream outputStream = socket.getOutputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream));
String info;
while((info= bufferedReader.readLine())!=null) {
String[] s = info.split(" ");
if (s[0].equals("set") || s[0].equals("SET")) { //识别为set命令就set
KvStore.set(s[1], s[2]);
} else if (s[0].equals("get") || s[0].equals("GET")) { //识别为get命令就get
String s1 = KvStore.get(s[1]);
bufferedWriter.write(s1 + "\n");
bufferedWriter.flush();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
存储
存储这里KV存储,所以就使用了java内置的map进行存储,由于可能有并发的问题,所以使用ConcurrentHashMap来解决。
public class KvStore {
private static final ConcurrentHashMap<String,String> hashMap = new ConcurrentHashMap<>();
public static void set(String k,String v){
hashMap.put(k, v);
}
public static String get(String k){
return hashMap.get(k);
}
}
到这里我们就实现了一个简单的KV数据库,是的,它相当的简陋,没有任何异常处理,只能set和get,没有用到任何高深的技术,没有定义任何协议,甚至没有导入任何的maven依赖。
下面让我们来测试一下,启动客户端,启动服务端:
他顺利的工作了起来。