JAVA实现一个数据库

简介: 它支持简单的CRUD操作和事务。这个实现中,每一个表都是一个Table对象。每个表都有一个名字、一组列名和列类型,以及一些行。每个行是一个对象数组,其中每个元素都是一个字段的值。表可以被创建、插入行和选择。对于选择,可以选择所有列或只选择特定列。

介绍

基于内存实现一个简易的类似mysql的数据库,末尾附代码,可优化,存储到磁盘。

创建一个Database类

Database类本身有一个Map,其中包含所有的Table对象。除了表的读写操作之外,Database类还支持事务。在这个实现中,每个事务都是在所有表上进行的。对于每个表,当前事务被表示为一个transactionRows Map,其中包含当前已插入的所有行。如果在事务中插入了新行,则这些行被添加到transactionRows,而不是直接添加到表中。当事务提交时,它们才会被真正地插入到表中。

创建一个Table类

Table类本身有一个名字,一组列名和类型,以及一个包含所有行的List。Table类有一个insertRow方法,可以将行插入到表中。此外,Table类还支持选择操作。这个实现中的选择支持选择所有列或只选择特定列。

支持事务

为了支持事务,Table类有两个Map:transactionRows和transactionLog。transactionRows Map包含当前已插入的所有行,transactionLog Map包含与当前事务相关的所有操作。在事务中,当插入新行时,新行将被添加到transactionRows和transactionLog中。事务提交时,transactionRows中的行被添加到Table的行中,transactionLog中的操作被提交。如果事务被回滚,则所有已插入的行都将从transactionRows中删除,并将transactionLog清空。

防止并发问题

另外,为了防止多个线程同时修改同一个表,Table类中包含一个读写锁,以确保只有一个线程可以写入数据。insertRow方法使用写锁,而selectRows方法使用读锁。

实现功能

代码还支持解析SQL语句,以执行相应的操作。它支持以下操作:

