手写txt模拟数据库简易框架

编程入门 行业动态 更新时间:2024-10-23 13:32:57

手写txt模拟数据库<a href=https://www.elefans.com/category/jswz/34/1769136.html style=简易框架"/>

手写txt模拟数据库简易框架

一.前言

  之前学校让我们写控制台饿了么项目,当时进度没有到数据库,所以用的文本文件txt,来模拟数据库的实现,其实本质上就是一个文件读写,但是简单文件读写并不能包含我们想要的功能,例如条件查询,分页查询等功能,所以我处于好奇,手写了一个简易txt文本数据库框架

二.txt文件准备

  我们先准备几个txt文本文件,来看看他的格式

1.shops.txt商家表

Id    商家名称   商家评分   商家地址   商家简介   商家电话
1001 李家包子 5 牧野区102号 非常美味 123212312
1002 杨铭宇黄焖鸡米饭 4 河师大对面 太好吃了 21312311
1003 王星瑶黄焖鸡米饭 4 河师大对面 太好吃了 21312311
1004 赵家粥铺 4 河师大对面 太好吃了 21312311
1005 蜜雪冰城 4 河师大对面 太好吃了 21312311
1006 台湾卤肉饭 4 河师大对面 太好吃了 21312311
1007 地锅鸡 4 河师大对面 太好吃了 21312311
1008 美味小吃 4 河师大对面 太好吃了 21312311
1009 兰州牛肉拉面 4 河师大对面 太好吃了 21312311
1010 肯德基 4 河师大对面 太好吃了 21312311
1011 德克士 4 河师大对面 太好吃了 21312311
1012 麦当劳 4 河师大对面 太好吃了 21312311
1013 杨铭宇黄焖鸡米饭 4 河师大对面 太好吃了 21312311
1014 杨铭宇黄焖鸡米饭 4 河师大对面 太好吃了 21312311
1015 杨铭宇黄焖鸡米饭 4 河师大对面 太好吃了 21312311
1016 杨铭宇黄焖鸡米饭 4 河师大对面 太好吃了 21312311

2.dishes.txt菜品表

dID shopID 菜品名 介绍 销量 份数 价格
101 1002 蔡徐坤 不好吃 11 10 12.3 
102 1001 包子 无 312 12 12.5 
103 1001 大包子 无 312 31 12.50
104 1001 小包子 无 312 31 12.50
105 1001 中包子 无 312 31 12.50
106 1001 肉包子 无 312 31 12.50
107 1001 肉包子 无 312 31 12.50
108 1001 肉包子 无 312 31 12.50
109 1001 肉包子 无 312 31 12.50
110 1001 肉包子 无 312 31 12.50
111 1001 肉包子 无 312 31 12.50
112 1002 蔡徐坤 不好吃 112 10 12.3 

3.users.txt用户表

ID   用户名   密码   年龄   电话 地址
1001 jjh123 123456 22 1241241234 天堂小区三号楼12层左手户
1002 jfsf 123456 12 1241241234 垃圾小区三号楼12层左手户
681373 zhangsan 123456 123 3123134 地域小区三号楼12层左手户
899803 lisi 12345 18 13123123111 河南省新乡市牧野区河师大对面
663714 lisi123 12345 20 13212331231 河师大对面 

4.orders.txt订单表

ID shopId dishId userId name count singlePrice allPrice address  desc time
001 1001 102 1001 包子 2 12.50 25.00 天堂小区三号楼12层左手户 尽量快一点 2023-10-06T14:43:42.982695700
622975 1001 102 0 包子 1 12.5 12.5 天堂小区三号楼12层左手户 多加糖 2023-10-06T14:43:42.982695700 
708911 1001 102 0 包子 1 12.5 12.5    0  无 2023-10-06T19:45:08.918948500 
955207 1001 102 0 包子 2 12.5 25.0 天堂小区三号楼12层左手户 无 2023-10-25T17:59:15.207836800 
570959 1001 102 0 包子 10 12.5 125.0 天堂小区三号楼12层左手户 快点送达 2023-10-25T18:26:10.996829600 
543529 1001 102 0 包子 2 12.5 25.0 河南省新乡市牧野区河师大对面 多放辣 2023-10-29T11:35:43.542230100 
711960 1001 102 0 包子 2 12.5 25.0 河师大对面 多放辣椒 2023-10-29T11:55:11.967471800 

我们让他的格式看起来尽可能和MySQL中的差不多,然后我们来实现这些查询功能

三.条件构造器

我们知道mybatisplus中有一个条件构造器,querywrapper,你可以构建各种条件,然后来查询

我们来模仿这个条件构造器,来实现我们自己的构造器

(1)QueryBody

