写点什么

浅入浅出 Mybatis(二)

作者:ES_her0
  • 2022 年 7 月 12 日
  • 本文字数:2101 字

    阅读完需:约 7 分钟

ORM 存在的意义就是提升业务开发效率,提升业务代码与数据库交互的性能。Mybatis 框架可以说是 ORM 的常青树,伴随 spring 的发展到 Spring boot 是很多业务开发者的首选。时至今日,有一部分人会觉得 xml 是万恶之源,讨厌这样的东西存在于自己的代码中,可能是 Spring boot 带起来的风潮吧。但实际上,这东西除了长的和 Java 代码不一样之外,性能上并不会降低多少。下面从整体上看一下 Mybatis 是如何运行的。

初始化

mybatis 在执行前会初始化一下,一般情况下会默认读取mybatis-config.xml文件。初始化仅仅会在项目启动时执行一次,以获取 mybatis 运行时必要的配置信息:数据库 url,user,password。这是基础信息,mybatis 是支持插件的,比如分页 PageHelper;还有一些设置信息,比如自动生成主键,驼峰命名自动转换,超时时间等。以下是初始化获取配置的方法:

private void parseConfiguration(XNode root) {    try {        this.propertiesElement(root.evalNode("properties"));        Properties settings = this.settingsAsProperties(root.evalNode("settings"));        this.loadCustomVfs(settings);        this.typeAliasesElement(root.evalNode("typeAliases"));        this.pluginElement(root.evalNode("plugins"));        this.objectFactoryElement(root.evalNode("objectFactory"));        this.objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));        this.reflectorFactoryElement(root.evalNode("reflectorFactory"));        this.settingsElement(settings);        this.environmentsElement(root.evalNode("environments"));        this.databaseIdProviderElement(root.evalNode("databaseIdProvider"));        this.typeHandlerElement(root.evalNode("typeHandlers"));        this.mapperElement(root.evalNode("mappers"));    } catch (Exception var3) {        throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + var3, var3);    }}
复制代码


以上解析获得了一个 Configuration 对象,这是构建 SqlSessionFactory 的基础,这个又是获得 SqlSeesion 的接口,而 SqlSeesion 提供了大量的 CRUD 方法,是日常使用最多的方法。在数据读写时首先会获取 SqlSession:

SqlSession session=sqlSessionFactory.openSession();
复制代码

数据读写

初始化完成之后,就可以开始进行数据的读写了。这个过程可以简单概括为以下几步:

  1. 寻找 Java 接口与 xml 的映射

  2. 组装参数

  3. 执行接口调用返回结果集


首先在 MapperRegistry 类中通过 getMapper 方法找到对应的接口实现,然后通过动态代理获取接口的参数列表并触发 MapperMethod 中的 execute 方法执行 SQL。附上最后的执行方法:

public Object execute(SqlSession sqlSession, Object[] args) {    Object param;    Object result;    switch(this.command.getType()) {    case INSERT:        param = this.method.convertArgsToSqlCommandParam(args);        result = this.rowCountResult(sqlSession.insert(this.command.getName(), param));        break;    case UPDATE:        param = this.method.convertArgsToSqlCommandParam(args);        result = this.rowCountResult(sqlSession.update(this.command.getName(), param));        break;    case DELETE:        param = this.method.convertArgsToSqlCommandParam(args);        result = this.rowCountResult(sqlSession.delete(this.command.getName(), param));        break;    case SELECT:        if (this.method.returnsVoid() && this.method.hasResultHandler()) {            this.executeWithResultHandler(sqlSession, args);            result = null;        } else if (this.method.returnsMany()) {            result = this.executeForMany(sqlSession, args);        } else if (this.method.returnsMap()) {            result = this.executeForMap(sqlSession, args);        } else if (this.method.returnsCursor()) {            result = this.executeForCursor(sqlSession, args);        } else {            param = this.method.convertArgsToSqlCommandParam(args);            result = sqlSession.selectOne(this.command.getName(), param);        }        break;    case FLUSH:        result = sqlSession.flushStatements();        break;    default:        throw new BindingException("Unknown execution method for: " + this.command.getName());    }
if (result == null && this.method.getReturnType().isPrimitive() && !this.method.returnsVoid()) { throw new BindingException("Mapper method '" + this.command.getName() + " attempted to return null from a method with a primitive return type (" + this.method.getReturnType() + ")."); } else { return result; }}
复制代码


以上就是简单的 mybatis 执行过程,只是一个大致的梳理。


用户头像

ES_her0

关注

还未添加个人签名 2018.03.21 加入

还未添加个人简介

评论

发布
暂无评论
浅入浅出Mybatis(二)_7月月更_ES_her0_InfoQ写作社区