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();
复制代码
数据读写
初始化完成之后,就可以开始进行数据的读写了。这个过程可以简单概括为以下几步:
寻找 Java 接口与 xml 的映射
组装参数
执行接口调用返回结果集
首先在 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 执行过程,只是一个大致的梳理。
评论