亮了!Java工程师用代码“造”出数据库,核心原理一篇讲透

亮了!Java工程师用代码“造”出数据库,核心原理一篇讲透怎么用 Java 写一个数据库 各位头条的朋友们 今天咱们不聊别的 就聊点硬核又好玩的 用 Java 亲手 造 一个数据库 听到 数据库 三个字 你可能脑海里会浮现出 MySQL Oracle 这些庞然大物 心想 哇 那得多复杂啊

大家好,欢迎来到IT知识分享网。

#怎么用Java写一个数据库#

各位头条的朋友们,今天咱们不聊别的,就聊点硬核又好玩的——用Java亲手“造”一个数据库!

听到“数据库”三个字,你可能脑海里会浮现出MySQL、Oracle这些庞然大物,心想:“哇,那得多复杂啊!” 别急,咱们不造航母,先从造个小舢板开始,体验一下当“造物主”的乐趣。这篇文章,就是想带你用最通俗易懂的方式,一步步揭开数据库的神秘面纱,用Java写一个迷你版数据库的雏形。

咱们的“数据库”要实现啥目标?

想象一下,你有一个小本本,专门记录朋友的联系方式。这个小本本就是你的“数据库”。

  • 存数据(INSERT):新认识一个朋友,在本本上添上一行:张三,138xxxx0001。
  • 查数据(SELECT):想找李四的电话,翻开本本找到李四那一行。
  • 改数据(UPDATE):王五换手机号了,找到王五那行,把旧号码划掉,写上新号码。
  • 删数据(DELETE):赵六搬走了,不再联系,把赵六那行撕掉(或者划掉)。

咱们的Java迷你数据库,也力求实现这些基本功能。简单起见,我们先做一个内存数据库,数据存在内存里,程序一关就没了(别担心,后面会提到怎么让它“持久化”)。

第一步:数据的“家”在哪里?—— 数据结构的选择

既然是迷你版,咱们就用Java里最熟悉的数据结构。

一个数据库通常有很多张“表”(Table),比如“朋友联系表”、“商品信息表”。
每张表里有很多行“记录”(Row),每行记录里有多个“字段”(Column/Field)。

  • 字段(Field):比如“姓名”、“电话号码”。我们可以用 String 类型来表示字段名。
  • 记录(Row):一行记录就是多个字段和值的对应关系。用什么存呢?Map<String, Object> 就很合适!键是字段名(String),值是字段值(Object,可以是字符串、数字等)。
  • 表(Table):一张表就是多行记录的集合。用什么存呢?List<Map<String, Object>> 太棒了!
  • 数据库(Database):一个数据库就是多张表的集合。用什么存呢?Map<String, List<Map<String, Object>>> 完美!键是表名(String),值就是上面说的表。

来,上代码,定义我们的“数据库”骨架:

