什么是MyBatis
MyBatis原来是apache的一个开源项目,叫做ibatis,2010年这个项目由apache迁移到了google code,并且改名为MyBatis,是一个基于Java的持久层框架。
MyBatis的优势
1.MyBatis 避免了几乎所有的JDBC 代码和手动设置参数以及获取结果集的过程,减少了代码的冗余,减少程序员的操作。
2.MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 实体类映射成数据库中的记录。
Mybatis的四个核心组件
1.SqlSessionFactoryBuilder (构造器):它会根据配置或者代码来生成 SqISessionFactory,采用的是分步构建的 Builder 模式。
2.SqlSessionFactory (工厂接口):依靠它来生成 SqlSession,使用的是工厂模式。
3.SqlSession (会话): 一个既可以发送 SQL 执行返回结果,也可以获取 Mapper 的接 口。在现有的技术中, 一般我们会让其在业务逻辑代码中“消失”,而使用的是 MyBatis 提供的 SQLMapper 接口编程技术,它能提高代码的可读性和可维护性。
4.SQL Mapper (映射器): MyBatis 新设计存在的组件,它由一个 Java 接口和 XML 文件(或注解)构成,需要给出对应的 SQL 和映射规则。它负责发送SQL去执行, 并返回结果
Mybatis配置文件的元素
Mybatis的基础crud语句
id标识了对应的SQL语句,parameterType标出了参数的类型,resultType则代表结果映射的类型。
解决 Mybatis 数据库字段名和实体类属性名不一致问题的三种办法
1.取别名
2.使用 resultMap 标签 (推荐使用)
3.如果只是单纯的下划线,可以使用 setting 标签设置开启驼峰命名规则。
<settings>
<setting name="mapUnderscoreToCamelCase" value="true" />
</settings>
动态 sql 拼接
MyBatis 动态 sql 可以让我们在 xml 映射文件内,以标签的形式编写动态 sql,完成逻辑判断和动态拼接 sql 的功能。其执行原理为,使用 OGNL 从 sql 参数对象中计算表达式的值,根据表达式的值动态拼接 sql,以此来完成动态 sql 的功能。
if 标签
if 标签通常用于 WHERE 语句、UPDATE 语句、INSERT 语句中,通过判断参数值来决定是否使用某个查询条件、判断是否更新某一个字段、判断是否插入某个字段的值。
<if test="name != null and name != ''">
and NAME = #{name}
</if>
foreach 标签
foreach 标签主要用于构建 in 条件,可在 sql 中对集合进行迭代(遍历集合)。也常用到批量删除、添加等操作中。
<!-- in查询所有,不分页 -->
<select id="selectIn" resultMap="BaseResultMap">
select name,hobby from student where id in
<foreach item="item" index="index" collection="list" open="(" separator="," close=")">
#{item}
</foreach>
</select>
属性介绍:
collection:遍历的集合。
item :表示在迭代过程中每一个元素的别名
index :表示在迭代过程中每次迭代到的位置(下标)
open :遍历开始前拼接的sql片段
close :遍历结束后拼接的sql片段
separator :分隔符,表示迭代时每个元素之间以什么分隔
choose 标签
有时候我们并不想应用所有的条件,而只是想从多个选项中选择一个。MyBatis 提供了 choose 元素,按顺序判断 when 中的条件出否成立,如果有一个成立,则 choose 结束。当 choose 中所有 when的条件都不满则时,则执行 otherwise 中的 sql。类似于 Java 的 switch 语句,choose 为 switch,when 为 case,otherwise 则为 default。
if 是与(and)的关系,而 choose 是或(or)的关系。
<select id="getStudentListChoose" parameterType="Student" resultMap="BaseResultMap">
SELECT * from STUDENT WHERE 1=1
<where>
<choose>
<when test="Name!=null and student!='' ">
AND name LIKE CONCAT(CONCAT('%', #{student}),'%')
</when>
<when test="hobby!= null and hobby!= '' ">
AND hobby = #{hobby}
</when>
<otherwise>
AND AGE = 15
</otherwise>
</choose>
</where>
</select>
where 标签
当 if 标签较多时,这样的组合可能会导致错误。 如下:
<select id="getStudentListWhere" parameterType="Object" resultMap="BaseResultMap">
SELECT * from STUDENT WHERE
<if test="name!=null and name!='' ">
NAME LIKE CONCAT(CONCAT('%', #{name}),'%')
</if>
<if test="hobby!= null and hobby!= '' ">
AND hobby = #{hobby}
</if>
</select>
当 name 值为 null 时,查询语句会出现 “WHERE AND” 的情况,解决该情况除了将"WHERE"改为“WHERE 1=1”之外,还可以利用 where标签。这个“where”标签会知道如果它包含的标签中有返回值的话,它就插入一个‘where’。此外,如果标签返回的内容是以 AND 或 OR 开头的,则它会剔除掉。
<select id="getStudentListWhere" parameterType="Object" resultMap="BaseResultMap">
SELECT * from STUDENT
<where>
<if test="name!=null and name!='' ">
NAME LIKE CONCAT(CONCAT('%', #{name}),'%')
</if>
<if test="hobby!= null and hobby!= '' ">
AND hobby = #{hobby}
</if>
</where>
</select>
set 标签
没有使用 if 标签时,如果有一个参数为 null,都会导致错误。当在 update 语句中使用 if 标签时,如果最后的 if 没有执行,则或导致逗号多余错误。使用 set 标签可以将动态的配置 set关键字,和剔除追加到条件末尾的任何不相关的逗号。
<update id="updateStudent" parameterType="Object">
UPDATE STUDENT
SET NAME = #{name},
MAJOR = #{major},
HOBBY = #{hobby}
WHERE ID = #{id};
</update>
<update id="updateStudent" parameterType="Object">
UPDATE STUDENT SET
<if test="name!=null and name!='' ">
NAME = #{name},
</if>
<if test="hobby!=null and hobby!='' ">
MAJOR = #{major},
</if>
<if test="hobby!=null and hobby!='' ">
HOBBY = #{hobby}
</if>
WHERE ID = #{id};
</update>
<update id="updateStudent" parameterType="Object">
UPDATE STUDENT
<set>
<if test="name!=null and name!='' ">
NAME = #{name},
</if>
<if test="hobby!=null and hobby!='' ">
MAJOR = #{major},
</if>
<if test="hobby!=null and hobby!='' ">
HOBBY = #{hobby}
</if>
</set>
WHERE ID = #{id};
</update>
trim 标签
trim标记是一个格式化的标记,主要用于拼接sql的条件语句(前缀或后缀的添加或忽略),可以完成set或者是where标记的功能。
trim属性主要有以下四个:
prefix:在trim标签内sql语句加上前缀
suffix:在trim标签内sql语句加上后缀
prefixOverrides:指定去除多余的前缀内容,如:prefixOverrides=“AND | OR”,去除trim标签内sql语句多余的前缀"and"或者"or"。
suffixOverrides:指定去除多余的后缀内容。
例如在update中
<update id="updateByPrimaryKey" parameterType="Object">
update student set
<trim suffixOverrides=",">
<if test="name != null">
NAME=#{name},
</if>
<if test="hobby != null">
HOBBY=#{hobby},
</if>
</trim>
where id=#{id}
</update>
如果name和hobby的值都不为空的话,会执行如下语句
update student set NAME='XX',HOBBY='XX' /*,*/ where id='XX'
会忽略最后一个“,” ;
sql 标签
当多种类型的查询语句的查询字段或者查询条件相同时,可以将其定义为常量,方便调用。为求 <select> 结构清晰也可将 sql 语句分解。
sql标签负责抽取重复字段,include标签负责在原来抽取的位置再通过include引用进来
<!-- 查询字段 -->
<sql id="Base_Column_List">
ID,MAJOR,BIRTHDAY,AGE,NAME,HOBBY
</sql>
<!-- 查询条件 -->
<sql id="Example_Where_Clause">
where 1=1
<trim suffixOverrides=",">
<if test="id != null and id !=''">
and id = #{id}
</if>
<if test="major != null and major != ''">
and MAJOR = #{major}
</if>
<if test="birthday != null ">
and BIRTHDAY = #{birthday}
</if>
<if test="age != null ">
and AGE = #{age}
</if>
<if test="name != null and name != ''">
and NAME = #{name}
</if>
<if test="hobby != null and hobby != ''">
and HOBBY = #{hobby}
</if>
<if test="sorting != null">
order by #{sorting}
</if>
<if test="sort!= null and sort != ''">
order by ${sort} ${order}
</if>
</trim>
</sql>
include 标签
用于引用定义的常量
<!-- 查询所有,不分页 -->
<select id="selectAll" resultMap="BaseResultMap">
SELECT
<include refid="Base_Column_List" />
FROM student
<include refid="Example_Where_Clause" />
</select>
<!-- 分页查询 -->
<select id="select" resultMap="BaseResultMap">
select * from (
select tt.*,rownum as rowno from
(
SELECT
<include refid="Base_Column_List" />
FROM student
<include refid="Example_Where_Clause" />
) tt
<where>
<if test="pageNum != null and rows != null">
and rownum
<![CDATA[<=]]>#{page}*#{rows}
</if>
</where>
) table_alias
where table_alias.rowno>#{pageNum}
</select>
<!-- 根据条件删除 -->
<delete id="deleteByEntity" parameterType="java.util.Map">
DELETE FROM student
<include refid="Example_Where_Clause" />
</delete>
MyBatis的分页插件
PageHelper: 物理分页, 通过拦截器加 limit 语句进行分页
RowBounds: 逻辑分页,数据量大的时候压力较大
总结:Mybatis的逻辑分页比较简单,简单来说就是取出所有满足条件的数据,然后舍弃掉前面offset条数据,然后再取剩下的数据的limit条。
如何批量插入
-
不使用批处理(Java语句中循环插入),速度很慢,效率低
2.foreach标签
3.使用batch元素进行批量操作
MyBatis 的三种基本 Executor 执行器
1.SimpleExecutor
每执行一次 update 或 select,就开启一个 Statement 对象,用完立刻关闭 Statement 对象。
2.ReuseExecutor
执行 update 或 select,以 sql 作为 key 查找 Statement 对象,存在就使用,不存在就创建,用完后,不关闭 Statement 对象,而是放置于 Map<String, Statement>内,供下一次使用。简言之,就是重复使用 Statement 对象。
3.BatchExecutor
执行 update(没有 select,JDBC 批处理不支持 select),将所有 sql 都添加到批处理中(addBatch()),等待统一执行(executeBatch()),它缓存了多个 Statement 对象,每个 Statement 对象都是 addBatch()完毕后,等待逐一执行 executeBatch()批处理。与 JDBC 批处理相同。作用范围:Executor 的这些特点,都严格限制在 SqlSession 生命周期范围内。
Mybatis配置日志
步骤:
- 在pom文件中导包(log4j)
- 配置log4j.properties
3.配置xml文件的<settings>,注意大小写和空格问题
4.完成
日志的简单使用:
- 在要使用Log4j的类中,导入包import org.apache.log4j.Logger
- 日志对象,参数为当前类的class
Static Logger logger=Logger.getLogger(UserDaoTest.class)
3.日志级别
OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL