一、快速入门
1、导入依赖
<dependencies>
<!-- mybatis依赖 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.11</version>
</dependency>
<!-- MySQL驱动 mybatis底层依赖jdbc驱动实现,本次不需要导入连接池,mybatis自带! -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.25</version>
</dependency>
<!--junit5测试-->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.3.1</version>
</dependency>
</dependencies>
2、创建实体类
public class Employee {
private Integer empId;
private String empName;
private Double empSalary;
//getter | setter
}
3、准备一个mapper接口
public interface EmployeeMapper {
Employee queryById(Integer id);
void deleteById(Integer id);
}
准备mapper.xml文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- namespace等于mapper接口类的全限定名,这样实现对应 -->
<mapper namespace="com.triticale.mapper.EmployeeMapper">
<!--声明标签写sql语句 crud select insert update delete
每个标签对应接口的一个方法,方法的一个实现
注意:mapper接口不能重载,因为mapper.xml无法识别,根据方法名识别
-->
<select id="queryById" resultType="com.triticale.pojo.Employee">
select emp_id empId,emp_name empName, emp_salary empSalary from
t_emp where emp_id = #{id}
</select>
<delete id="deleteById">
delete from t_emp where emp_id = #{id}
</delete>
</mapper>
4、准备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>
<!-- environments表示配置Mybatis的开发环境,可以配置多个环境,在众多具体环境中,使用default属性指定实际运行时使用的环境。default属性的取值是environment标签的id属性的值。 -->
<environments default="development">
<!-- environment表示配置Mybatis的一个具体的环境 -->
<environment id="development">
<!-- Mybatis的内置的事务管理器 -->
<transactionManager type="JDBC"/>
<!-- 配置数据源 -->
<dataSource type="POOLED">
<!-- 建立数据库连接的具体信息 -->
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis-example"/>
<property name="username" value="root"/>
<property name="password" value="yaojinlun"/>
</dataSource>
</environment>
</environments>
<mappers>
<!-- Mapper注册:指定Mybatis映射文件的具体位置 -->
<!-- mapper标签:配置一个具体的Mapper映射文件 -->
<!-- resource属性:指定Mapper映射文件的实际存储位置,这里需要使用一个以类路径根目录为基准的相对路径 -->
<!-- 对Maven工程的目录结构来说,resources目录下的内容会直接放入类路径,所以这里我们可以以resources目录为基准 -->
<mapper resource="mappers/EmployeeMapper.xml"/>
</mappers>
</configuration>
5、使用mybatis api进行数据库查找即可
@Test
public void test_01() throws IOException {
//1.读取外部配置文件
InputStream ips = Resources.getResourceAsStream("mybatis-config.xml");
//2.创建sqlSessionFactory
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(ips);
//3.根据sqlSessionFactory创建sqlSession(每次业务创建一个,用完就释放)
SqlSession sqlSession = sqlSessionFactory.openSession();
//4.获取接口的代理对象,调用代理对象的方法,就会查找mapper接口的方法
EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
Employee employee = mapper.queryById(1);
System.out.println(employee.toString());
//5.提交事务(非DQL)释放资源
sqlSession.close();
}
二、MyBatis基本使用
2.1 #{} 和 ${}的区别
#{key} : 占位符 + 赋值 相当于 emp_id = ? , ? = 赋值
${key} : 字符串拼接 相当于 "emp_id = " + id
推荐使用#{key},防止 注入攻击 的问题
总结: 如动态的列名 容器名 关键字,使用 ${key}
动态值 使用#{key}
比如 select * from 表 where ${columnName} = #{columnValue}
2.2 数据输入
-
简单类型(只包含一个值的数据类型)
传入的单个简单类型的key 随便写, 一般情况下推荐使用参数名
<select id="queryById" resultType="com.triticale.pojo.Employee">
select emp_id as empId, emp_name as empName, emp_salary as empSalary
from t_emp where emp_id = #{id}
</select>
<delete id="deleteById">
delete from t_emp
where emp_id = #{id}
</delete>
<select id="queryBySalary" resultType="com.triticale.pojo.Employee">
select emp_id as empId, emp_name as empName, emp_salary as empSalary
from t_emp where emp_salary = #{salary}
</select>
-
单个实体对象传入
key = 对象属性名即可
<insert id="insertEmp">
insert into t_emp(emp_name, emp_salary) values(#{empName},#{empSalary});
</insert>
-
传入多个简单值
方案1:注解指定 @Param注解 指定多个简单参数的key
List<Employee> queryByNameAndSalary(@Param("name") String name, @Param("salary") Double salary)
<select id="queryByNameAndSalary" resultType="com.triticale.pojo.Employee">
select emp_id as empId, emp_name as empName, emp_salary as empSalary
from t_emp where emp_name = #{name} and emp_salary = #{salary}
</select>
方案2:mybatis默认机制
arg0, arg1 … 形参从左到右依次对应
或者param1,param2 … 形参从左到右依次对应
<select id="queryByNameAndSalary" resultType="com.triticale.pojo.Employee">
select emp_id as empId, emp_name as empName, emp_salary as empSalary
from t_emp where emp_name = #{agr0} and emp_salary = #{agr1}
</select>
- map类型传入
//插入员工数据,传入的是一个map,key为(name=员工的名字,salary=员工的薪水)
int insertEmpMap(Map data);
<insert id="insertEmpMap">
insert into t_emp(emp_name ,emp_salary) values(#{name},#{salary});
</insert>
2.3 数据输出
如果是DML语句,返回值均为int
查询语句指定输出类型
resultType语法:
类的全限定符号
别名简称
mybatis给我们提供了72种默认的别名
这些都是我们常用的Java数据类型,如果没有提供需要自己定义或者写类的全限定名
<select id="queryNameById" resultType="java.lang.String">
select emp_name from t_emp where emp_id = #{id}
</select>
<select id="querySalaryById" resultType="double">
select emp_salary from t_emp where emp_id = #{id}
</select>
扩展:给自己声明的类定义别名
- 给类单独定义别名
在config文件中,位置放在的下面
- 也可以批量设置
这样该包下的所有类都会设置别名,别名是类的首字母小写
- 批量设置后再单独给类设置别名,使用注解
@Alias(“suibian”)
-
单个实体类型输出
返回单个实体类型,要求列名和属性名要一致!
这样才可以进行实体类的属性映射
但是可以进行设置,设置支持驼峰式自动映射
<setting name="mapUnderscoreToCamelCase" value="true"/>
-
map类型输出
<select id="selectEmpNameAndMaxSalary" resultType="map">
select emp_name, emp_salary,(select avg(emp_salary) from t_emp from t_emp where emp_salary = (select max(emp_salary) from t_emp)) from t_emp
</select>
- 返回List类型
List<String> queryNamesBySalary(Double salary);
List<Employee> queryAll();
返回值是集合的话,resultType不需要指定集合类型,只需要指定范型即可
<select id="queryNamesBySalary" resultType="string">
select emp_name from t_emp whre emp_salary > #{salary}
</select>
<select id="queryAll" resultType="com.triticale.pojo.Employee">
select * from t_emp
</select>
2.4 自增长主键回显
在一个主键自增长的表中,如果插入数据并且想拿到该数据对应的主键值,可以在mapper.xml文件中对应的标签中添加三个属性
<insert id="insertEmp" useGeneratedKeys="true" keyColumn="emp_id" keyProperty="empId">
insert into t_emp(emp_name,emp_salary)
values(#{empName},#{empSalary});
</insert>
其中,useGeneratedKeys=“true” 我们想要数据库自动增加的主键值
keyColumn=“emp_id” 数据库主键列的值
keyProperty=“empId” 接收主键列值的属性
2.5 非自增长主键回显
在一个非主键自增长的表中,比如主键为UUID,我们也可以将维护主键的工作交给mybatis
<insert id="insertTeacher">
<selectKey order="BEFORE" resultType="string" keyProperty="tId">
select replace(uuid(),'-','');
</selectKey>
insert into teacher(t_id, t_name) values(#{tId},#{tName});
</insert>
其中,order=“before|after” sql语句是在插入语句之前还是之后执行
resultType = 返回值类型
keyProperty = 查询结果给哪个属性赋值
2.6 自定义映射关系
在select标签中,我们通过指定resultType属性以及开启驼峰映射可以实现单层的映射关系
但是如果在多表查询中,单层映射关系显然不能满足需求
我们可以通过标签和 标签中的resultMap属性来完成自定义映射
<resultMap id="tMap" type="teacher">
<id column="t_id" property="tId"/>
<result column="t_name" property="tName"/>
</resultMap>
<select id="queryTeacher" resultMap="tMap">
select * from tercher where t_id = #{tId}
</select>
resultMap标签中,id 是主键映射关系
result 是普通列的映射关系
三、MyBatis多表映射
3.1 对一查询实现
在实体类中添加查询元素的对象
public class Order {
private Integer orderId;
private String orderName;
private Integer customerId;
private Customer customer;
}
使用标签
<resultMap id="orderMap" type="order">
<id column="order_id" property="orderId"/>
<result column="order_name" property="orderName"/>
<result column="customer_id" property="customerId"/>
<association property="customer" javaType="customer">
<id column="customer_id" property="customerId"/>
<result column="customer_name" property="customerName"/>
</association>
</resultMap>
<select id="queryOrderById" resultMap="orderMap">
select * from t_order as tor
join t_customer as tur
on tor.customer_id = tur.customer_id
where tor.order_id = #{id};
</select>
中的property是在当前实体类中用来建立关联关系的属性名
javaType是被关联的实体类类型全类名
3.2 对多查询实现
在实体类中添加查询元素的集合
public class Customer {
private Integer customerId;
private String customerName;
private List<Order> orderList;
}
使用标签
<resultMap id="customerMap" type="customer">
<id column="customer_id" property="customerId"/>
<result column="customer_name" property="customerName"/>
<collection property="orderList" ofType="order">
<id column="order_id" property="orderId"/>
<result column="order_name" property="orderName"/>
<result column="customer_id" property="customerId"/>
</collection>
</resultMap>
<select id="queryList" resultMap="customerMap">
select * from t_order as tor join t_customer tur
on tor.customer_id = tur.customer_id;
</select>
中的property是在当前实体类中用来建立关联关系的属性名
ofType是被关联的实体类类型全类名
3.3 多表映射优化
setting属性 | 属性含义 | 可选值 | 默认值 |
---|---|---|---|
autoMappingBehavior | 指定 MyBatis 应如何自动映射列到字段或属性。 NONE 表示关闭自动映射;PARTIAL 只会自动映射没有定义嵌套结果映射的字段。 FULL 会自动映射任何复杂的结果集(无论是否嵌套)。 | NONE, PARTIAL, FULL | PARTIAL |
我们可以将autoMappingBehavior设置为full,进行多表resultMap映射的时候,可以省略符合列和属性命名映射规则(列名=属性名,或者开启驼峰映射也可以自定映射)的result标签!
<resultMap id="teacherMap" type="teacher">
<id property="tId" column="t_id" />
<!-- 开启自动映射,并且开启驼峰式支持!可以省略 result!-->
<!-- <result property="tName" column="t_name" />-->
<collection property="students" ofType="student" >
<id property="sId" column="s_id" />
<!-- <result property="sName" column="s_name" />-->
</collection>
</resultMap>
四、MyBatis动态语句
4.1 if和where标签
<select id="query" resultType="employee">
select * from t_emp
<where>
<if test="name != null">
emp_name = #{name}
</if>
<if test="salary != null">
and emp_salary > #{salary}
</if>
</where>
</select>
如果传入属性,就判断相等,如果不传入,不加对应的条件
if 判断传入的参数,最终是否添加语句
test属性,内部做比较运算,最终true将标签内的sql语句进行拼接
false则不拼接
where标签的作用有两个:
1、自动添加where关键字,where内部有任何一个if满足,自动添加where关键字,不满足去掉where
2、自动去掉多余的and 和 or关键字
4.2 set标签
<update id="updateEmployeeDynamic">
update t_emp
<!-- set emp_name=#{empName},emp_salary=#{empSalary} -->
<!-- 使用set标签动态管理set子句,并且动态去掉两端多余的逗号 -->
<set>
<if test="empName != null">
emp_name=#{empName},
</if>
<if test="empSalary < 3000">
emp_salary=#{empSalary},
</if>
</set>
where emp_id=#{empId}
<!--
第一种情况:所有条件都满足 SET emp_name=?, emp_salary=?
第二种情况:部分条件满足 SET emp_salawo ry=?
第三种情况:所有条件都不满足 update t_emp where emp_id=?
没有set子句的update语句会导致SQL语法错误
-->
</update>
set标签可以 1、自动去掉多余的 ,
2、自动添加set关键字
4.3 trim标签
使用trim标签控制条件部分两端是否包含某些字符
- prefix属性:指定要动态添加的前缀
- suffix属性:指定要动态添加的后缀
- prefixOverrides属性:指定要动态去掉的前缀,使用“|”分隔有可能的多个值
- suffixOverrides属性:指定要动态去掉的后缀,使用“|”分隔有可能的多个值
4.4 choose/when/otherwise 标签
在多个分支条件中,仅执行一个。
- 从上到下依次执行条件判断
- 遇到的第一个满足条件的分支会被采纳
- 被采纳分支后面的分支都将不被考虑
- 如果所有的when分支都不满足,那么就执行otherwise分支
<!-- List<Employee> selectEmployeeByConditionByChoose(Employee employee) -->
<select id="selectEmployeeByConditionByChoose" resultType="com.atguigu.mybatis.entity.Employee">
select emp_id,emp_name,emp_salary from t_emp
where
<choose>
<when test="empName != null">emp_name=#{empName}</when>
<when test="empSalary < 3000">emp_salary < 3000</when>
<otherwise>1=1</otherwise>
</choose>
<!--
第一种情况:第一个when满足条件 where emp_name=?
第二种情况:第二个when满足条件 where emp_salary < 3000
第三种情况:两个when都不满足 where 1=1 执行了otherwise
-->
</select>
4.5 foreacn 标签
批量操作时使用
<select id="queryBatch" resultType="employee">
select * from t_emp
where emp_id in
<foreach collection="ids" open="(" close=")" separator="," item="id">
#{id}
</foreach>
</select>
<delete id="deleteBatch">
delete from t_emp where id in
<foreach collection="ids" open="(" close=")" separator="," item="id">
#{id}
</foreach>
</delete>
<insert id="insertBatch">
insert into t_emp(emp_name, emp_salary)
values
<foreach collection="list" separator="," item="employee">
(#{employee.empName},#{employee.empSalary})
</foreach>
</insert>
<update id="updateBatch">
<foreach collection="list" item="employee">
update t_emp set emp_name = #{employee.empName}, emp_salary = #{employee.empSalary}
where emp_id = #{employee.empId};
</foreach>
</update>
批量更新时需要注意
上面批量插入的例子本质上是一条SQL语句,而实现批量更新则需要多条SQL语句拼起来,用分号分开。也就是一次性发送多条SQL语句让数据库执行。此时需要在数据库连接信息的URL地址中设置:
atguigu.dev.url=jdbc:mysql:///mybatis-example?allowMultiQueries=true
4.6 sql片段
抽取重读的SQL片段
<!-- 使用sql标签抽取重复出现的SQL片段 -->
<sql id="mySelectSql">
select emp_id,emp_name,emp_age,emp_salary,emp_gender from t_emp
</sql>
引用已抽取的SQL片段
<!-- 使用include标签引用声明的SQL片段 -->
<include refid="mySelectSql"/>
五、高级扩展
5.1 Mapper 批量映射优化
在配置文件中的标签中添加 标签 属性name指定包
在resources中创建相同结构的文件夹
注意:resources下直接创建多层文件夹使用 / 分割,如果用.分割则是一层文件夹
5.2 分页插件 PageHelper
导入依赖
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.1.11</version>
</dependency>
在mybatis-config.xml配置分页插件
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor">
<property name="helperDialect" value="mysql"/>
</plugin>
</plugins>
其中,com.github.pagehelper.PageInterceptor 是 PageHelper 插件的名称,dialect 属性用于指定数据库类型(支持多种数据库)
分页插件的使用
public void test_02(){
EmployeeMapper mapper = session.getMapper(EmployeeMapper.class);
//调用之前,先设置分页数据(当前是第几页,每页显示多少个)
PageHelper.startPage(1,2);
List<Employee> list = mapper.queryList();
//将查询数据封装到一个叫PageInfo的分页实体类(一共有多少页,一共有多少页等等)
PageInfo<Employee> pageInfo = new PageInfo<>(list);
//从PageInfo中获取分页的数据
List<Employee> list1 = pageInfo.getList();
//当前页数
int pages = pageInfo.getPages();
//总页数
long total = pageInfo.getTotal();
System.out.println(pages);
System.out.println(total);
}
5.3 逆向工程和MybatisX插件
ORM思维介绍
ORM(Object-Relational Mapping,对象-关系映射)是一种将数据库和面向对象编程语言中的对象之间进行转换的技术。它将对象和关系数据库的概念进行映射,最后我们就可以通过方法调用进行数据库操作
也就是用面向对象的思维进行数据库操作
而逆行工程则是 半自动orm -> 全自动orm迈进
逆向工程MybatisX插件使用
下载插件即可