SSM之Mybatis
一、MyBatis简介
实现了操作数据库的JDBC的封装。
1、MyBatis特性
- 持久层框架,支持定制化SQL、存储过程以及高级映射;
- 封装了JDBC以及获取结果集代码
- 可以使用XML或者注解用于配置原始映射,映射成数据库中的记录
- 半自动的ORM(对象关系映射)框架(SQL需要自己写)
2、MyBatis的下载
mybatis的jar包,可以通过maven下载,gihub可以拿到mybatis的官方文档
3、MyBatis和其他持久化层技术对比
Hibernate是全自动的:不需要写SQL语句
MyBatis是半自动的:需要写SQL语句
二、MyBatis框架搭建
第一步:new Module
第二步:在pom.xml中导入依赖jar包
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.zhw.mybatis</groupId>
<artifactId>mybatis2</artifactId>
<version>1.0-SNAPSHOT</version>
<!-- 设置工程的打包方式 -->
<packaging>jar</packaging>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<!-- 导入工程依赖 -->
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<!-- mysql依赖版本要和本地安装的mysql版本一样/或者兼容 -->
<version>8.0.31</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.7</version>
</dependency>
<!-- <dependency>-->
<!-- <groupId>log4j</groupId>-->
<!-- <artifactId>log4j</artifactId>-->
<!-- <version>1.2.12</version>-->
<!-- </dependency>-->
</dependencies>
</project>
第三步:创建mybatis的核心配置文件 resources/mybatis-config.xml
第四步: 创建mybatis的映射文件 resources/com/zhw/mybatis/mapper/*.xml
三、MyBatis基础功能
1、MyBatis核心配置文件 /resources/mybatis-config.xml
jdbc.properties
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/zhw_blog?useSSL=false&serverTimezone=Hongkong&characterEncoding=utf-8&autoReconnect=true
jdbc.username=root
jdbc.password=
<?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?,
settings?,
typeAliases?,
typeHandlers?,
objectFactory?,
objectWrapperFactory?,
reflectorFactory?,
plugins?,
environments?,
databaseIdProvider?,
mappers?
-->
<!--引入properties文件 数据库连接配置抽离出到同级下的jdbc.properties-->
<properties resource="jdbc.properties" />
<!--设置mybatis的全局配置-->
<settings>
<!--设置实体类的驼峰命名和数据库的下划线命名对应-->
<setting name="mapUnderscoreToCamelCase" value="true" />
<!-- 开启延迟加载 -->
<setting name="lazyLoadingEnabled" value="true"/>
</settings>
<typeAliases>
<!-- <typeAlias type="com.zhw.mybatis.pojo.User" alias="User" />-->
<!-- 以包为单位 将包下所有的类设置为别名为类名 且不区分大小写 -->
<package name="com.zhw.mybatis.pojo"/>
</typeAliases>
<!-- environments: 配置多个连接数据库的环境
default:根据环境id 设置默认使用哪个数据库环境
-->
<environments default="development">
<environment id="development">
<!--
transactionManager: 设置事务管理方式
type: JDBC/MANAGED
JDBC: 表示当前环境中,执行SQL时,使用的是JDBC中原生的事务管理方式,即是:事务的提交或者回滚需要手动处理;
MANAGED: 被管理。例如spring中的AOP
-->
<transactionManager type="JDBC"/>
<!--
dataSource: 设置数据源
type: POOLED/UNPOOLED/JNDI
POOLED: 表示使用数据库连接池缓存数据库连接
UNPOOLED: 不使用数据库连接池
JNDI: 表示使用上下文中的数据源
-->
<dataSource type="POOLED">
<!-- 数据库驱动-->
<property name="driver" value="${jdbc.driver}"/>
<!-- 数据库地址-->
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<!-- <mapper resource="mappers/UserMapper.xml"/> -->
<!--
以包为单位引入映射文件: 多级目录的创建 com/zhw/mybatis/mapper
要求:
1、mapper接口所在包要和映射文件所在包一致【层次和名字】
2、mapper接口要和映射文件的名字一致
-->
<package name="com.zhw.mybatis.mapper"/>
</mappers>
</configuration>
2、MyBatis映射文件
<?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">
namespace
<!--namespace: mapper接口所在的全类名-->
<mapper namespace="com.zhw.mybatis.mapper.UserMapper">
<!--selectUser: mapper接口里的抽象方法-->
<select id="selectUser" resultType="com.zhw.mybatis.pojo.User">
select * from sys_user where id = 1
</select>
</mapper>
3、MyBatis实现增删改查
查: 需要指定resultType 实体类型
resultMap: 自定义字段名和属性名不一致时
<select id="selectUser" resultType="实体类型对象全类名">
select * from sys_user where id = 1
</select>
4、MyBatis获取参数值的两种方式
1、${} 本质字符串拼接【需要程序员手动添加单引号】
会有SQL注入的风险 不推荐
<select id="getUserByUserName" resultType="User">
select * from sys_user where del_flag = 0 and user_name = '${userName}' // 【需要程序员手动添加单引号】
</select>
2、#{} 本质占位符赋值,会默认加单引号
<select id="getUserByUserName" resultType="User">
select * from sys_user where del_flag = 0 and user_name = #{userName}
</select>
3、mybatis获取参数值的各种情况
3.4、实参是实体类
传递的是实体类,直接通过属性名占位获取
3.1、通过@param注解命名参数
传的是String, mapperXml接收的是Map集合,且是 以@param注解的值为键
// UserMapper接口里
User checkoutLogin(@Param("userName") String userName, @Param("password")String password);
// SqlSession
User user = mapper.checkoutLogin("mysql", "123456");
<select id="checkoutLogin" resultType="User">
select * from sys_user where del_flag = 0 and user_name = #{userName} and password = #{password}
</select>
5、MyBatis执行特殊SQL语句
5.1、模糊查询
select * from sys_user where user_name like "%"#{userName}"%"
5.2、批量删除
批量删除不能使用#{}. 因为#{}会默认添加单引号,从而导致批量删除SQL语句报错
delete from sys_user where id in (${ids})
delete from sys_user where id in (1,2,3) // 对
delete from sys_user where id in ('1,2,3') // 错误
5.3、获取是自增主键的新增的数据
<!-- useGeneratedKeys: 标记当前sql操作的数据表,使用了自增主键 -->
<!-- keyProperty:值为数据表中的自增主键的的属性 -->
<insert id="insertUser" useGeneratedKeys="true" keyProperty="id">
</insert>
6、MyBatis自定义映射resultMap
分步查询的优点:可以实现延迟加载(即是分步时,可以只是获取其中一个表的数据,关联表的数据不获取)
6.1、通过分步查表,解决多对一的属性字段映射关系
<!-- 多个员工对应一个部门 -->
<resultMap id="deptMap" type="Employee">
<id property="id" column="id"></id>
<result property="userName" column="user_name"></result>
<result property="password" column="password"></result>
<!-- select:分步查询sql的唯一标识namespace.SQLId / mapper接口的全类名.方法名 -->
<!-- column:分步查询sql的条件 -->
<!-- fetchType: 当开启了全局延迟加载后,可以通过该属性控制延迟加载的效果 -->
<association property="dept"
select="com.zhw.mybatis.mapper.SelectMapper.getAllUser"
column="dept_id"
fetchType="lazy"
></association>
</resultMap>
6.2、通过分步查询表,解决一对多的属性字段映射关系
<!-- 一个部门对应多个员工 -->
<resultMap id="deptMap" type="Dept">
<id property="id" column="id"></id>
<result property="userName" column="user_name"></result>
<result property="password" column="password"></result>
<association property="emps"
select="com.zhw.mybatis.mapper.SelectMapper.getAllUser"
column="dept_id"
fetchType="lazy"
></association>
</resultMap>
7、MyBatis的动态Sql
使用xml标签,根据不同条件,拼接sql语句
7.1、if标签
if标签中的test属性所对应的表达式决定标签中的内容是否需要拼接到SQL中
<select id="selectUserByParams" resultType="User">
# 1 = 1: 恒成立条件 为了拼接后面的and条件,避免某个为空造成的SQL语法错误
select * from sys_user where 1 = 1
<if test="userName != null and userName != ''">
and user_name = #{userName}
</if>
<if test="password != null password age != ''">
and password = #{password}
</if>
</select>
7.2、where标签
当where标签中有内容时,会自动生成where关键字,并且将sql语句前多余的and或者or去掉
当where标签中没有内容时,此时where不会解析到SQL语句中
注意: where标签不能将sql语句后面多余的and或者or去掉, 只能去掉前面的
<select id="selectUserByParams" resultType="User">
select * from sys_user
<where>
<if test="userName != null and userName != ''">
and user_name = #{userName}
</if>
<if test="password != null password age != ''">
or password = #{password}
</if>
</where>
</select>
7.3、trim标签
当trim标签中有内容时:
prefix|suffix: 将拼接语句的前面或者后面添加指定内容
suffixOverrides|prefixOverrides:将拼接的sql语句中的前面后面指定的内容去掉
当trim标签中没有内容时,trim标签无任何效果,即是不会被解析到sql语句中
<select id="selectUserByParams" resultType="User">
select * from sys_user
<trim prefix="where" suffixOverrides="and|or">
<if test="userName != null and userName != ''">
and user_name = #{userName}
</if>
<if test="password != null password age != ''">
and password = #{password}
</if>
</trim>
</select>
7.4、choose、when、otherwise 相当于 if…else if…else
<select id="selectUserByParams" resultType="User">
select * from sys_user
<where>
<choose>
<when test="userName != null and userName != ''">
user_name = #{userName}
</when>
<when test="password != null and password != ''">
password = #{password}
</when>
<otherwise></otherwise>
</choose>
</where>
</select>
7.5、foreach标签
根据or关键字或者in关键字,接收数组,批量删除
批量新增数据
7.6、sql标签:存储sql片段
四、MyBatis的分页插件
五、MyBatis的逆向工程
通过配置插件将数据库表逆向的映射成实体类、mapper配置和mapper接口
六、MyBatis的缓存
缓存只针对查询操作
1、mybatis的一级缓存
mybatis的一级缓存是默认开启的,级别是SqlSession。同一个SqlSession的相同查询条件,只会执行一次SQL语句,后面都会从缓存中获取的,不会再次访问数据库的。
1.1、使一级缓存失效的四种情况
- 不同的SqlSession对应不同的一级缓存
- 同一个SqlSession但是查询条件不同
- 同一个SqlSession两次查询期间执行了任何一次的增删改操作
- 同一个SqlSession两次查询期间手动清空了缓存。sqlSession.clearCache()
2、mybatis的二级缓存
mybatis的二级缓存是默认关闭的。级别是SqlSessionFactory,比一级缓存的级别大。即是:通过同一个SqlSessionFactory创建的sqlSession查询的都会被缓存
2.1 、二级缓存开启的必须条件,缺一不可
- 在核心配置文件中,设置全局配置属性cacheEnabled=“true”,默认为true,所以不需要手动设置了
- 在映射文件中设置标签
- 必须手动关闭/提交sqlSession
- 需要缓存的实体类必须实现序列化接口
2.2、 二级缓存失效情况
- 两次查询之间执行了任意的增删改,会使一级和二级缓存同时失效