阿里面试题:如何建立Mybatis中的Dao接口和XML文件中的SQL之间的关系?
阿里的这样一道面试题:
如何在SQL和XML文件中建立Dao接口和Mybatis的关系?如果有两个XML文件与这个DAO建立关系,岂不是会产生冲突?
如果你看过作者之前关于Mybatis源码分析的博文,相信你一定能给出很好的答案。
不过,由于该系列文章比较长,且以源码解读为主,所以笔者想重点围绕这个话题,梳理一下整个流程。 ? 。
1。创建SqlSource
Mybatis会将每个SQL标签封装成一个SqlSource对象。然后根据SQL语句的不同,分为动态SQL和静态SQL。其中,静态SQL包括字符串类型的SQL语句;而动态SQL则由SqlNode组成。
假设我们有这样的 SQL:
<select id="getUserById" resultType="user">
select * from user
<where>
<if test="uid!=null">
and uid=#{uid}
</if>
</where>
</select>
复制代码
相应的 SqlSource 对象应如下所示:
2。创建MappedStatement
XML文件中的每个SQL标签都对应一个MappedStatement对象,这有两个属性非常重要。
- id
ID 由完全限定类名 + 方法名组成。
- sqlSource
SqlSource 对象对应于当前的 SQL 标签。
创建MappedStatement
对象后,将其缓存在Configuration#mappedStatements
中。
配置对象,我们知道它是Mybatis中的大管家,基本上所有的配置信息都保存在这里。解析完所有的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动态代理相关知识? 答案是肯定的,只要你配置 这到底是什么意思?我们来看一个例子。 如果我们为UserDao制作一个实现类并注册到Spring中。 然后我们在service方法中注入这个userDao。猜猜会发生什么? 也许你猜对了,是的,它开始报错。因为在注入的过程中,发现了两个UserMapper实例对象。日志如下: 命名当然不是完全正确的规范。事实上,我们可以通过名称注入它,如下所示: 具体原理请参见转作者文章:彻底理解Spring中的自动组装和自动装配 可能扯得太远了,我们继续回到Mybatis吧。所以,现在我们也有了一个通过 Dao 接口的代理实现,这样我们就可以执行其中的方法了。 上面说了,当我们调用Dao接口方法时,实际上调用的是代理对象的call方法。这里,实际上调用的是SqlSession中的东西。 看到上面的代码就说明我们想得不错。它通过语句 说到这里,我们回到一开始讨论的问题。也许你可以更好地回答他们。同时,笔者认为,如果你在这个问题中涵盖了以下关键词,面试官会非常满意。 答案也显而易见。无论有多少 XML 与 Dao 关联,请确保 作者:安静之地MapperScan
,它就会扫描然后生成代理。但是,如果你的Dao接口有一个实现类,并且这个实现类也是一个Spring bean,那么就看你在Autowired
时注入哪一个了。 @Component
public class UserDaoImpl implements UserDao{
public List<User> getUserList(Map<String,Object> map){
return new ArrayList<User>();
}
}
复制代码
@Service
public class UserServiceImpl implements UserService{
@Autowired
UserMapper userDao1;
public List<User> getUserList(Map<String,Object> map) {
return userDao1.getUserList(map);
}
}
复制代码
没有定义 [com.viewscenes.netsupervisor.dao.UserDao] 类型的合格 bean:预期只有匹配的 bean 但发现 2:userDaoImpl,userDao
@Autowired UserMapper userDao;
或@Autowired UserMapper userDaoImpl;
或添加。 3。执行
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并返回。 4。总结
namespace+id
是唯一的。
链接:https://juejin.im/post/5c9f4af6f265da30bf15c45a
来源:掘金版权归作者所有。如需商业转载,请联系求作者授权。非商业转载请来源。
版权声明
本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。