这是我参与11月更文挑战的第19天,活动详情查看:2021最后一次更文挑战。
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执行过程,只是一个大致的梳理。