1.什么是Mybatis?
Mybatis是一个半ORM(对象关系映射)框架,它内部封装了JDBC--加载驱动、创建连接、创建statement等繁杂的过程,开发者开发时只需要关注如何编写SQL语句,可以严格控制sql执行性能,灵活度高。
Class.forName("com.jdbc.mysql.drvier);
}
2.MyBatis的实现逻辑
在 MyBatis 的初始化过程中,会生成一个 Configuration 全局配置对象,里面包含了所有初始化过程中生成对象。
根据 Configuration 创建一个 SqlSessionFactory 对象,用于创建 SqlSession “会话”。
通过 SqlSession 可以获取到 Mapper 接口对应的动态代理对象,去执行数据库的相关操作。
动态代理对象 执行数据库的操作,由 SqlSession 执行相应的方法,在他的内部调用 Executor 执行器去执行数据库的相关操作。
在 Executor 执行器中,会进行相应的处理,将数据库执行结果返回。
3.一级、二级缓存
一级缓存在 Executor 执行器(SimpleExecutor)中有一个 Cache 对象中,默认就是一个 HashMap 存储缓存数据,执行数据库查询操作前,如果在一级缓存中有对应的缓存数据,则直接返回。
二级缓存在 Executor 执行器(CachingExecutor)中有一个 TransactionalCacheManager 对象中,可以在一定程度上解决的一级缓存中多个 SqlSession 会话可能会导致数据不一致的问题,就是将一个 XML 映射文件中定义的缓存对象放在全局对象中,对于同一个 Mapper 接口都是使用这个 Cache 对象,不管哪个 SqlSession 都是使用该 Cache 对象执行数据库查询操作前,如果在二级缓存中有对应的缓存数据,则直接返回,没有的话则去一级缓存中获取,如果有对应的缓存数据,则直接返回。
4.缓存带来的问题
数据一致性问题 (在实际生产开发中,一级缓存 和 二级缓存 都是要关闭的!!)
5.## #{} 和 ${} 的区别是什么?
两者在 MyBatis 中都可以作为 SQL 的参数占位符,在处理方式上不同。
#{}:在解析 SQL 的时候会将其替换成 ? 占位符,然后通过 JDBC 的 PreparedStatement 对象添加参数值,这里会进行预编译处理,可以有效地防止 SQL 注入,提高系统的安全性。
${}:在 MyBatis 中带有该占位符的 SQL 片段会被解析成动态 SQL 语句,根据入参直接替换掉这个值,然后执行数据库相关操作,存在 SQL注入 的安全性问题。
6.MyBatis中自定义标签的执行原理
MyBatis 提供了以下几种动态 SQL 的标签:
<if />、<choose />、<when />、<otherwise />、<trim />、<where />、<set />、<foreach />、<bind />
在 MyBatis 的初始化过程中的解析 SQL 过程中,会将定义的一个 SQL 解析成一个个的 SqlNode 节点对象,当需要执行数据库查询前,需要根据入参对这些 SqlNode 对象进行解析。---> 先解析标签、再语句,最终生成完整的可执行的sql语句。
7.Mybaits的优缺点
(1)优点:
① 与JDBC相比,减少了50%以上的代码量,消除了JDBC大量冗余的代码,不需要手动开关连接;
② 基于SQL语句编程,相当灵活,不会对应用程序或者数据库的现有设计造成任何影响,SQL写在XML里,解除sql与程序代码的耦合,便于统一管理;提供XML标签,支持编写动态SQL语句,并可重用。
③ 很好的与各种数据库兼容(因为MyBatis使用JDBC(可以连mysql、oracle....)来连接数据库,所以只要JDBC支持的数据库MyBatis都支持)。
④ 能够与Spring很好的集成;
⑤ 提供映射标签,支持对象与数据库的ORM字段关系映射;提供对象关系映射标签,支持对象关系组件维护。
(2)缺点:
① SQL语句的编写工作量较大,尤其当字段多、关联表多时,对开发人员编写SQL语句的功底有一定要求。
② SQL语句依赖于数据库,导致数据库移植性差,不能随意更换数据库。
8.mapper如何传递参数?
(1)第一种:
//DAO层的函数
Public User selectUser(String name,String area);
//对应的xml,#{0}代表接收的是dao层中的第一个参数,#{1}代表dao层中第二参数,更多参数一致往后加即可。
<select id="selectUser"resultMap="BaseResultMap">
select * fromuser_user_t whereuser_name = #{0} anduser_area=#{1}
</select>
(2)第二种: 使用 @param 注解:
public interface usermapper {
user selectuser(@param(“username”) string username,@param(“hashedpassword”) string hashedpassword);
}
然后,就可以在xml像下面这样使用(推荐封装为一个map,作为单个参数传递给mapper):
<select id=”selectuser” resulttype=”user”>
select id, username, hashedpassword
from some_table
where username = #{username}
and hashedpassword = #{hashedpassword}
</select>
(3)第三种:多个参数封装成map
try{
//映射文件的命名空间.SQL片段的ID,就可以调用对应的映射文件中的SQL
//由于我们的参数超过了两个,而方法中只有一个Object参数收集,因此我们使用Map集合来装载我们的参数
Map<String, Object> map = new HashMap();
map.put("start", start);
map.put("end", end);
return sqlSession.selectList("StudentID.pagination", map);
}catch(Exception e){
e.printStackTrace();
sqlSession.rollback();
throw e; }
finally{
MybatisUtil.closeSqlSession();
}
(4) 第4种,通过对象传递(最常用的方式--业务语义清晰)
public class EmailSend {//这是一个对象
private Integer id;
private String sourceEmail;
private String targetEmail;
private Date createTime;
private String content;
}
<update id="updateByPrimaryKeySelective" parameterType="com.surwen.base.tool.domain.EmailSend">
update email_send
<set>
<if test="sourceEmail != null">
source_email = #{sourceEmail,jdbcType=VARCHAR},
</if>
<if test="targetEmail != null">
target_email = #{targetEmail,jdbcType=VARCHAR},
</if>
<if test="createTime != null">
create_time = #{createTime,jdbcType=TIMESTAMP},
</if>
<if test="content != null">
content = #{content,jdbcType=VARCHAR},
</if>
<if test="isValid != null">
is_valid = #{isValid,jdbcType=BIT},
</if>
</set>
where id = #{id,jdbcType=INTEGER}
</update>