前排说一下,这是一个十分简陋的KV内存数据库,作为笔者实现redis的第一章,大佬可以走了,因为真的很简陋。仅供学习。
心血来潮,看到了开源项目godis,但自己对go又没有很熟悉,一开始去看了godis,一头雾水,索性想到为什么不用java来实现一个redis呢?说干就干
第一步,我们来实现一个简单的运行在单机的内存型的KV数据库,严格来说这不是redis,和redis差了十万八千里。就是将一个字典,通过网络的方式提供了出去。但毕竟第一步,我们就来实现一个简单一点的(十分的简陋)。
我们主要来实现几个部分
客户端负责根据用户输入发起请求,通过网络的方式向服务端发送命令,并接受服务端的返回的结果,我们这里使用最原生的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依赖。
下面让我们来测试一下,启动客户端,启动服务端:
他顺利的工作了起来。