什么是MyBatis?
MyBatis是一个半ORM框架,它封装了JDBC,开发时只需关注SQL语句本身,不必再编写加载驱动、创建连接、编写statement的繁琐过程。程序员直接编写原生SQL,可以严格控制SQL语句的执行性能,灵活性高。
MyBatis可以通过XML和注解的形式来配置映射信息,避免了编写JDBC代码和手动处理结果集映射。
缺点是编写SQL语句工作量大,并且SQL语句依赖于数据库,导致不能随意更换数据库
ORM是什么?
ORM是对象关系映射,就是将程序中的对象映射为数据库中的记录,程序中的对象可以自动持久化到数据库中,数据库中的记录也能自动映射为对象,无需手动逐个处理映射关系。
为什么说MyBatis是半自动ORM框架,和全自动的区别是什么?
- Hibernate 属于全自动 ORM 映射工具,使用 Hibernate 查询关联对象或者关联集合对象时,可以根据对象关系模型直接获取,所以它是全自动的。
- 而 Mybatis 在查询关联对象或关联集合对象时,需要手动编写 SQL 来完成,所以,被称之为半自动 ORM 映射工具。
JDBC编程有哪些不足之处?MyBatis是如何解决的?
- 1、数据库连接创建、释放频繁造成系统资源浪费从而影响系统性能,在 mybatis-config.xml 中配置数据连接池,使用连接池统一管理数据库连接。
- 2、sql 语句写在代码中造成代码不易维护,将 sql 语句配置在 XXXXmapper.xml 文件中与 java 代码分离。
- 3、向 sql 语句传参数麻烦,因为 sql 语句的 where 条件不一定,可能多也可能少,占位符需要和参数一一对应。Mybatis 自动将 java 对象映射为 sql 语句的参数,灵活处理参数映射。
- 4、对结果集解析麻烦,sql 变化导致解析代码变化,且解析前需要遍历,如果能将数据库记录封装成 pojo 对象解析比较方便。Mybatis 自动将 sql 执行结果映射至 java 对象。
Hibernate和MyBatis的区别?
都是对JDBC的封装,都是作用于持久层的框架
不同点:
从映射关系上来看,MyBatis是半自动ORM框架,配置的是Java对象和sql执行结果的映射关系,多表关联关系配置简单;Hibernate是全自动ORM框架,配置的是Java对象和数据库全表的对应关系,多表关联关系配置复杂
从SQL优化和移植性角度,MyBatis需要手动编写SQL,可以直接使用SQL语句操作数据库,SQL优化容易,但是数据库可移植性差;Hibernate会自动生成SQL,不用手动编写SQL所以SQL优化困难,但是支持多种数据库
MyBatis使用过程?生命周期?
MyBatis生命周期
MyBatis的生命周期其实就是由各个组件的生命周期组成的
SqlSessionFactoryBulider:一般是临时的,用完即弃,生命周期是方法级的
SqlSessionFactory:复用的连接池,生命周期一般是应用级的,并且是单例的
SqlSession:一次查询会话,生命周期一般是方法级或者事务级别的,线程不安全,不能被共享
Mapper:一次SQL查询,生命周期一般是方法级别的
在Mapper中如何传递多个参数
方法 1:@Param 注解传参法
public User selectUser(@Param("userName") String name, int @Param("deptId") deptId);
<select id="selectUser" resultMap="UserResultMap">
select * from user
where user_name = #{userName} and dept_id = #{deptId}
</select>
\#{}
里面的名称对应的是注解@Param 括号里面修饰的名称。- 这种方法在参数不多的情况还是比较直观的,(推荐使用)。
方法 2:Map 传参法
public User selectUser(Map<String, Object> params);
<select id="selectUser" parameterType="java.util.Map" resultMap="UserResultMap">
select * from user
where user_name = #{userName} and dept_id = #{deptId}
</select>
\#{}
里面的名称对应的是 Map 里面的 key 名称。- 这种方法适合传递多个参数,且参数易变能灵活传递的情况。
方法 3:Java Bean 传参法
public User selectUser(User user);
<select id="selectUser" parameterType="com.jourwon.pojo.User" resultMap="UserResultMap">
select * from user
where user_name = #{userName} and dept_id = #{deptId}
</select>
\#{}
里面的名称对应的是 User 类里面的成员属性。- 这种方法直观,需要建一个实体类,扩展不容易,需要加属性,但代码可读性强,业务逻辑处理方便,推荐使用。(推荐使用)。
实体类属性名和表中字段名不一样怎么办?
在查询的SQL语句中自定义数据库字段的别名,使其和实体类属性名一致。
通过 resultMap 中的<result>来映射字段名和实体类属性名的一一对应的关系。
MyBatis是否可以映射Enum枚举类?
可以,需要自定义一个TypeHandler,实现 setParameter()和 getResult()两个方法,对应javaType到jdbcType设置参数和jdbcType到javaType获取查询结果
#{}和${}的区别?
#{}
是预编译处理,${}
是字符串替换。
①、当使用 #{}
时,MyBatis 会在 SQL 执行之前,将占位符替换为问号 ?
,并使用参数值来替代这些问号。
由于 #{}
使用了预处理,所以能有效防止 SQL 注入,确保参数值在到达数据库之前被正确地处理和转义。
②、当使用 ${}
时,参数的值会直接替换到 SQL 语句中去,而不会经过预处理。
这就存在 SQL 注入的风险,因为参数值会直接拼接到 SQL 语句中,假如参数值是 1 or 1=1
,那么 SQL 语句就会变成 SELECT * FROM users WHERE id = 1 or 1=1
,这样就会导致查询出所有用户的结果。
${}
通常用于那些不能使用预处理的场合,比如说动态表名、列名、排序等,要提前对参数进行安全性校验。
模糊查询like语句怎么写?
MyBatis能执行一对一、一对多的关联查询吗?
可以,一对一需要在resultMap中定义association标签,映射关联对象到主对象;一对多需要在resultMap中定义collection标签,映射关联对象集合到主对象
MyBatis是否支持延迟加载?原理?
- Mybatis 支持 association 关联对象和 collection 关联集合对象的延迟加载,association 指的就是一对一,collection 指的就是一对多查询。在 Mybatis 配置文件中,可以配置是否启用延迟加载 lazyLoadingEnabled=true|false。
- 原理是使用CGLIB创建目标对象的代理对象,当访问这个代理对象的关联对象时,进入拦截器方法intercept(),发现关联对象的值是null未填充,此时会执行查询对应关联对象的sql,然后在set到主对象中,接着完成针对关联对象的获取。
如何获取生成的主键?
xml中的insert标签中添加:keyProperty=" ID " 即可,生成的主键ID会返回设置到对象中
MyBatis支持动态SQL吗?
支持,根据表达式的值动态拼接SQL,比如if标签、choose (when, otherwise)标签,<where>可以用在所有的查询条件都是动态的情况,foreach构建IN语句
MyBatis如何进行批量操作?
foreach构建子句,collection代表集合类型的参数名(单个List或Array类型的参数名直接用list或array,Map类型传入多个参数的话,collection的参数名是map中对应集合的key),item代表每个元素名(随便起),separator 表示在每次进行迭代之间以什么符号作为分隔符,常用“,”;
第二种方法是使用 ExecutorType.BATCH
设置SqlSeesion的模式为BATCH,for循环像平时一样调用 Mapper 接口的方法,实际每次调用都不会立即执行而是缓存累积SQL语句,按照一定的频率批量提交累计的SQL语句
说说MyBatis的一级、二级缓存?
一级缓存:作用域是sqlSession,各个sqlSession之间的一级缓存是隔离的,基于HashMap,默认开启,可以减少重复数据库查询。
二级缓存:作用域是Mapper,各个sqlSession之间共享,也是基于HashMap,需要手动打开,实现跨 SqlSession
的数据共享,进一步减少数据库查询