MyBatis简介
- MyBatis前身是iBatis,本是Apache的一个开源的项目。
- 官方网站:http://mybatis.org
- ORM框架
- 实体类和SQL语句之间建立映射关系。
- 特点:
基于SQL语法,简单易学。
能了解底层封装过程。
SQL语句封装在配置文件中,便于统一管理与维护,降低程序的耦合度。
方便程序代码调试。
搭建MyBatis开发环境
- 下载Mybatis-3.4.2.jar包并导入工程.
- 编写MyBatis核心配置文件(configuration.xml)
- 创建实体类-POJO
- 编写DAO层-SQL映射文件(mapper.xml)
- 创建测试类
- 读取核心配置文件mybatis-config.xml
- 通过SqlSessionFactoryBuilder类的build()方法读取配置文件,创建SqlSessionFactory对象。
- 通过SqlSessionFactory类的openSession()方法创建SqlSession对象。
- 调用mapper文件进行数据操作。
工具类代码示例:
public class MyBatisUtil {
private static SqlSessionFactory factory = null;
static {
try {
// 1. 声明总配置文件的位置
String resource = "mybatis-config.xml";
// 2. 使用输入流读取总配置文件
InputStream is = Resources.getResourceAsStream(resource);
// 3. 根据读取的内容创建一个SqlSessionFactory对象
factory = new SqlSessionFactoryBuilder().build(is);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 返回一个SqlSession对象
* @return
*/
public static SqlSession getSqlSession(){
// 4. 根据SqlSessionFactory对象创建SqlSession对象(参数为true开启自动事务提交,默认为false)
SqlSession sqlSession = factory.openSession(true);
return sqlSession;
}
}
- 核心接口和类的结构
核心对象
SqlSessionFactoryBuilder
- 用过即丢,其生命周期只存在于方法体内
- 可重用其来创建多个 SqlSessionFactory 实例
- 负责构建SqlSessionFactory,并提供多个build方法的重载
SqlSessionFactory
- SqlSessionFactory是每个MyBatis应用的核心
- 作用:创建SqlSession实例
- SqlSession session = sqlSessionFactory.openSession(boolean autoCommit);
- true:开启事务自动提交
- false:关闭事务控制(默认)
- 作用域:Application
- 生命周期与应用的生命周期相同
- 单例:存在于整个应用运行时,并且同时只存在一个对象实例
SqlSession
- 包含了执行SQL所需的所有方法
- 对应一次数据库会话,会话结束必须关闭(close())
- 线程级别,不能共享
- 在SqlSession里可以执行多次SQL语句,但一旦关闭了SqlSession就需要重新创建.
- SqlSession的两种使用方式
- 通过SqlSession实例直接运行映射的SQL语句
- 基于Mapper接口方式操作数据
系统核心配置文件
mybatis-config.xml 系统核心配置文件
特别需要注意节点之间的顺序,顺序错了会引起报错。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 引入外部的数据库连接配置文件 -->
<properties resource="jdbc.properties" />
<!-- 设置标签 -->
<settings>
<!--开启驼峰命名规则-->
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
<!-- 定义实体类的别名,该包下的所有实体类名默认首字母小写为其别名,或者通过在类上边加@Alias()注解进行自定义 -->
<typeAliases>
<package name="com.zanya.entity"/>
</typeAliases>
<!-- 上边properties 标签定义数据库文件名 ,这里可以读取配置信息进行配置,可以配置多套,通过default和id属性选择需要使用那一套配置-->
<environments default="development">
<environment id="development">
<!--使用JDBC事务管理-->
<transactionManager type="JDBC" />
<!--配置数据库连接信息,可以直接配置,也可以通过外部配置文件通过properties标签配置,然后引入-->
<dataSource type="POOLED">
<property name="driver" value="${driverClassName}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<!-- 定义映射器,找到Dao接口对应Mapper.xml文件,如果有多个可以通过另外一个 package 配置包扫描-->
<mappers>
<mapper resource="com/zanya/dao/EduUserMapper.xml"></mapper>
</mappers>
</configuration>
SQL映射的XML文件
- MyBatis 真正的强大在于映射语句,专注于SQL,功能强大,SQL映射的配置却是相当简单
- SQL映射文件的几个顶级元素(按照定义的顺序)
- mapper – namespace
- cache – 配置给定命名空间的缓存
- cache-ref – 从其他命名空间引用缓存配置
- resultMap –用来描述数据库结果集和对象的对应关系
- sql – 可以重用的SQL块,也可以被其他语句引用
- insert – 映射插入语句
- update – 映射更新语句
- delete – 映射删除语句
- select – 映射查询语句
简单的代码示例:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- 对应的接口的全限定名 -->
<mapper namespace="com.zanya.dao.EduUserDao">
<!-- 查询:id属性对应接口的方法名,通过namespace+id就可以找到对应的方法,resultType返回值类型,user是我们起的别名 -->
<select id="getAllUser" resultType="user">
SELECT USER_ID , MOBILE , USER_NAME , AGE , SEX FROM edu_user
</select>
<!--
id自增长中id的映射、不需要时可以不写
useGeneratedKeys="true"
keyProperty="userId"
-->
<insert id="insert" useGeneratedKeys="true" keyProperty="userId">
insert into edu_user(MOBILE , USER_NAME , AGE) values (#{mobile} , #{userName} , #{age})
</insert>
</mapper>
mapper
- namespace:命名空间
- namespace和子元素的id联合保证唯一,区别不同的mapper
- 绑定DAO接口
- namespace的命名必须跟某个接口同名
- 接口中的方法与映射文件中SQL语句id一一对应
select标签
- id属性
- 命名空间中唯一的标识符
- 接口中的方法与映射文件中的SQL语句id一一对应
- parameterType属性
- 传入SQL语句的参数类型(默认只能传入一个参数,但可以通过在接口中的方法形参处通过注解的方式实现多个参数的传入:@Param())
- resultType属性
- SQL语句返回值类型的完整类名或别名
- resultMap :对外部resultMap的引用
- 应用场景:
数据库字段信息与对象属性不一致
复杂的联合查询,自由控制映射结果
- 应用场景:
- resultType和resultMap 不能同时存在,本质上都是Map数据结构
select小结
insert
- id:标识
- parameterType:参数类型
insert、update、delete元素均没有resultType属性
resultMap
resultMap属性
- id:resultMap的唯一标识
- type:Java实体类
- resultMap子元素
- id:一般对应数据库中该行的主键id,设置此项可提高MyBatis性能
- result:映射到JavaBean的某个“简单类型”属性
- association:映射到JavaBean的某个“复杂类型”属性,比如JavaBean类
- collection:映射到JavaBean的某个“复杂类型”属性,比如集合
- association
- 复杂的类型关联,一对一
- 内部嵌套:映射一个嵌套JavaBean属性
- 属性
- property:映射数据库列的实体对象的属性
- javaType:完整Java类名或者别名
- resultMap:引用外部resultMap
- 子元素
- id
- result
- property:映射数据库列的实体对象的属性
- column:数据库列名或者别名
- collection
- 复杂类型集合,一对多
- 内部嵌套
- 映射一个嵌套结果集到一个列表
- 属性
- property:映射数据库列的实体对象的属性
- ofType:完整Java类名或者别名(集合所包括的类型)
- resultMap:引用外部resultMap
- 子元素
- id
- result
- property:映射数据库列的实体对象的属性
- column:数据库列名或者别名
MyBatis缓存
- 一级缓存
- 二级缓存
二级缓存
- MyBatis的全局cache配置
<settings>
<setting name="cacheEnabled" value="true"/>
</settings>
- 在Mapper XML文件中设置缓存,默认情况下是没有开启缓存的
<cache eviction="FIFO" flushInterval="60000" size="512" readOnly="true"/>
- 在Mapper XML文件配置支持cache后,如果需要对个别查询进行调整,可以单独设置cache
<select id="selectAll" resultType="Emp" useCache="true">
动态SQL
- 基于OGNL表达式
- 完成多条件查询等逻辑实现
- 用于实现动态SQL的元素主要有:
- if
- trim
- where
- set
- choose(when、otherwise)
- foreach
if、where标签
- 民间写法
<select>
select * from ems_employees t1
where 1=1
<if test=”name != null”>
and name = #{name}
</if>
<if test=”age != 0”>
and age = #{age}
</if>
</select>
- 官方写法 if+where
- where:简化SQL语句中where条件判断,智能处理and和or
-where”标签会知道如果它包含的标签中有返回值的话,它就插入一个‘where’。此外,如果标签返回的内容是以AND 或OR 开头的,则它会剔除掉。
<select>
select * from ems_employees t1
<!--可以根据里面是否有条件决定是否生成where关键字-->
<where>
<!-- 如果是第一个条件,会自动去掉and -->
<if test=”name != null”>
and name = #{name}
</if>
<if test=”age != 0”>
and age = #{age}
</if>
</where>
</select>
if、set标签
<update id="updateId" parameterType="com.zany.pojo.User">
update user u
<set>
<if test="username != null and username != ''">
u.username = #{username},
</if>
<if test="sex != null and sex != ''">
u.sex = #{sex}
</if>
</set>
where id=#{id}
</update>
- 这样写,如果某个 if 条件为false,则会自动去掉当前值的修改。例如: username 为空, sql 语句为:update user u set u.sex=? where id=?。如果不为空就正常执行。
choose(when,otherwise) 语句
- 相当于Java中switch语句
- 当when有条件满足的时候,就跳出choose,都不满足时执行otherwise标签内的代码
- 语法:
-
<choose> <when test ="条件1"> …</when> <when test ="条件2"> …</when> <when test ="条件3"> …</when> … <otherwise>…</otherwise> </choose>
代码示例:
<select id="selectUser" resultType="com.zany.pojo.User" parameterType="com.zany.pojo.User">
select * from user
<where>
<choose>
<when test="id !='' and id != null">
id=#{id}
</when>
<when test="username !='' and username != null">
and username=#{username}
</when>
<otherwise>
and sex=#{sex}
</otherwise>
</choose>
</where>
</select>
trim 语句
- trim标记是一个格式化的标记,可以完成set或者是where标记的功能
- 属性
- prefix:前缀
- suffix:后缀
- prefixOverrides:去掉第一个and或是or
- suffixOverrides:去掉最后一个逗号,当然也可以是其他标记
- 更灵活地去除多余关键字
- 替代where和set
- 示例:
<update id ="modify" parameterType="User">
update user
<trim prefix="set" suffixOverrides="," suffix="where id = #{id}">
<if test="userCode != null">
userCode = #{userCode},
</if>
<if test="userName!= null">
userCode = #{userName },
</if>
<if test="userPassword!= null">
userPassword=#{userPassword },
</if>
</trim>
</update>
foreach 语句
- 迭代一个集合,通常用于in条件
- 属性
- item:每次遍历生成的对象
- index:表示在迭代过程中,每次迭代到的位置
- collection:(必须指定)指定输入对象中的集合属性,主要有以下 3 种情况:
- list:表示传入一个List集合
- array:表示传入一个数组
- map-key:表示传入一个Map
- open:开始遍历时的拼接字符串
- separator:遍历对象之间需要拼接的字符串
- close:结束时拼接的字符串
- 示例:
<!-- select * from user where id in (1,2,3) 如下所示:-->
<select id="selectUserByListId" parameterType="com.zany.pojo.User" resultType="com.zany.pojo.User">
select * from user
<where>
<foreach collection="array" item="id" open="and id in (" close=") " separator=",">
#{id}
</foreach>
</where>
</select>
SQL 片段
- 有时候可能某个 sql 语句我们用的特别多,为了增加代码的重用性,简化代码,我们需要将这些代码抽取出来,然后使用时直接调用。
- 定义SQL片段
<!-- 定义 sql 片段 -->
<sql id="selectUserOne">
<if test="username != null and username != ''">
AND username = #{username}
</if>
<if test="sex != null and sex != ''">
AND sex = #{sex}
</if>
</sql>
- 引用SQL片段
<select id="selectUserBy" resultType="user" parameterType="com.zany.pojo.User">
select * from user
<trim prefix="where" prefixOverrides="and | or">
<!-- 引用 sql 片段,如果refid 指定的不在本文件中,那么需要在前面加上 namespace -->
<include refid="selectUserOne"></include>
<!-- 在这里还可以引用其他的 sql 片段 -->
</trim>
</select>
- 注意:
- 最好基于 单表来定义 sql 片段,提高片段的可重用性
- 在 sql 片段中最好不要包括 where