import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public class MiniDB { // 我们的“数据库”,用一个Map来存储所有的“表” // Key: 表名 (String) // Value: 表数据 (List<Map<String, Object>>) private Map<String, List<Map<String, Object>>> tables; public MiniDB() { this.tables = new HashMap<>(); System.out.println("MiniDB 启动啦!虽然小,但五脏俱全哦!"); } // 创建一张新表 public void createTable(String tableName) { if (tables.containsKey(tableName)) { System.out.println("警告:表 '" + tableName + "' 已经存在啦!"); return; } tables.put(tableName, new ArrayList<>()); System.out.println("表 '" + tableName + "' 创建成功!像不像给你的数据安了个新家?"); } // ... 后续我们会在这里添加 INSERT, SELECT 等方法 } 

你看,是不是很简单?MiniDB 类就是我们的数据库核心,tables 这个 Map 就是它管理所有数据的地方。createTable 方法就像是在你的大本子里新开一页,准备记录新的信息类别。

第二步:往“家”里添砖加瓦 —— INSERT 操作

现在我们有了“表”,怎么往里面放数据呢?比如,我们要往“朋友联系表”(friends)里加一条记录:姓名是“张三”,电话是“”。

// (接上面的 MiniDB 类) // 向指定表插入一条记录 public void insert(String tableName, Map<String, Object> row) { if (!tables.containsKey(tableName)) { System.out.println("错误:表 '" + tableName + "' 不存在,先用 createTable 创建一个吧!"); return; } List<Map<String, Object>> table = tables.get(tableName); table.add(row); // 直接加到List末尾 System.out.println("向表 '" + tableName + "' 插入数据成功: " + row); } 

来个小例子演示一下:

public class Main { public static void main(String[] args) { MiniDB myContactsDB = new MiniDB(); // 1. 创建一个叫 "friends" 的表 myContactsDB.createTable("friends"); // 2. 准备要插入的数据 Map<String, Object> friend1 = new HashMap<>(); friend1.put("name", "张三"); friend1.put("phone", ""); friend1.put("city", "北京"); Map<String, Object> friend2 = new HashMap<>(); friend2.put("name", "李四"); friend2.put("phone", ""); // 李四可能没有城市信息,我们的迷你数据库很灵活! // 3. 插入数据 myContactsDB.insert("friends", friend1); myContactsDB.insert("friends", friend2); // 尝试插入到一个不存在的表 Map<String, Object> dataForGhostTable = new HashMap<>(); dataForGhostTable.put("error", "test"); myContactsDB.insert("ghost_table", dataForGhostTable); } } 

运行 Main 方法,你会看到:

MiniDB 启动啦!虽然小,但五脏俱全哦! 表 'friends' 创建成功!像不像给你的数据安了个新家? 向表 'friends' 插入数据成功: {city=北京, name=张三, phone=} 向表 'friends' 插入数据成功: {name=李四, phone=} 错误:表 'ghost_table' 不存在,先用 createTable 创建一个吧! 

是不是感觉有点小成就了?我们已经能创建表、插入数据了!

第三步:从“家”里找东西 —— SELECT 操作

数据存进去了,关键是要能取出来。我们先实现一个简单的 SELECT * FROM tableName,也就是把表里的所有数据都捞出来。

// (接上面的 MiniDB 类) // 查询指定表的所有数据 (SELECT * FROM tableName) public List<Map<String, Object>> selectAll(String tableName) { if (!tables.containsKey(tableName)) { System.out.println("错误:表 '" + tableName + "' 不存在,是不是写错名字了?"); return new ArrayList<>(); // 返回一个空列表 } List<Map<String, Object>> table = tables.get(tableName); System.out.println("从表 '" + tableName + "' 中查询到 " + table.size() + " 条记录:"); for (Map<String, Object> row : table) { System.out.println(row); } return new ArrayList<>(table); // 返回一个拷贝,防止外部修改原始数据 } 

Main 方法里加几行测试一下:

// (接上面的 Main 方法) System.out.println("\n--- 查询 friends 表所有数据 ---"); List<Map<String, Object>> allFriends = myContactsDB.selectAll("friends"); // 你可以对 allFriends 做进一步处理 System.out.println("\n--- 查询一个不存在的表 ---"); myContactsDB.selectAll("enemies"); 

输出会增加:

--- 查询 friends 表所有数据 --- 从表 'friends' 中查询到 2 条记录: {city=北京, name=张三, phone=} {name=李四, phone=} --- 查询一个不存在的表 --- 错误:表 'enemies' 不存在,是不是写错名字了? 

来点挑战:带条件的查询 (SELECT * FROM tableName WHERE … )

如果我们只想找“张三”的信息怎么办?这就需要带条件的查询了。为了简单,我们先实现一个单条件查询:WHERE 字段名 = 值

// (接上面的 MiniDB 类) // 根据条件查询数据 (简化的 WHERE 子句) // 例如: SELECT * FROM friends WHERE name = '张三' public List<Map<String, Object>> selectWhere(String tableName, String fieldName, Object value) { if (!tables.containsKey(tableName)) { System.out.println("错误:表 '" + tableName + "' 不存在。"); return new ArrayList<>(); } List<Map<String, Object>> table = tables.get(tableName); List<Map<String, Object>> result = new ArrayList<>(); System.out.println("在表 '" + tableName + "' 中查找 '" + fieldName + "' 是 '" + value + "' 的记录..."); for (Map<String, Object> row : table) { // 注意:这里简单用了 equals比较。对于不同类型和 null 值需要更严谨的处理。 // 而且,如果字段不存在于某行,row.get(fieldName) 会返回 null。 if (row.containsKey(fieldName) && value.equals(row.get(fieldName))) { result.add(row); } } System.out.println("找到 " + result.size() + " 条符合条件的记录:"); for (Map<String, Object> row : result) { System.out.println(row); } return result; } 

Main 方法里测试:

// (接上面的 Main 方法) System.out.println("\n--- 查询 friends 表中 name 是 '张三' 的数据 ---"); myContactsDB.selectWhere("friends", "name", "张三"); System.out.println("\n--- 查询 friends 表中 city 是 '上海' 的数据 ---"); myContactsDB.selectWhere("friends", "city", "上海"); // 应该找不到 System.out.println("\n--- 查询 friends 表中 phone 是  的数据 ---"); myContactsDB.selectWhere("friends", "phone", ""); 

看看输出,是不是感觉越来越像个正经数据库了?

第四步:装修“家” —— UPDATE 操作

王五换号了,得更新一下。UPDATE 操作通常也需要条件,比如 UPDATE tableName SET newField=newValue WHERE conditionField=conditionValue
我们简化一下:找到符合条件的行,然后用新的数据更新它(或者合并)。

// (接上面的 MiniDB 类) // 更新数据 (简化的 UPDATE ... WHERE ...) // 更新所有满足条件的行中的特定字段 public int update(String tableName, String conditionField, Object conditionValue, String updateField, Object newValue) { if (!tables.containsKey(tableName)) { System.out.println("错误:表 '" + tableName + "' 不存在。"); return 0; } List<Map<String, Object>> table = tables.get(tableName); int updatedCount = 0; System.out.println("准备更新表 '" + tableName + "' 中 '" + conditionField + "' 是 '" + conditionValue + "' 的记录,将 '" + updateField + "' 设置为 '" + newValue + "'"); for (Map<String, Object> row : table) { if (row.containsKey(conditionField) && conditionValue.equals(row.get(conditionField))) { row.put(updateField, newValue); // 更新或添加字段 updatedCount++; System.out.println("更新了一条记录:" + row); } } System.out.println("总共更新了 " + updatedCount + " 条记录。"); return updatedCount; } 

测试一下:

// (接上面的 Main 方法) System.out.println("\n--- 更新 张三 的城市为 深圳 ---"); myContactsDB.update("friends", "name", "张三", "city", "深圳"); myContactsDB.selectWhere("friends", "name", "张三"); // 查看更新结果 System.out.println("\n--- 给 李四 添加城市信息 上海 ---"); myContactsDB.update("friends", "name", "李四", "city", "上海"); myContactsDB.selectWhere("friends", "name", "李四"); // 查看更新结果 

第五步:清理“家” —— DELETE 操作

赵六搬走了,我们得把他从通讯录里删掉。DELETE FROM tableName WHERE conditionField=conditionValue

// (接上面的 MiniDB 类) // 删除数据 (简化的 DELETE ... WHERE ...) public int delete(String tableName, String conditionField, Object conditionValue) { if (!tables.containsKey(tableName)) { System.out.println("错误:表 '" + tableName + "' 不存在。"); return 0; } List<Map<String, Object>> table = tables.get(tableName); // 注意:不能在遍历List时直接删除元素,会导致 ConcurrentModificationException // 所以我们先收集要删除的,再统一删除,或者使用 Iterator.remove() List<Map<String, Object>> rowsToRemove = new ArrayList<>(); int deletedCount = 0; System.out.println("准备从表 '" + tableName + "' 中删除 '" + conditionField + "' 是 '" + conditionValue + "' 的记录..."); for (Map<String, Object> row : table) { if (row.containsKey(conditionField) && conditionValue.equals(row.get(conditionField))) { rowsToRemove.add(row); } } if (!rowsToRemove.isEmpty()) { table.removeAll(rowsToRemove); deletedCount = rowsToRemove.size(); System.out.println("成功删除了 " + deletedCount + " 条记录。"); } else { System.out.println("没有找到符合条件的记录进行删除。"); } return deletedCount; } 

测试:

// (接上面的 Main 方法) // 先加个王五用来删除 Map<String, Object> friendWang = new HashMap<>(); friendWang.put("name", "王五"); friendWang.put("phone", ""); myContactsDB.insert("friends", friendWang); System.out.println("\n--- 当前所有朋友 ---"); myContactsDB.selectAll("friends"); System.out.println("\n--- 删除 王五 的记录 ---"); myContactsDB.delete("friends", "name", "王五"); System.out.println("\n--- 删除后,当前所有朋友 ---"); myContactsDB.selectAll("friends"); 

思考与展望:让“小舢板”变成“巡洋舰”

我们这个迷你数据库虽然简陋,但已经有了CRUD(Create, Read, Update, Delete)的雏形。它就像一个刚刚学会走路的婴儿,离真正的数据库还有很长的路要走:

  1. 数据持久化:现在数据都在内存里,程序一关就没了。怎么保存到硬盘上呢?简单方式:可以将 tables 这个 Map 序列化成一个文件(比如用Java的 ObjectOutputStream),启动时再反序列化回来。文本方式:可以把每张表存成一个CSV文件,或者JSON文件。每行代表一条记录。
  2. 更复杂的查询SELECT 指定字段,而不是 SELECT *WHERE 支持 AND, OR, >, <, LIKE 等。ORDER BY (排序)。GROUP BY (分组), JOIN (多表连接)。
  3. 索引(Index):现在查询都是遍历整张表,数据量大了会慢得像蜗牛。索引就像书的目录,能大大加快查找速度。比如可以为“name”字段建一个索引,用一个 Map<String, List<Integer>> 存名字到行号列表的映射。
  4. 事务(Transaction):转账操作,A账户减钱,B账户加钱,这两个操作要么都成功,要么都失败。这就是事务ACID特性(原子性、一致性、隔离性、持久性)的体现。
  5. 并发控制(Concurrency Control):多个人同时操作数据库,怎么保证数据不错乱?需要锁机制等。
  6. SQL解析器:我们现在是直接调用Java方法,真正的数据库需要解析SQL语句(比如 “SELECT name, phone FROM friends WHERE city = ‘北京’”),将其转换成内部操作。这通常需要编译原理的知识(词法分析、语法分析)。
  7. 数据类型和约束:比如定义某个字段必须是整数,某个字段不能为空等。

总结

朋友们,今天我们用Java搭了一个超简陋的数据库框架。虽然它离生产环境的数据库还差十万八千里,但这个过程能帮助我们理解数据库的基本原理:核心就是如何组织和操作数据

是不是觉得没那么高不可攀了?编程的乐趣就在于创造。从一个简单的想法开始,一步步添砖加瓦,最终构建出一个有用的东西,这种成就感是无可比拟的。

如果你对这个话题感兴趣,可以尝试着给咱们的 MiniDB 添加上面提到的“持久化”功能,或者尝试实现一个更强大的 WHERE 条件判断。你会发现,在解决这些问题的过程中,你的编程能力和对系统设计的理解都会噌噌上涨!

希望这篇文章能点燃你对数据库底层探索的兴趣。下次再聊!觉得有用的话,点个赞支持一下呗!

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/179770.html

(0)
上一篇 2025-06-01 07:20
下一篇 2025-06-01 07:26

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信