自定义简单ORM框架

git地址:https://github.com/dp33221/my_orm

上次分析完了Mybatis启动以及执行流程后,本次根据上次的思路实现一个简单的mybatis框架。

首先需要分析一下什么场景下出现了ORM框架,最早的时候我们使用数据库链接步骤如下

原生jdbc操作

可以看到每次都需要注册驱动,建立连接,执行查询,获取结果,关闭连接。显然这存在高耦合以及硬编码问题。所以我们一步一步的解决问题。

第一四个问题:注册驱动以及建立数据库连接

    这边我们可以封装一个连接池,这样就可以解决耦合问题,然后数据库连接配置的话我们需要使用方提供,这边借鉴Mybatis的方式,使用xml进行配置。所以需要一个configuration对象。

第二三个问题:执行查询

    为了能够解耦以及可配置性,这边也是想到的使用配置文件的方式进行配置,参考Mybatis的Mapper.xml文件,这边需要一个mapperStatement对象存储对应的xml信息,分析一下这个对象需要哪些属性,首先肯定需要记录sql,然后要记录入参parameter,然后就是返回结果result,还有执行的类型也就是executorType,以及对应的id这个id默认就是标签中的id。

mappedStatement

xml中每个标签都会被解析成一个mappedstatement对象,所以我们需要有一个映射关系来保存,最容易想到的就是Map也就是键值对,键就取xml中的namespace+id,值就是对应的MappedStatement对象。存储在configuration对象中。所以configuration对象要存一个连接池,以及解析的xml的数据。

Conifguration

首先解决前两个问题,第一步需要配置配置文件sqlMapConfig.xml,其中我设置一个根标签<configuration />,以及子标签property来配置数据库连接属性解决硬编码问题。在解析configuration文件时也可以同时解析mapper.xml所以在设置一个mapper标签来设置要解析的mapper路径。

sqlMapConfig.xml

这就是基础的configuration配置,其中property就是数据库连接的基本配置,mapper就是要解析的mapper.xml

mapper.xml

mapper.xml文件配置了一些sql信息包括namespace、id、paramType、resultType、sql这些信息。

解析配置文件

    在解析配置文件之前,要理清楚一个大体的流程。首先需要创建一个SqlSession对象的工厂用于生成SqlSession,同时解析配置文件,然后生成sqlsession对象,之后在进行excutor操作。

总体结构

第一步

Resources.Java

1.开始解析xml配置文件,我借助dom4j以及jaxen来实现。首先第一步要将xml配置文件读成输入流的形式,借助classloader的getResourcesAsStream方法实现。


SqlSessionFactoyBuild.java

2.将字节输入流传递进来开始进行xml文件解析,执行XmlConfigBuild的buildConfiguration方法

XmlConfigBuild.java

3.首先获取字节流,然后获取xml跟标签, 通过xpath表达式得到节点信息,然后存储到properties中,创建连接池,然后设置数据源,存储到configuration对象中。然后获取所有的mapper标签,并遍历解析。调用的xmlMapperBuild的build方法。

XmlMapperBuild.java

在新建xmlmapperbuild对象时,要将已经设置数据源的configuration传入。解析Mapper的步骤与sqlMapConfig差不多,这边主要讲一下解析各个标签的步骤,首先就是获取到对应的id然后返回类型以及参数类型,再获取到sql语句,生成statementid(namespace+id)以及MappedStatement,存入configuration对象中的Map集合中。到这一步就执行完文件解析的步骤了。

第二步

接着就是生成sqlsession对象,sqlsession主要就是sql对话对象,执行sql操作

sqlsession.java
defaultSqlSession.java

首先定义一个接口 需要实现哪些方法,然后生成一个默认的实现类来实现这些方法,主要就是一个查询select方法以及一个更新update方法。其中提供了getMapper方法来实现Mapper接口的代理对象创建(jdk动态代理),具体步骤就是通过全限定类名+方法名去获取到MappedStatement对象(注意:因此namespace需要是类的全限定路径,id是类的方法,同时这也导致了方法无法重载)。然后通过返回值类型以及操作类型判断是走查询还是走更新操作,如果走更新操作则会记录方法的参数数组。sqlsession是一个对外的会话对象,其中执行sql语句还是通过Executor对象来执行的。

第三步

执行sql操作

Excutor.java
DefaultExecutor.java#query
DefaultExecutor.java#update

和sqlsession一样先创建一个接口定义规则,然后创建一个defaultExecutor进行默认实现。其中有一个查询功能一个更新功能,我这边注释写的比较全面,就不赘述了。其中有在处理请求参数时我借用了mybatis中的处理类。并进行了简化

utils

参数处理:下面是代码

GenericTokenParser

```

public class GenericTokenParser {

private final StringopenToken;

private final StringcloseToken;

private final TokenHandlerhandler;

public GenericTokenParser(String openToken, String closeToken, TokenHandler handler) {

this.openToken = openToken;

this.closeToken = closeToken;

this.handler = handler;

}

public String parse(String text) {

if (text ==null || text.isEmpty()) {

return "";

}

// search open token

    int start = text.indexOf(openToken);

if (start == -1) {

return text;

}

char[] src = text.toCharArray();

int offset =0;

final StringBuilder builder =new StringBuilder();

StringBuilder expression =null;

while (start > -1) {

if (start >0 && src[start -1] =='\\') {

// this open token is escaped. remove the backslash and continue.

        builder.append(src, offset, start - offset -1).append(openToken);

offset = start +openToken.length();

}else {

// found open token. let's search close token.

        if (expression ==null) {

expression =new StringBuilder();

}else {

expression.setLength(0);

}

builder.append(src, offset, start - offset);

offset = start +openToken.length();

int end = text.indexOf(closeToken, offset);

while (end > -1) {

if (end > offset && src[end -1] =='\\') {

// this close token is escaped. remove the backslash and continue.

            expression.append(src, offset, end - offset -1).append(closeToken);

offset = end +closeToken.length();

end = text.indexOf(closeToken, offset);

}else {

expression.append(src, offset, end - offset);

break;

}

}

if (end == -1) {

// close token was not found.

          builder.append(src, start, src.length - start);

offset = src.length;

}else {

builder.append(handler.handleToken(expression.toString()));

offset = end +closeToken.length();

}

}

start = text.indexOf(openToken, offset);

}

if (offset < src.length) {

builder.append(src, offset, src.length - offset);

}

return builder.toString();

}

}

```


ParameterMapping

```

public class ParameterMapping {

private Stringname;

}

```



ParameterMappingTokenHandler

```

public class ParameterMappingTokenHandlerimplements TokenHandler {

private ListparameterMappings =new ArrayList<>();

public List getParameterMappings() {

return parameterMappings;

}

@Override

    public String handleToken(String content) {

parameterMappings.add(buildParameterMapping(content));

return "?";

}

private ParameterMapping buildParameterMapping(String content) {

return new ParameterMapping(content);

}

}

```


TokenHandler

public interface TokenHandler {

String handleToken(String content);

}



测试结果

如图就是自定义ORM框架的查询结果,如果要查看增删改方法则调用update/delete/insert方法

Mapper中方的方法
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,539评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,594评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,871评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,963评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,984评论 6 393
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,763评论 1 307
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,468评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,357评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,850评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,002评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,144评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,823评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,483评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,026评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,150评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,415评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,092评论 2 355

推荐阅读更多精彩内容