Mybatis如何获取SQL语句
Mybatis如何获取SQL语句
⼀、获取映射⽂件xml
在我们的l⽂件⾥⾯,有这么⼀个标签
<mappers>
<mapper resource="l"/>
</mappers>
众所周知,这个绑定的是写SQL语句的⽂件,所以说,谁去解析的上⾯的这个xml⽂件,谁就能拿到SQL语句
那这个⽂件将会被哪个标签或者哪个类加载呢?我们知道l⽂件包含在mappers标签中,那么谁去解析mappers这个标签就能拿到这个⽂件所以内容。
在⾃动查资源⽅⾯,Java 并没有提供⼀个很好的解决⽅案,所以最好的办法是直接告诉 MyBatis 到哪
⾥去映射⽂件。
我们查看mappers标签,发现mybatis提供了4种⽅法映射⽂件。
与此同时,查看官⽅⽂档,官⽅给出了具体的使⽤⽅法。
但是,这四种哪⼀种的优先级的级别最⾼呢?
我们继续查看源码。我们来到上⼀讲的解析 configuration 标签下的所有属性配置的函数⽅法下⾯,/**
* 功能描述: 解析 configuration 标签下的所有属性配置
* @date 2020/2/27
*/
private void parseConfiguration(XNode root){
try{
// 读取l中的properties,加载config.properties⽂件中的参数
propertiesElement(root.evalNode("properties"));
Properties settings =settingsAsProperties(root.evalNode("settings"));
loadCustomVfs(settings);
loadCustomLogImpl(settings);
typeAliasesElement(root.evalNode("typeAliases"));
pluginElement(root.evalNode("plugins"));
objectFactoryElement(root.evalNode("objectFactory"));
objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
reflectorFactoryElement(root.evalNode("reflectorFactory"));
settingsElement(settings);
// 加载environments节点
environmentsElement(root.evalNode("environments"));
databaseIdProviderElement(root.evalNode("databaseIdProvider"));
typeHandlerElement(root.evalNode("typeHandlers"));
// 加载mapper⽂件
mapperElement(root.evalNode("mappers"));
}catch(Exception e){
throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: "+ e, e);
}
}
到对mappers解析的代码,mapperElement()
我们在⾥⾯可以查看到,mybatis对于映射⽅法的优先级确定。
private void mapperElement(XNode parent)throws Exception {
if(parent != null){
// 加载mapper的4种⽅式,分别为package、resource、url、class,优先级从前往后
for(XNode child : Children()){
if("package".Name())){
String mapperPackage = StringAttribute("name");
configuration.addMappers(mapperPackage);
}else{
String resource = StringAttribute("resource");
String url = StringAttribute("url");
String mapperClass = StringAttribute("class");
// 解析resource
if(resource != null && url == null && mapperClass == null){
ErrorContext.instance().resource(resource);
InputStream inputStream = ResourceAsStream(resource);
XMLMapperBuilder mapperParser =new XMLMapperBuilder(inputStream, configuration, resource, SqlFragments()); mapperParser.parse();
// 解析url
}else if(resource == null && url != null && mapperClass == null){
ErrorContext.instance().resource(url);
InputStream inputStream = UrlAsStream(url);
XMLMapperBuilder mapperParser =new XMLMapperBuilder(inputStream, configuration, url, SqlFragments());
mapperParser.parse();
// 解析mapperClass
}else if(resource == null && url == null && mapperClass != null){
Class<?> mapperInterface = Resources.classForName(mapperClass);
configuration.addMapper(mapperInterface);
}else{
throw new BuilderException("A mapper element may only specify a url, resource or class, but not more than one.");
}
}
}
}
}
优先级:package>resource>url>mapperClass
⼆、解析mapper⽂件,并获取内容
我们对于其中⼀个进⾏分析,例如resource:
ErrorContext.instance().resource(resource);
InputStream inputStream = ResourceAsStream(resource);
XMLMapperBuilder mapperParser =new XMLMapperBuilder(inputStream,SqlFragments()); mapperParser.parse();
我们查看最后⼀⾏代码mapperParser.parse(),
public void parse(){
if(!configuration.isResourceLoaded(resource)){
configurationElement(parser.evalNode("/mapper"));
configuration.addLoadedResource(resource);
bindMapperForNamespace();
}
parsePendingResultMaps();
parsePendingCacheRefs();
parsePendingStatements();
}
很明显,configurationElement⽅法就是对mapper⽂件进⾏解析的。我们深⼊查看。
private void configurationElement(XNode context){
try{
String namespace = StringAttribute("namespace");
if(namespace == null || namespace.equals("")){
throw new BuilderException("Mapper's namespace cannot be empty");
}
builderAssistant.setCurrentNamespace(namespace);
cacheRefElement(context.evalNode("cache-ref"));
cacheElement(context.evalNode("cache"));
parameterMapElement(context.evalNodes("/mapper/parameterMap"));
resultMapElements(context.evalNodes("/mapper/resultMap"));
sqlElement(context.evalNodes("/mapper/sql"));
buildStatementFromContext(context.evalNodes("select|insert|update|delete"));
}catch(Exception e){
throw new BuilderException("Error parsing Mapper XML. The XML location is '"+ resource +"'. Cause: "+ e, e);
}
}
我们先得到参数列表中的context值,
<mapper namespace="ad.UserDao">
<select id="selectUser"resultType="ad.User">
SELECT * FROM User where id = #{id}
</select>
</mapper>
发现,这正是mapper⽂件的内容。所以我们就已经拿到了mapper⽂件的内容,接下来的就是需要解析mapper⽂件⾥⾯的标签,拿到SQL语句。
三、得到SQL语句
我们继续查看上⾯对mapper⽂件解析的java代码,发现了两个可能与SQL语句相关的代码
sqlElement(context.evalNodes("/mapper/sql"));
buildStatementFromContext(context.evalNodes("select|insert|update|delete"));
我们先深⼊查看第⼀⾏代码,
private void sqlElement(List<XNode> list)throws Exception {
//从这⾥开始看
DatabaseId()!= null){
sqlElement(list, DatabaseId());
}
sqlElement(list, null);
}
其中
sqlElement(list, DatabaseId());
的解析过程如下:
private void sqlElement(List<XNode> list, String requiredDatabaseId)throws Exception { // 开始遍历每1个⼦节点
for(XNode context : list){
// 获取databaseId属性
String databaseId = StringAttribute("databaseId");
// 获取id属性
String id = StringAttribute("id");
// 添加上namespace构成完整路径
id = builderAssistant.applyCurrentNamespace(id,false);
// 继续处理
if(databaseIdMatchesCurrent(id, databaseId, requiredDatabaseId)){
resultset 遍历// 添加到这⾥
sqlFragments.put(id, context);
//添加进去
}
//结束
}
//结束
}
然后,继续处理
sqlElement(list, null);
这个⼀般不处理。
我们再查看第⼆⾏代码buildStatementFromContext
private void buildStatementFromContext(List<XNode> list){
DatabaseId()!= null){
buildStatementFromContext(list, DatabaseId());
}
buildStatementFromContext(list, null);
}
我们发现参数列表⾥⾯list,得到了SQL语句
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论