public class QueryBody {private String key;private String value;public QueryBody() {}public QueryBody(String key, String value) {this.key = key;this.value = value;}public String getKey() {return key;}public void setKey(String key) {this.key = key;}public String getValue() {return value;}public void setValue(String value) {this.value = value;}@Overridepublic String toString() {return "QueryBody{" +"key='" + key + '\'' +", value='" + value + '\'' +'}';}
}

其实就是一个key和对应的value,然后我们在来构建条件

(2)QueryWrapper

/*** 查询条件*/
public class QueryWrapper {/*** 参数集合*/private  List<QueryBody> queryArgs = new ArrayList<>();public QueryWrapper(){}/*** 相等条件*/public QueryWrapper eq(String key,String arg){QueryBody queryBody = new QueryBody(key,arg);queryArgs.add(queryBody);return this;}public List<QueryBody> getQueryArgs() {return queryArgs;}

这里为了简单我只实现了等值条件查询eq(),

注意:我们返回的是this,这个对象本身,这样就可以实现链式编程了

四.分页结果类PageBody

/*** 对分页的封装*/
public class PageBody {/*** 总条数*/private int total;/*** 当前的页数*/private int currntPage;/*** 当前每页的尺寸*/private int size;/*** 总页数*/private int pageSize;/*** 结果集*/private List<Object> results;public PageBody() {}public PageBody(int total, int currntPage, int size, int pageSize, List<Object> results) {this.total = total;this.currntPage = currntPage;this.size = size;this.pageSize = pageSize;this.results = results;}public int getTotal() {return total;}public void setTotal(int total) {this.total = total;//设置总页数if(size!=0){this.pageSize = total / size +1;}}public int getCurrntPage() {return currntPage;}public void setCurrntPage(int currntPage) {this.currntPage = currntPage;}public int getSize() {return size;}public void setSize(int size) {this.size = size;}public int getPageSize() {return pageSize;}//    public void setPageSize(int pageSize) {
//        this.pageSize = pageSize;
//    }public List<Object> getResults() {return results;}public void setResults(List<Object> results) {this.results = results;}@Overridepublic String toString() {return "PageBody{" +"total=" + total +", currntPage=" + currntPage +", size=" + size +", pageSize=" + pageSize +", results=" + results +'}';}public void setPageSize(int pageSize) {this.pageSize = pageSize;}
}

大致上和mybatispllus的page对象差不多

五.FileUtils工具类

该框架其实就是一个工具类,实现了大量的方法

/*** 文件工具类* @author JJH*/
public class FileUtils {......
}

我们把每个方法截取出来一个一个分析

返回属性get方法的工具方法

  private static String getXxx(String name){return "get" + name.substring(0,1).toUpperCase()+ name.substring(1);}

1.根据文件路径将文件内容返回为集合

