Mybatis
Mybatis 是什么
- Mybatis是一个半自动ORM(对象关系映射)框架,它内部封装了JDBC,加载驱动、创建连接、创建 statement等繁杂的过程,开发者开发时需要关注如何编写SQL语句,可以严格控制sql执行性能,灵活度高。
- 作为一个半自动ORM框架,MyBatis 可以使用 XML 或注解来配置和映射原生信息,将 POJO映射成数 据库中的记录,避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。
- 通过xml 文件或注解的方式将要执行的各种 statement 配置起来,并通过java对象和 statement中 sql的动态参数进行映射生成最终执行的sql语句,最后由mybatis框架执行sql并将结果映射为java 对象并返回。(从执行sql到返回result的过程)。
- 由于MyBatis专注于SQL本身,灵活度高,所以比较适合对性能的要求很高,或者需求变化较多的 项目,如互联网项目。
Mybatis优缺点
优点:
- 基于sql语句编程,相当灵活。sql写在 xml里,解除sql与程序代码的耦合,便于统一管理。提供xml标签,支持编写动态sql语句,并可重用。
- 与jdbc相比,减少了50%以上的代码量,消除了jdbc大量冗余的代码,不需要手动开关连接。
- 很好的兼容各种数据库
- 能够与Spring很好的集成;
- 提供映射标签,支持对象与数据库的ORM字段关系映射; 提供对象关系映射标签,支持对象关系组件维护。
缺点:
- sql语句的编写工作量较大,尤其当字段多、关联表多时,对开发人员编写sql语句的功底有一定要求。
- sql语句依赖于数据库,导致数据库移植性差,不能随意更换数据库。
为什么说mybatis是半自动ORM映射工具?它与全自动的区别在哪里
habernate属于全自动ORM映射工具,使用habernate查询关联对象或者关联集合对象时,可以根据对象 关系模型直接获取,所以它是全自动的。
而mybatis在查询关联对象或关联集合对象时,需要手动编写sql来完成,所以,称之为半自动ORM映射 工具。
Hibernate 和 Mybatis 的区别
相同点:都是对jdbc的封装,都是持久层的框架,都用于dao层的开发。
- 映射关系
mybatis 是一个半自动映射的框架,配置java对象与sql语句执行结果的对应关系,多表关联关系配置简 单。
Hibernate 是一个全表映射的框架,配置java对象与数据库表的对应关系,多表关联关系配置复杂。 - sql优化和移植性
Hibernate 对sql语句封装,提供了日志、缓存、级联(级联比 Mybatis 强大)等特性,此外还提供 HQL(Hibernate query language)操作数据库,数据库无关性支持好,但会多消耗性能。如果项目需 要支持多种数据库,代码开发量少,但sql语句优化困难。
Mybatis 需要手动编写 sql, 支持动态 sql、处理列表、动态生成表名、支持存储过程。开发工作量相 对大些。直接使用sql语句操作数据库,不支持数据库无关性,但sql语句优化容易。 - 开发难易程度和学习成本
Hibernate 是重量级框架,学习使用门槛高,适合于需求相对稳定,中小型的项目,比如:办公自动化
系统
Mybatis 是轻量级框架,学习使用门槛低,适合于需求变化频繁,大型的项目,比如:互联网电子商务 系统
Mybatis 是一个小巧、方便、高效、简单、直接、半自动化的持久层框架.
Hibernate 是一个强大、方便、高效、复杂、间接、全自动化的持久层框架。
JDBC 编程有哪些不足之处,Mybatis 是如何解决这些问题的
- 数据库链接创建、释放频繁造成系统资源浪费从而影响系统性能,如果使用数据库链接池可解决此问题。
解决:在SqlMapConfig.xml中配置数据链接池,使用连接池管理数据库链接。 - sql语句写在代码中造成代码不易维护,实际应用sql变化的可能较大,sql变动需要改变java代码。
解决:将sql语句配置在xml文件中与java代码分离。 - 向sql语句传参数麻烦,因为sql语句的where条件不一定,可能多也可能少,占位符需要和参数一一 对应。
解决: Mybatis自动将java对象映射至sql语句。 - 对结果集解析麻烦,sql变化导致解析代码变化,且解析前需要遍历,如果能将数据库记录封装成
pojo对象解析比较方便。
解决:mybatis自动将sql执行结果映射至java对象。
Mybatis编程步骤
- 创建 SqlSessionFactory
- 通过 SqlSessionFactory 创建 SqlSession
- 通过 SqlSession 执行数据库操作
- 调用 session.commit 提交事务
- 调用 session.close 关闭会话
#{} 和 ${}的区别
${}的本质就是字符串拼接,#{}的本质就是占位符赋值
${}使用字符串拼接的方式拼接sql,若为字符串类型或日期类型的字段进行赋值时,需要手动加单引号;
#{}使用占位符赋值的方式拼接sql,此时为字符串类型或日期类型的字段进行赋值时,可以自动添加单引号
一般情况下推荐使用#{},但是有些时候使用#{}会有问题,譬如:模糊查询
、批量删除
、动态设置表面
select * from t_user where username = #{username}
select * from t_user where username = '${username}'
<!-- 2个参数 -->
select * from t_user where username = #{arg0} and password = #{arg1}
select * from t_user where username = '${param1}' and password = '${param2}'
解决字段名和属性名不一致的情况
a>为字段起别名,保持和属性名的一致
b>设置全局配置,将_自动映射为驼峰
c>通过resultMap设置自定义的映射关系
MyBatis获取参数值的各种情况:
-
mapper接口方法的参数为单个的字面量类型
可以通过KaTeX parse error: Expected 'EOF', got '#' at position 4: {}和#̲{}以任意的名称获取参数值,但…{}的单引号问题 -
mapper接口方法的参数为多个时
此时MyBatis会将这些参数放在一个map集合中,以两种方式进行存储
a>以arg0,arg1…为键,以参数为值
b>以param1,param2…为键,以参数为值
因此只需要通过#{}和 以键的方式访问值即可,但是需要注意 {}以键的方式访问值即可,但是需要注意 以键的方式访问值即可,但是需要注意{}的单引号问题 -
若mapper接口方法的参数有多个时,可以手动将这些参数放在一个map中存储
只需要通过#{}和 以键的方式访问值即可,但是需要注意 {}以键的方式访问值即可,但是需要注意 以键的方式访问值即可,但是需要注意{}的单引号问题 -
mapper接口方法的参数是实体类类型的参数
只需要通过#{}和 以属性的方式访问属性值即可,但是需要注意 {}以属性的方式访问属性值即可,但是需要注意 以属性的方式访问属性值即可,但是需要注意{}的单引号问题 -
使用@Param注解命名参数
此时MyBatis会将这些参数放在一个map集合中,以两种方式进行存储
a>以@Param注解的值为键,以参数为值
b>以param1,param2…为键,以参数为值
xml映射文件中,不同xml映射文件id是否可以重复
可以重复
Mybatis实现一对一有几种方式,具体怎么操作的
- 联合查询,几个表一次性查询 : 在resultMap中配置, 级联属性赋值、 association赋值
- 分步查询,先查一个表,然后根据外键查另一个表: association赋值
<resultMap id="empAndDeptByStepResultMap" type="Emp">
<id property="eid" column="eid"></id>
<result property="empName" column="emp_name"></result>
<result property="age" column="age"></result>
<result property="sex" column="sex"></result>
<result property="email" column="email"></result>
<!--
select:设置分步查询的sql的唯一标识(namespace.SQLId或mapper接口的全类名.方法名)
column:设置分布查询的条件
fetchType:当开启了全局的延迟加载之后,可通过此属性手动控制延迟加载的效果
fetchType="lazy|eager":lazy表示延迟加载,eager表示立即加载
-->
<association property="dept"
select="com.atguigu.mybatis.mapper.DeptMapper.getEmpAndDeptByStepTwo"
column="did"
fetchType="eager"></association>
</resultMap>
<!-- 核心配置 -->
<settings>
<!--将表中字段的下划线自动转换为驼峰-->
<setting name="mapUnderscoreToCamelCase" value="true"/> <!--开启延迟加载-->
<setting name="lazyLoadingEnabled" value="true"/>
</settings>
Mybatis实现一对多有几种方式,具体怎么操作的
- 联合查询,几个表一次性查询 : collection配置
- 分步查询,先查一个表,然后根据外键查另一个表: collection配置
<resultMap id="deptAndEmpByStepResultMap" type="Dept">
<id property="did" column="did"></id>
<result property="deptName" column="dept_name"></result>
<collection property="emps"
select="com.atguigu.mybatis.mapper.EmpMapper.getDeptAndEmpByStepTwo"
column="did" fetchType="eager"></collection>
</resultMap>
Mybatis动态sql是做什么的,都有哪些动态sql
Mybatis框架的动态SQL技术是一种根据特定条件动态拼装SQL语句的功能,它存在的意义是为了解决
拼接SQL语句字符串时的痛点问题。
if \ where \ trim \ choose when otherwise \ foreach \ sql 等等
Mybatis的一二级缓存
- 一级缓存:基于Hashmap本地缓存,其存储作用域为 SqlSession, 当 session close 或flush之后,该session中的所有cache就将清空,默认打开一级缓存。
- 二级缓存与一级缓存机制相同,默认也是采用 hashMap 存储,不同在于其存储 作用域为 Mapper(namespace),并且可自定义存储源,如EhCache。默认不打开二级缓存,要开启二级缓存,使用二级缓存属性类需要实现serializable序列化接口(可用来保存对象的状态),可在它的 映射文件中配置。
对于缓存数据更新机制,当某一个作用域(一级缓存session二级缓存namespace)进行了增删改操作后,默认该作用域下所有select中的缓存将被clear。
使用Mybatis的 Mapper 接口时有哪些要求
- Mapper 接口方法名和 xml 中定义的每个 sql 的 id 相同;
- Mapper 接口方法的输入参数类型和 xml 中定义的每个 sql 的 parameterType 类型相同;
- Mapper 接口方法的输出参数类型和 xml 中定义的每个 sql 的 returnType 的类型相同;
- xml 文件中的 namespace 即是 mapper 接口的类路径。