创建表 create table [table name] [column names]
插入行 insert into [table name] [values]
选择所有列 select * from [table name]
选择特定列 select [column names] from [table name]
开始事务 begin
提交事务 commit
回滚事务 rollback

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class Database {
    private Map<String, Table> tables;
    private ReadWriteLock tablesLock;

    public Database() {
        tables = new HashMap<>();
        tablesLock = new ReentrantReadWriteLock();
    }

    public void createTable(String tableName, String[] columnNames, Class<?>[] columnTypes) {
        tablesLock.writeLock().lock();
        try {
            // initialize table
            Table table = new Table(tableName, columnNames, columnTypes);
            tables.put(tableName, table);
        } finally {
            tablesLock.writeLock().unlock();
        }
    }
    public void execute(String statement) {
        String[] tokens = statement.trim().split("\\s+");

        if (tokens.length < 1) {
            throw new RuntimeException("Invalid statement");
        }
        String tableName="";
        if(tokens.length>=2){
            tableName = tokens[2];
        }
        if (tokens[0].equalsIgnoreCase("create")) {
            if (tokens.length < 4) {
                throw new RuntimeException("Invalid statement");
            }

            String[] columnNames = Arrays.copyOfRange(tokens, 3, tokens.length);
            Class<?>[] columnTypes = new Class<?>[columnNames.length];
            Arrays.fill(columnTypes, String.class);
            createTable(tableName, columnNames, columnTypes);
        } else if (tokens[0].equalsIgnoreCase("insert")) {
            if (tokens.length < 4) {
                throw new RuntimeException("Invalid statement");
            }
            String[] values = Arrays.copyOfRange(tokens, 3, tokens.length);
            Object[] row = new Object[values.length];
            for (int i = 0; i < values.length; i++) {
                row[i] = values[i];
            }
            Table table = getTable(tableName);
            table.insertRow(row);
        } else if (tokens[0].equalsIgnoreCase("select")) {
            if (tokens.length < 4) {
                throw new RuntimeException("Invalid statement");
            }
            int to=2;
            for (int i = 0; i < tokens.length; i++) {
                if(tokens[i].equalsIgnoreCase("from")){
                    to=i;
                }
            }
            String[] columnNames;
            if (tokens[1].equals("*")) {
                columnNames = null;
            } else {
                if(to==2){
                    throw new RuntimeException("Invalid statement");
                }
                columnNames = Arrays.copyOfRange(tokens, 1, to);
            }
            tableName=tokens[to+1];
            Table table = getTable(tableName);
            List<Object[]> rows = table.selectRows(columnNames);

            for (Object[] row : rows) {
                for (Object value : row) {
                    System.out.print(value + "\t");
                }
                System.out.println();
            }
        } else if (tokens[0].equalsIgnoreCase("begin")) {
            beginTransaction();
        } else if (tokens[0].equalsIgnoreCase("commit")) {
            commitTransaction();
        } else if (tokens[0].equalsIgnoreCase("rollback")) {
            rollbackTransaction();
        } else {
            throw new RuntimeException("Invalid statement");
        }
    }

    private Table getTable(String tableName) {
        tablesLock.readLock().lock();
        try {
            Table table = tables.get(tableName);
            if (table == null) {
                table = tables.get(tableName);
            }
            return table;
        } finally {
            tablesLock.readLock().unlock();
        }
    }

    private List<Table> getTables() {
        tablesLock.readLock().lock();
        try {
            return new ArrayList<>(tables.values());
        } finally {
            tablesLock.readLock().unlock();
        }
    }

    private void beginTransaction() {
        List<Table> tables = getTables();
        for (Table table : tables) {
            table.beginTransaction();
        }
    }

    private void commitTransaction() {
        List<Table> tables = getTables();
        for (Table table : tables) {
            table.commitTransaction();
        }
    }

    private void rollbackTransaction() {
        List<Table> tables = getTables();
        for (Table table : tables) {
            table.rollbackTransaction();
        }
    }

    private static class Table {
        private String tableName;
        private String[] columnNames;
        private Class<?>[] columnTypes;
        private List<Object[]> rows;
        private Map<Long, Object[]> transactionRows;
        private Map<Long, Operation> transactionLog;
        private ReadWriteLock lock;

        public Table(String tableName, String[] columnNames, Class<?>[] columnTypes) {
            this.tableName = tableName;
            this.columnNames = columnNames;
            this.columnTypes = columnTypes;
            this.rows = new ArrayList<>();
            this.transactionRows = new HashMap<>();
            this.transactionLog = new HashMap<>();
            this.lock = new ReentrantReadWriteLock();
        }

        public void insertRow(Object[] row) {
            lock.writeLock().lock();
            try {
                if (transactionRows.containsKey(Thread.currentThread().getId())) {
                    transactionLog.put(Thread.currentThread().getId(), new InsertOperation(row));
                    transactionRows.put(Thread.currentThread().getId(), row);
                } else {
                    rows.add(row);
                }
            } finally {
                lock.writeLock().unlock();
            }
        }

        public List<Object[]> selectRows(String[] columnNames) {
            lock.readLock().lock();
            try {
                List<Object[]> selectedRows = new ArrayList<>();
                if (transactionRows.containsKey(Thread.currentThread().getId())) {
                    for (Object[] row : transactionRows.values()) {
                        selectedRows.add(selectColumns(row, columnNames));
                    }
                } else {
                    for (Object[] row : rows) {
                        selectedRows.add(selectColumns(row, columnNames));
                    }
                }
                return selectedRows;
            } finally {
                lock.readLock().unlock();
            }
        }

        private Object[] selectColumns(Object[] row, String[] columnNames) {
            if (columnNames == null) {
                return row;
            } else {
                Object[] selectedColumns = new Object[columnNames.length];
                for (int i = 0; i < columnNames.length; i++) {
                    int columnIndex = getColumnIndex(columnNames[i]);
                    selectedColumns[i] = row[columnIndex];
                }
                return selectedColumns;
            }
        }

        public void beginTransaction() {
            lock.writeLock().lock();
            try {
                transactionRows.put(Thread.currentThread().getId(), new Object[0]);
                transactionLog.put(Thread.currentThread().getId(), null);
            } finally {
                lock.writeLock().unlock();
            }
        }

        public void commitTransaction() {
            lock.writeLock().lock();
            try {
                Object[] row = transactionRows.get(Thread.currentThread().getId());
                rows.add(row);
                transactionRows.remove(Thread.currentThread().getId());
                transactionLog.remove(Thread.currentThread().getId());
            } finally {
                lock.writeLock().unlock();
            }
        }

        public void rollbackTransaction() {
            lock.writeLock().lock();
            try {
                Operation operation = transactionLog.get(Thread.currentThread().getId());
                if (operation != null) {
                    if (operation instanceof InsertOperation) {
                        Object[] row = transactionRows.get(Thread.currentThread().getId());
                        rows.remove(row);
                    }
                }
                transactionRows.remove(Thread.currentThread().getId());
                transactionLog.remove(Thread.currentThread().getId());
            } finally {
                lock.writeLock().unlock();
            }
        }

        private int getColumnIndex(String columnName) {
            for (int i = 0; i < columnNames.length; i++) {
                if (columnNames[i].equalsIgnoreCase(columnName)) {
                    return i;
                }
            }
            throw new IllegalArgumentException("Column not found: " + columnName);
        }

        private abstract static class Operation {
        }

        private static class InsertOperation extends Operation {
            private Object[] row;

            public InsertOperation(Object[] row) {
                this.row = row;
            }

            public Object[] getRow() {
                return row;
            }
        }
    }

    public static void main(String[] args) {
        Database table = new Database();
        table.execute("create table test (id int, name varchar(50))");
        table.execute("insert into test (id, name) values (1, '小明')");
        table.execute("insert into test (id, name) values (2, '小红')");
        table.execute("insert into test (id, name) values (3, '小李')");

        table.execute("begin");
        table.execute("insert into test (id, name) values (4, '小黑')");
        table.execute("commit");
        table.execute("begin");
        table.execute("insert into test (id, name) values (5, '小白')");
        table.execute("rollback");

        table.execute("select * from test");

      }
}