   /*** 根据文件路径将文件内容返回为集合* @param path 文件路径* @param clazz 要返回对象的类型* @return 对象集合*/public static  List<Object> fileToList(String path, Class<?> clazz) {List<Object> list = new ArrayList<>();BufferedReader br = null;try {br = new BufferedReader(new FileReader(path));//读掉第一行数据(表头)br.readLine();String row;while ((row=br.readLine()) != null) {//先把对象创建出来Object obj = clazz.newInstance();//获取每一个元素String[] s = row.split(" ");//获取属性集合Field[] fields = clazz.getDeclaredFields();for (int i=0;i<fields.length;i++) {//获取属性的类型Class<?> type = fields[i].getType();String name = fields[i].getName();String setXxx="set"+name.substring(0,1).toUpperCase()+name.substring(1);//获取set方法Method setMethod = clazz.getDeclaredMethod(setXxx,type);//把参数类型转换一下String s1 = s[i];Object arg = TypeUtils.getInstanceByType(s1, type);//调用set方法给属性赋值setMethod.invoke(obj,arg);}//装入集合中list.add(obj);}return list;} catch (IOException | InvocationTargetException | NoSuchMethodException | InstantiationException |IllegalAccessException e) {throw new RuntimeException(e);} finally {try {assert br != null;br.close();} catch (IOException e) {throw new RuntimeException(e);}}}

主要使用了反射,传入文件的路径和要返回集合中对象的类型,这样就可以根据反射来获取属性然后给属性赋值了

2.将集合保存到文件中去

 /*** 将集合保存到文件中去* @param list 要保存的结合* @param path 文件路径* @param clazz 对象的类型* @return 是否保存成功* @param*/public static  boolean ListToFile(List<Object> list, String path, Class<?> clazz){BufferedWriter bw = null;try {//第二个参数是允许追加写入bw = new BufferedWriter(new FileWriter(path,true));StringBuilder sb = new StringBuilder();for (Object obj : list) {//先获取对象的属性Field[] fields = clazz.getDeclaredFields();for (Field field : fields) {//将第一个字母转化为大写String name = field.getName();String getXxx = "get"+name.substring(0, 1).toUpperCase()+ name.substring(1);//调用get方法获取属性值Method getMethod = clazz.getDeclaredMethod(getXxx);String str = getMethod.invoke(obj).toString();sb.append(str).append(" ");}sb.append("\n");}bw.write(sb.toString());} catch (Exception e) {throw new RuntimeException(e);} finally {try {assert bw != null;bw.close();} catch (IOException e) {throw new RuntimeException(e);}}return true;}

3.返回文件的行数

 /*** 返回文件的行数* @param path 文件路径* @return 行数* @throws IOException*/public static int getFileRow(String path) throws IOException {BufferedReader br = new BufferedReader(new FileReader(path));int sum =0;while (true){String str = br.readLine();if(str!=null){sum++;}else {break;}}return sum-1; //第一行不算}

4.模拟分页查询

 /*** 模拟分页查询* @param page 页数* @param size 尺寸* @param path 文件路径* @param clazz 返回集合中对象的类型* @return  对象集合*/public static List<Object> pageList(int page,int size,String path, Class<?> clazz) {/*计算开始位置,第一行不算,所以是从第二行开始2-11为第一页了,12-22为第二页23-33为第三页start = 2 + (page-1)*size当我们最后一页不满的时候,如果要把这一页剩余的部分查出来,直接查询会报错误,我们需要判断最后一页还有多少余量,让我们最后一次循环次数等于这个余量,不要让它越界*/List<Object> list = new ArrayList<>();try {//先获取总的条数,第一行不算int total = getFileRow(path) - 1;//计算一下最后一页有多少剩余(求余)int leastSize = total % size;BufferedReader br = new BufferedReader(new FileReader(path));//先让它读到startint start = 2 + (page - 1) * size;for (int i = 1; i < start; i++) {br.readLine();}//判断一下循环的次数,看看是满的,还是最后一页剩余的int num = total - (page-1) * size;int loop ; //循环次数if(leastSize==0||num>=10){loop = size;}else {loop = leastSize-1;}//然后让它读size次,默认为10for (int i = 0; i < loop; i++) {String row = br.readLine();//先把对象创建出来Object obj = clazz.newInstance();//获取每一个元素String[] s = row.split(" ");//获取属性集合Field[] fields = clazz.getDeclaredFields();for (int j = 0; j < fields.length; j++) {//获取属性的类型Class<?> type = fields[j].getType();String name = fields[j].getName();String setXxx = "set" + name.substring(0, 1).toUpperCase() + name.substring(1);//获取set方法Method setMethod = clazz.getDeclaredMethod(setXxx, type);//把参数类型转换一下String s1 = s[j];Object arg = TypeUtils.getInstanceByType(s1, type);//调用set方法给属性赋值setMethod.invoke(obj, arg);}//装入集合中list.add(obj);}}catch (Exception e){e.printStackTrace();}return list;}

5. 根据相等条件分页查询

 /*** 根据相等条件分页查询* @param page 页数* @param size 尺寸* @param path 文件路径* @param clazz 集合对象类型* @param wrapper 条件构造器* @return 对象集合*/public static List<Object> pageQueryList(int page, int size, String path, Class<?> clazz, QueryWrapper wrapper){//把条件构造器中的条件拿出来List<QueryBody> querybodys = wrapper.getQueryArgs();List<Object> list = new ArrayList<>();List<Object> resList = new ArrayList<>();try {BufferedReader br = new BufferedReader(new FileReader(path));br.readLine(); // 先把第一行读了int rows = getFileRow(path);for(int i=0;i<rows-1;i++){String str = br.readLine();//先把对象创建出来Object obj = clazz.newInstance();//获取每一个元素String[] s = str.split(" ");//获取属性集合Field[] fields = clazz.getDeclaredFields();for (int j = 0; j < fields.length; j++) {//获取属性的类型Class<?> type = fields[j].getType();String name = fields[j].getName();String setXxx = "set" + name.substring(0, 1).toUpperCase() + name.substring(1);//获取set方法Method setMethod = clazz.getDeclaredMethod(setXxx, type);//把参数类型转换一下String s1 = s[j];Object arg = TypeUtils.getInstanceByType(s1, type);//调用set方法给属性赋值setMethod.invoke(obj, arg);}//装入集合中list.add(obj);}}catch (Exception e){e.printStackTrace();}// list.forEach(System.out::println);//以上是拿到了所有的元素,下面我们来对元素先进行一个筛选try {for (QueryBody querybody : querybodys) {//对每个条件进行过滤String key = querybody.getKey();String value = querybody.getValue();//每次先清空resList.removeAll(resList);for (Object obj:list) {String getXxx = getXxx(key);//调用get方法来获取属性值Method getMethod = clazz.getDeclaredMethod(getXxx);String res = getMethod.invoke(obj).toString();//比对条件是否相等if(res.equals(value)){resList.add(obj);}}}} catch (Exception e) {throw new RuntimeException(e);}// resList.forEach(System.out::println);// 如果不传page和size,默认就全查if(Objects.isNull(page)&&Objects.isNull(size)){return resList;}ArrayList<Object> pageList = new ArrayList<>();//分页查询/*** 0-9 第一页* 10-19 第二页* 20-21 第三页* 还是得先判断一下最后一页的剩余问题**/int start = (page-1)*size;for(int i = 0;i<resList.size();i++){if(i==start){if(resList.size()<=size){size = resList.size();}else {//多于一页,算一下余量int mod = resList.size()%size;if(mod>0){//计算当前页面int currentPage = start/size+1 ;//算一下之前的总数据量是否if(mod+(currentPage*size-1) < currentPage*size){size = mod;}}}for(int j = start; j < (start+size); j++){pageList.add(resList.get(j));//pageList.forEach(System.out::println);}break;}}// pageList.forEach(System.out::println);return pageList;}

6.分页查询的默认全查形式,方法重载

/*** 分页查询的默认全查形式,方法重载* @param path 文件路径* @param clazz 对象类型* @param wrapper 条件构造器* @return  对象集合*/public static List<Object> pageQueryList(String path, Class<?> clazz, QueryWrapper wrapper){//把条件构造器中的条件拿出来List<QueryBody> querybodys = wrapper.getQueryArgs();List<Object> list = new ArrayList<>();List<Object> resList = new ArrayList<>();try {BufferedReader br = new BufferedReader(new FileReader(path));br.readLine(); // 先把第一行读了String row;while ((row=br.readLine())!=null){//先把对象创建出来Object obj = clazz.newInstance();//获取每一个元素String[] s = row.split(" ");//获取属性集合Field[] fields = clazz.getDeclaredFields();for (int j = 0; j < fields.length; j++) {//获取属性的类型Class<?> type = fields[j].getType();String name = fields[j].getName();String setXxx = "set" + name.substring(0, 1).toUpperCase() + name.substring(1);//获取set方法Method setMethod = clazz.getDeclaredMethod(setXxx, type);//把参数类型转换一下String s1 = s[j];Object arg = TypeUtils.getInstanceByType(s1, type);//调用set方法给属性赋值setMethod.invoke(obj, arg);}//装入集合中list.add(obj);}}catch (Exception e){e.printStackTrace();}//以上是拿到了所有的元素,下面我们来对元素先进行一个筛选try {for (QueryBody querybody : querybodys) {//对每个条件进行过滤String key = querybody.getKey();String value = querybody.getValue();// System.out.println(key+":"+value);//每次先清空resList.removeAll(resList);for (Object obj:list) {String getXxx = getXxx(key);//调用get方法来获取属性值Method getMethod = clazz.getDeclaredMethod(getXxx);Object res = getMethod.invoke(obj);//比对条件是否相等if(res.toString().equals(value)){resList.add(obj);}}}} catch (Exception e) {throw new RuntimeException(e);}return resList;}

7.根据主键修改改行数据

 /*** 根据主键修改改行数据* @param* @param*/public static boolean updateOne(String path, Object obj) {Class<?> aClass = obj.getClass();StringBuilder updateRow = new StringBuilder();Method getMethod = null;String str = null;String id = null;Field[] fields = aClass.getDeclaredFields();for (int i = 0;i<fields.length;i++) {try {getMethod = aClass.getDeclaredMethod(getXxx(fields[i].getName()));str = getMethod.invoke(obj).toString();updateRow.append(str).append(" ");} catch (Exception e) {throw new RuntimeException(e);}if(i==0){id = str;}}StringBuilder sb = new StringBuilder();try {BufferedReader reader = new BufferedReader(new InputStreamReader(Files.newInputStream(Paths.get(path))));//先把表头添加上String head = reader.readLine();sb.append(head).append("\r\n");int rows = getFileRow(path);for (int i = 0; i <rows ; i++) {String row = reader.readLine();String Id = row.split(" ")[0];if(id.equals(Id)) {sb.append(updateRow).append("\r\n");}else {sb.append(row).append("\r\n");}}//再把文件写回去BufferedWriter writer = new BufferedWriter(new FileWriter(path));writer.write(sb.toString());reader.close();writer.close();} catch (IOException e) {throw new RuntimeException(e);}return true;}

六.测试数据

我们来测试一下查询效果

可以看到,这时默认的全部查询方式,

 

可以看到,这是等值条件查询,查询到了包子店铺的菜品,

综上所述,我们实现了自己的txt文本数据库简易框架,当然还有很多功能不完善,下次希望可以模拟sql语句来实现查询,或者模拟一下事务的实现

 

更多推荐

手写txt模拟数据库简易框架

本文发布于:2023-11-15 21:32:37,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1606682.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:简易   框架   数据库   txt

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!