Code前端首页关于Code前端联系我们

阿里面试题:如何建立Mybatis中的Dao接口和XML文件中的SQL之间的关系?

terry 2年前 (2023-09-26) 阅读数 51 #数据库

阿里的这样一道面试题:

如何在SQL和XML文件中建立Dao接口和Mybatis的关系?如果有两个XML文件与这个DAO建立关系,岂不是会产生冲突?

如果你看过作者之前关于Mybatis源码分析的博文,相信你一定能给出很好的答案。

不过,由于该系列文章比较长,且以源码解读为主,所以笔者想重点围绕这个话题,梳理一下整个流程。 ? 。

1。创建SqlSource

Mybatis会将每个SQL标签封装成一个SqlSource对象。然后根据SQL语句的不同,分为动态SQL和静态SQL。其中,静态SQL包括字符串类型的SQL语句;而动态SQL则由SqlNode组成。 阿里面试题:Mybatis中Dao接口和XML文件里SQL如何建立关系?

假设我们有这样的 SQL:

<select id="getUserById" resultType="user">
	select * from user 
	<where>
		<if test="uid!=null">
			and uid=#{uid}
		</if>
	</where>
</select>	
复制代码

相应的 SqlSource 对象应如下所示:阿里面试题:Mybatis中Dao接口和XML文件里SQL如何建立关系?

2。创建MappedStatement

XML文件中的每个SQL标签都对应一个MappedStatement对象,这有两个属性非常重要。

  • id

ID 由完全限定类名 + 方法名组成。

  • sqlSource

SqlSource 对象对应于当前的 SQL 标签。

创建MappedStatement对象后,将其缓存在Configuration#mappedStatements中。

配置对象,我们知道它是Mybatis中的大管家,基本上所有的配置信息都保存在这里。解析完所有的XML之后,配置就包含了所有的SQL信息。 阿里面试题:Mybatis中Dao接口和XML文件里SQL如何建立关系?

至此XML解析完成。如果你看到上图,如果你足够聪明的话,你可能会有一个想法。当我们执行Mybatis方法时,通过完全限定类名+方法名找到MappedStatement对象,然后分析并执行里面的SQL内容。

2.Dao接口代理

我们的Dao接口没有实现类。那么,当我们调用它的时候,它最终是如何执行我们的SQL语句的呢?

首先,在spring的配置文件中,我们通常这样配置:

<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
	<property name="basePackage" value="com.viewscenes.netsupervisor.dao" />
	<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
</bean>
复制代码

或者如果你的项目是基于SpringBoot的,你一定见过这样的:@MapperScan("com.xxx.dao" )

它们具有相同的效果。在Spring Bean中注册包路径下的所有类,并将它们的BeanClass设置为MapperFactoryBean。有趣的是,MapperFactoryBean实现了FactoryBean接口,俗称工厂bean。然后,当我们通过@Autowired注入这个Dao接口时,返回的对象就是这个工厂bean中的MapperFactoryBean方法对象。

那么,这个方法有什么作用呢?

简单来说,就是通过JDK动态代理从Dao接口返回一个代理对象。该代理对象的处理器是 MapperProxy 对象。一切,当我们通过@Autowired注入Dao接口时,代理对象就被注入了。当我们调用Dao接口的方法时,会调用MapperProxy对象的call方法。

对于不明白这个内容的人,可以先看看Spring中使用代理的FactoryBean和JDK动态代理相关知识?

答案是肯定的,只要你配置MapperScan,它就会扫描然后生成代理。但是,如果你的Dao接口有一个实现类,并且这个实现类也是一个Spring bean,那么就看你在Autowired时注入哪一个了。

这到底是什么意思?我们来看一个例子。

如果我们为UserDao制作一个实现类并注册到Spring中。

@Component
public class UserDaoImpl implements UserDao{
	public List<User> getUserList(Map<String,Object> map){
		return new ArrayList<User>();
	}
}
复制代码

然后我们在service方法中注入这个userDao。猜猜会发生什么?

@Service
public class UserServiceImpl implements UserService{

	@Autowired
	UserMapper userDao1;

	public List<User> getUserList(Map<String,Object> map) {
		return userDao1.getUserList(map);
	}
}
复制代码

也许你猜对了,是的,它开始报错。因为在注入的过程中,发现了两个UserMapper实例对象。日志如下: 没有定义 [com.viewscenes.netsupervisor.dao.UserDao] 类型的合格 bean:预期只有匹配的 bean 但发现 2:userDaoImpl,userDao

命名当然不是完全正确的规范。事实上,我们可以通过名称注入它,如下所示:@Autowired UserMapper userDao;@Autowired UserMapper userDaoImpl;或添加。

具体原理请参见转作者文章:彻底理解Spring中的自动组装和自动装配

可能扯得太远了,我们继续回到Mybatis吧。所以,现在我们也有了一个通过 Dao 接口的代理实现,这样我们就可以执行其中的方法了。

3。执行

上面说了,当我们调用Dao接口方法时,实际上调用的是代理对象的call方法。这里,实际上调用的是SqlSession中的东西。

public class DefaultSqlSession implements SqlSession {

	public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
		try {
			MappedStatement ms = configuration.getMappedStatement(statement);
			return executor.query(ms, 
				wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
		}
	}
}
复制代码

看到上面的代码就说明我们想得不错。它通过语句完全限定类型+方法名获取MappedStatement对象,然后通过ExecutorExecutor执行具体的SQL并返回。 阿里面试题:Mybatis中Dao接口和XML文件里SQL如何建立关系?

4。总结

说到这里,我们回到一开始讨论的问题。也许你可以更好地回答他们。同时,笔者认为,如果你在这个问题中涵盖了以下关键词,面试官会非常满意。

  • SqlSource 和动态标签 SqlNode
  • MappedStatement 对象
  • Spring Factory Bean 和动态代理
  • SqlSession 和 Executor So 是 Da-Relo-Question 的第二个问题:这不是冲突吗?

    答案也显而易见。无论有多少 XML 与 Dao 关联,请确保 namespace+id 是唯一的。

    作者:安静之地
    链接:https://juejin.im/post/5c9f4af6f265da30bf15c45a
    来源:掘金版权归作者所有。如需商业转载,请联系求作者授权。非商业转载请来源。

版权声明

本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

热门