目录
相关文章
|
4月前
|
负载均衡 算法 关系型数据库
大数据大厂之MySQL数据库课程设计:揭秘MySQL集群架构负载均衡核心算法:从理论到Java代码实战,让你的数据库性能飙升!
本文聚焦 MySQL 集群架构中的负载均衡算法,阐述其重要性。详细介绍轮询、加权轮询、最少连接、加权最少连接、随机、源地址哈希等常用算法,分析各自优缺点及适用场景。并提供 Java 语言代码实现示例,助力直观理解。文章结构清晰,语言通俗易懂,对理解和应用负载均衡算法具有实用价值和参考价值。
大数据大厂之MySQL数据库课程设计:揭秘MySQL集群架构负载均衡核心算法:从理论到Java代码实战,让你的数据库性能飙升!
|
5月前
|
NoSQL Java API
在Java环境下如何进行Redis数据库的操作
总的来说,使用Jedis在Java环境下进行Redis数据库的操作,是一种简单而高效的方法。只需要几行代码,就可以实现复杂的数据操作。同时,Jedis的API设计得非常直观,即使是初学者,也可以快速上手。
265 94
|
10月前
|
XML Java 数据库连接
性能提升秘籍:如何高效使用Java连接池管理数据库连接
在Java应用中,数据库连接管理至关重要。随着访问量增加,频繁创建和关闭连接会影响性能。为此,Java连接池技术应运而生,如HikariCP。本文通过代码示例介绍如何引入HikariCP依赖、配置连接池参数及使用连接池高效管理数据库连接,提升系统性能。
188 5
|
5月前
|
Java 关系型数据库 MySQL
Java汽车租赁系统源码(含数据库脚本)
Java汽车租赁系统源码(含数据库脚本)
91 4
|
6月前
|
前端开发 JavaScript Java
[Java计算机毕设]基于ssm的OA办公管理系统的设计与实现,附源码+数据库+论文+开题,包安装调试
OA办公管理系统是一款基于Java和SSM框架开发的B/S架构应用,适用于Windows系统。项目包含管理员、项目管理人员和普通用户三种角色,分别负责系统管理、请假审批、图书借阅等日常办公事务。系统使用Vue、HTML、JavaScript、CSS和LayUI构建前端,后端采用SSM框架,数据库为MySQL,共24张表。提供完整演示视频和详细文档截图,支持远程安装调试,确保顺利运行。
244 17
|
7月前
|
人工智能 JavaScript 关系型数据库
【02】Java+若依+vue.js技术栈实现钱包积分管理系统项目-商业级电玩城积分系统商业项目实战-ui设计图figmaUI设计准备-figma汉化插件-mysql数据库设计-优雅草卓伊凡商业项目实战
【02】Java+若依+vue.js技术栈实现钱包积分管理系统项目-商业级电玩城积分系统商业项目实战-ui设计图figmaUI设计准备-figma汉化插件-mysql数据库设计-优雅草卓伊凡商业项目实战
223 14
【02】Java+若依+vue.js技术栈实现钱包积分管理系统项目-商业级电玩城积分系统商业项目实战-ui设计图figmaUI设计准备-figma汉化插件-mysql数据库设计-优雅草卓伊凡商业项目实战
|
7月前
|
人工智能 JavaScript 安全
【01】Java+若依+vue.js技术栈实现钱包积分管理系统项目-商业级电玩城积分系统商业项目实战-需求改为思维导图-设计数据库-确定基础架构和设计-优雅草卓伊凡商业项目实战
【01】Java+若依+vue.js技术栈实现钱包积分管理系统项目-商业级电玩城积分系统商业项目实战-需求改为思维导图-设计数据库-确定基础架构和设计-优雅草卓伊凡商业项目实战
283 13
【01】Java+若依+vue.js技术栈实现钱包积分管理系统项目-商业级电玩城积分系统商业项目实战-需求改为思维导图-设计数据库-确定基础架构和设计-优雅草卓伊凡商业项目实战
|
7月前
|
存储 缓存 Java
java语言后台管理ruoyi后台管理框架-登录提示“无效的会话,或者会话已过期,请重新登录。”-扩展知识数据库中密码加密的方法-问题如何解决-以及如何重置若依后台管理框架admin密码-优雅草卓伊凡
java语言后台管理ruoyi后台管理框架-登录提示“无效的会话,或者会话已过期,请重新登录。”-扩展知识数据库中密码加密的方法-问题如何解决-以及如何重置若依后台管理框架admin密码-优雅草卓伊凡
730 3
java语言后台管理ruoyi后台管理框架-登录提示“无效的会话,或者会话已过期,请重新登录。”-扩展知识数据库中密码加密的方法-问题如何解决-以及如何重置若依后台管理框架admin密码-优雅草卓伊凡
|
8月前
|
SQL Java 关系型数据库
使用 JDBC 实现 Java 数据库操作
JDBC(Java Database Connectivity)是 Java 提供的数据库访问技术,允许通过 SQL 语句与数据库交互。本文详细介绍了 JDBC 的使用方法,包括环境准备、编程步骤和完整示例。
757 7
|
8月前
|
SQL Java 数据库连接
【潜意识Java】MyBatis中的动态SQL灵活、高效的数据库查询以及深度总结
本文详细介绍了MyBatis中的动态SQL功能,涵盖其背景、应用场景及实现方式。
839 6

热门文章

最新文章