目录
简介
MyBatis 是一款优秀的持久层框架,免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
Mybatis 将基本的JDBC常用接口封装,对外提供操作即可。中文官网:https://mybatis.org/mybatis-3/zh/getting-started.htmlhttps://mybatis.org/mybatis-3/zh/getting-started.html
Mybatis环境搭建
1.创建一张表和表对应的实体类
2.导入MyBatis jar包,mysql 数据库驱动包
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.16</version>
</dependency>
3.创建MyBatis全局配置文件
<?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="config.properties"></properties>
<environments default="development">
<environment id="development">
<dataSource type="POOLED">
<property name="driver" value="" />
<property name="url" value="" />
<property name="username" value="" />
<property name="password" value=""/>
</dataSource>
</environment>
</environments>
</configuration>
4.创建sql映射文件
<?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="接口地址">
定义sql语句
</mapper>
5. 定义接口
在接口中定义方法
public interface AdminDao{
}
6.测试MyBatis
(1) 读取配置文件
Reader reader = Resources.getResourceAsReader("mybatis-config.xml");
(2)创建SqlSessionFactory
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(reader);
(3)创建SqlSession
SqlSession sqlSession = sessionFactory.openSession();
(4)获得接口代理对象
sqlSession.getMapper(接口.class);
sqlSession .close();关闭
API接口说明
SqlSessionFactory 接口
使用SqlSessionFactory 来创建 SqlSession,一旦创建 SqlSessionFactory 就 会在整个应用过程中始终存在。
SqlSession 接口
Sqlsession 意味着创建与数据库链接会话,该接口中封装了对数据库操作的方法,与数据库会话完成后关闭会话。
Mybatis-Dao 层 Mapper 接口化开发
Mapper接口开发方式只需要我们编写Mapper接口,由Mybatis框架创建接口的动态代理对象,使用sqlsession.getMapper(接口.class),获得代理对象。
Mapper接口开发条件
(1)Mapper.xml文件中的namespace与mapper接口的类路径相同。
(2)Mapper接口方法名和Mapper.xml中定义的每个statement的id相同。
(3)Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql 的 parameterType 的类型相同。
(4)Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的 resultType 的类型相同。
Mybatis 日志
配置日志
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
参数传递
单个参数直接传递
Admin findAdminByid(int id); <select id="findAdminByid" resultType="Admin" parameterType="int"> select id,account,password,admin_gender from admin where id = #{id} </select>
多个参数使用@Param(“id”)绑定
saveAdmin(@Param("acc") String account, @Param("pwd") String password);
<insert id="saveAdmin"> insert into admin(account,password) values(#{acc},#{pwd}) </insert>
如果传入一个复杂的对象,就需要使用parameterType参数进行类型定义
void saveAdmin1(Admin admin);
<insert id="saveAdmin1" parameterType="Admin"> insert into admin(account,password) values(#{account},#{password}) </insert>
增删改查
增加
<insert id="唯一标识" parameterType="参数类型" useGeneratedKeys="取出数据库中生成的主键" keyColumn="指定主键列id" keyProperty="指定主键对应的属性id">
insert into admin(account,password) values(#{account},#{password})
</insert>
删除
<delete id="唯一标识" parameterType="参数类型">
delete from admin where id= #{id}
</delete>
修改
<update id="唯一标识" parameterType=“参数类型">
update adminsetaccount= #{account},password= #{password} where id= #{id}
</update>
查询
<select id="唯一标识" resultType="返回结果集类型">
select * from admin where id= #{id}
</select>
嵌套查询
将一个多表关联查询拆分为多次查询,先查询主表数据,然后查询关联表数据。
<resultMap id="studentmap" type="Student">
<id column="id" property="id"></id>
<result column="num" property="num"></result>
<result column="name" property="name"></result>
<result column="gender" property="gender"></result>
<association property="dorm" javaType="Dorm" select="findDormByid" column="dormid"></association>
</resultMap>
<select id="findDormByid" parameterType="int" resultType="Dorm">
select num from Dorm where id=#{id}
</select>
column="dormid":关联查询时将 num 列的值传入findDormByid, 并将findDormByid 查询的结果映射到Student的dorm属性中。collection 和 association 都需要配置 select 和 column 属性,两者配置方法相同。
映射
对象映射
如果表中的类名与类中的属性名完全相同,mybatis会自动将查询结果封装到POJO对象中。
如果java中使用标准驼峰命名,数据库中使用下划线连接命名,可以开始全局设置实现自动转换。
private String adminGender;
<setting name="mapUnderscoreToCamelCase" value="true"/>
<select id="findAdminByid" resultType="Admin" parameterType="int">
select id,account,password,admin_gender from admin where id = #{id}
</select>
结果映射
定义resultMap
<resultMap id="userResultMap" type="User">
<id property="id" column="user_id" />
<result property="username" column="user_name"/>
<result property="password" column="hashed_password"/>
</resultMap>
(1)resutlMap 的 id 属性是resutlMap的唯一标识(2)resutlMap 的 id 属性是映射的POJO类(3)id 标签映射主键,result标签映射非主键(4)property 设置 POJO 的属性名称,column映射查询结果的列名称
然后在引用它的语句中设置 resultMap
属性就行了(注意去掉了 resultType
属性)
使用resultMap
<select id="selectUsers" resultMap="userResultMap">
select user_id, user_name, hashed_password
from some_table
where id = #{id}
</select>
多表关联处理结果集
(1)宿舍一方,配置多方集合 宿舍有很多个学生
public class Dorm {
private int id;
private int num;
private List<Student> students;
}
组装查询结果
<resultMap id="dormMap" type="Dorm">
<id column="id" property="id"></id>
<result column="num" property="num"></result>
<!--封装学生集合-->
<collection property="students" javaType="list" ofType="Student">
<result column="name" property="name"></result>
<result column="xuehao" property="num"></result>
</collection>
</resultMap>
<!--查询宿舍列表-->
<select id="findDorms" resultMap="dormMap">
SELECT d.id,d.num,s.name,s.num xuehao FROM dorm d
LEFT JOIN student s ON s.dormid = d.id
</select>
(2)学生多方,在多方配置一方 学生有一个宿舍
public class Student {
private int id;
private int num;
private String name;
private String gender;
private Dorm dorm;
}
<resultMap id="studentmap" type="Student">
<id column="id" property="id"></id>
<result column="num" property="num"></result>
<result column="name" property="name"></result>
<result column="gender" property="gender"></result>
<!--把学生关联的宿舍封装到宿舍对象中去,属于嵌套映射-->
<association property="dorm" javaType="Dorm">
<result column="dnum" property="num"></result>
</association>
</resultMap>
<select id="findStudentByid" resultMap="studentmap" parameterType="int">
SELECT s.id,s.name,s.gender,s.num,d.num dnum FROM student s
LEFT JOIN dorm d ON s.dormid = d.id
WHERE s.id = #{ID}
</select>
Mybatis三种自动映射等级
- NONE - 禁用自动映射。即使是单张表
- PARTIAL - 如果没有嵌套映射,会自动映射结果。如果使用了嵌套映射,所有的都不映射了。是mybatis默认的
- FULL - 自动映射所有属性,无论是否开启嵌套映射。
Mybatis动态SQL
动态 SQL 是 MyBatis 的强大特性之一。如果你使用过 JDBC 或其它类似的框架,你应该能理解根据不同条件拼接 SQL 语句有多痛苦,例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。利用动态 SQL,可以彻底摆脱这种痛苦。
if
<select id="findStudents" resultType="Student" parameterType="Student">
select id,num,name,gender from student
where state = "active"
<if test="num!=0">
and num=#{num}
</if>
<if test="name!=null">
and name=#{name}
</if>
</select>
如果上面没有 state="active",后面num存在,语句就成为 where and 错误
对于查询条件不确定 可以使用where
where
<select id="findStudents" resultType="Student" parameterType="Student">
select id,num,name,gender from student
<where>
<if test="num!=0">
num=#{num}
</if>
<if test="name!=null">
and name=#{name}
</if>
<if test="gender!=null">
or gender = #{gender}
</if>
</where>
</select>
<where>元素会进行判断,如果它包含的标签中有返回值的话,它就插入一个 ‘where’。 此外,如果标签返回的内容是以AND 或OR 开头,它会剔除掉AND或OR。
trim
where 标签,其实用trim 也可以表示,当WHERE后紧随AND或则OR的 时候,就去除AND或者OR。prefix前缀,prefixOverrides覆盖首部指定内容。
<select id="findStudents" resultType="Student" parameterType="Student">
select id,num,name,gender from student
<trim prefix="where" prefixOverrides="and">
<if test="num!=0">
num=#{num}
</if>
<if test="name!=null">
and name=#{name}
</if>
<if test="gender!=null">
or gender = #{gender}
</if>
</trim>
</select>
Choose 元素
它有点像 Java 中的 switch 语句。
比如 传入了 “num” 就按 “num” 查找,传入了 “name” 就按 “name” 查找。若两者都没有传入,就选择gender="女"进行查询。
<select id="findStudents" resultType="Student" parameterType="Student">
select id,num,name,gender from student
<trim prefix="where" prefixOverrides="and">
<choose>
<when test="num!=0">
num=#{num}
</when>
<when test="name!=null">
and name=#{name}
</when>
<otherwise>
and gender = '女'
</otherwise>
</choose>
</trim>
</select>
set元素
set 元素会动态地在行首插入 SET 关键字,并会删掉额外的逗号(这些逗号是在使用条件语句给列赋值时引入的)。
<update id="updateStudent" parameterType="Student">
update student
<set>
<if test="num!=0">
num=#{num},
</if>
<if test="name!=null">
name=#{name},
</if>
<if test="gender!=null">
gender = #{gender}
</if>
</set>
where id = #{id}
</update>
也可以使用trim实现,suffixOverrides覆盖尾部内容
<update id="updateStudent" parameterType="Student">
update student
<trim prefix="set" suffixOverrides=",">
<if test="num!=0">
num=#{num},
</if>
<if test="name!=null">
name=#{name},
</if>
<if test="gender!=null">
gender = #{gender},
</if>
</trim>
where id = #{id}
</update>
foreach元素
主要用在构建in条件中,它可以在SQL语句中对集合进行遍历。在使用foreach的时候最关键的就是collection属性,该属性是必须指定的。
item 表示集合中每一个元素进行迭代时的别名,index指定一个名字,用于表示在迭代过程中,每次迭代到的位置,open表示该语句以什么开始, separator 表示在每次进行迭代之间以什么符号作为分隔符,close表示以什么符号结束。
<delete id="deleteStudent">
delete from student where id in
<!--<foreach collection="array" item="item" open="(" separator="," close=")">
#{item}
</foreach>-->
<foreach collection="list" item="item" open="(" separator="," close=")">
#{item}
</foreach>
</delete>
特殊符号处理
在mybatis中的xml文件中,存在一些特殊的符号,比如:<、>、"、&、<> 等,正常书写mybatis会报错,需要对这些符号进行转义。具体转义如下所示:
特殊字符 转义字符
< <
> >
" "
’ '
& &
还可以使用 <![CDATA[]]> 来包裹特殊字符。
<if test="id != null">
AND <![CDATA[ id <> #{id} ]]>
</if>
mybatis一级缓存二级缓存
为什么使用缓存?
缓存(cache)的作用是为了减去数据库的压力,提高查询性能。缓存实现的原理 是从数据库中查询出来的对象在使用完后不要销毁,而是存储在内存(缓存)中, 当再次需要获取该对象时,直接从内存(缓存)中直接获取,不再向数据库执行 select 语句,从而减少了对数据库的查询次数,因此提高了数据库的性能。
一级缓存
Mybatis 对缓存提供支持,默认开启一级缓存,一级缓存只是相对于同一个SqlSession而言。我们使用同一个SqlSession对象调用一个Mapper方法,往往只执行一次SQL,第一次查询后会将结果封装到SqlSession中,如果没有声明需要刷新,并且缓存没有超时的情况下,第二次执行相同的Sql语句查询, SqlSession 都会取出当前缓存的数据,而不会再次发送SQL到数据库。
清除方式:(1)SqlSession.close(); 关闭SqlSession对象 (2)SqlSession.clearCache();清理数据,对象仍可用。
(3)SqlSession 中执行了任何一个update操作(update()、delete()、 insert()) ,都会清空缓存的数据,但是该对象可以继续使用。
二级缓存
每次查询会先从缓存区域查找,如果找不到则从数据库查询,并将查询到数据写入缓存。
当第一次查询到数据后,关闭SqlSession时将数据存入到二级缓存中。
二级缓存配置
(1)启用二级缓存
在SqlMapperConfig.xml 中启用二级缓存,代码所下,当 cacheEnabled 设置为true时启用二级缓存,设置为false时禁用二级缓存。
<setting name="cacheEnabled" value="true"/>
(2)对象序列化
将所有的POJO类实现序列化接口Java.io.Serializable
(3)配置映射文件
在Mapper映射文件中添加
<cache flushInterval="时间"></cache>
表示此mapper开启二级缓存。当SqlSeesion 关闭时,会将数据存入到二级缓存。