1. Mybatis基础操作
mybatis入门配置后,学习mybatis的CRUD基础操作。
1.1 需求
需求列表:
- 查询
- 根据主键ID查询
- 条件查询
- 新增
- 更新
- 删除
- 根据主键ID删除
- 根据主键ID批量删除
1.2 准备
步骤
- 准备数据库表
- 创建一个新的springboot工程,选择引入对应的起步依赖(mybatis、mysql驱动、lombok)
- application.properties中引入数据库连接信息
- 创建对应的实体类 Emp(实体类属性采用驼峰命名)
- 准备Mapper接口 EmpMapper
1.3 删除
1.3.1 根据主键删除数据
- SQL语句
-- 删除id=17的数据
delete from emp where id = 17;
Mybatis框架让程序员更关注于SQL语句
- 接口方法
@Mapper
public interface EmpMapper {
@Delete("delete from emp where id = #{id}")//使用#{key}方式获取方法中的参数值
public void delete(Integer id);
}
1.3.2 日志输入
在Mybatis当中我们可以借助日志,查看到sql语句的执行、执行传递的参数以及执行结果。具体操作如下:
- 打开application.properties文件
- 开启mybatis的日志,并指定输出到控制台
#指定mybatis输出日志的位置, 输出控制台
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
但是我们发现输出的SQL语句:delete from emp where id = ?,我们输入的参数16并没有在后面拼接,id的值是使用?进行占位。那这种SQL语句我们称为预编译SQL。
1.3.3 预编译SQL
1.3.3.1 介绍
预编译SQL有两个优势:
- 性能更高
- 更安全(防止SQL注入)
1.3.3.2 SQL注入
SQL注入:是通过操作输入的数据来修改事先定义好的SQL语句,以达到执行代码对服务器进行攻击的方法。
1.3.3.3 参数占位符
在Mybatis中提供的参数占位符有两种:${…} 、#{…}
- #{…}
- 执行SQL时,会将#{…}替换为?,生成预编译SQL,会自动设置参数值
- 使用时机:参数传递,都使用#{…}
- ${…}
- 拼接SQL。直接将参数拼接在SQL语句中,存在SQL注入问题
- 使用时机:如果对表名、列表进行动态设置时使用
注意事项:在项目开发中,建议使用#{…},生成预编译SQL,防止SQL注入安全。
1.4 新增
功能:新增员工信息
1.4.1 基本新增
SQL语句:
insert into emp(username, name, gender, image, job, entrydate, dept_id, create_time, update_time) values ('songyuanqiao','宋远桥',1,'1.jpg',2,'2012-10-09',2,'2022-10-01 10:00:00','2022-10-01 10:00:00');
接口方法:
@Mapper
public interface EmpMapper {
@Insert("insert into emp(username, name, gender, image, job, entrydate, dept_id, create_time, update_time) values (#{username}, #{name}, #{gender}, #{image}, #{job}, #{entrydate}, #{deptId}, #{createTime}, #{updateTime})")
public void insert(Emp emp);
}
1.4.2 主键返回
概念:在数据添加成功后,需要获取插入数据库数据的主键。
- 默认情况下,执行插入操作时,是不会主键值返回的。如果我们想要拿到主键值,需要在Mapper接口中的方法上添加一个Options注解,并在注解中指定属性useGeneratedKeys=true和keyProperty=“实体类属性名”
主键返回代码实现:
@Mapper
public interface EmpMapper {
//会自动将生成的主键值,赋值给emp对象的id属性
@Options(useGeneratedKeys = true,keyProperty = "id")
@Insert("insert into emp(username, name, gender, image, job, entrydate, dept_id, create_time, update_time) values (#{username}, #{name}, #{gender}, #{image}, #{job}, #{entrydate}, #{deptId}, #{createTime}, #{updateTime})")
public void insert(Emp emp);
}
1.5 更新
功能:修改员工信息
SQL语句:
update emp set username = 'linghushaoxia', name = '令狐少侠', gender = 1 , image = '1.jpg' , job = 2, entrydate = '2012-01-01', dept_id = 2, update_time = '2022-10-01 12:12:12' where id = 18;
接口方法:
@Mapper
public interface EmpMapper {
/**
* 根据id修改员工信息
* @param emp
*/
@Update("update emp set username=#{username}, name=#{name}, gender=#{gender}, image=#{image}, job=#{job}, entrydate=#{entrydate}, dept_id=#{deptId}, update_time=#{updateTime} where id=#{id}")
public void update(Emp emp);
}
1.6 查询
1.6.1 根据ID查询
SQL语句:
select id, username, password, name, gender, image, job, entrydate, dept_id, create_time, update_time from emp;
接口方法:
@Mapper
public interface EmpMapper {
@Select("select id, username, password, name, gender, image, job, entrydate, dept_id, create_time, update_time from emp where id=#{id}")
public Emp getById(Integer id);
}
1.6.2 数据封装
我们看到查询返回的结果中大部分字段是有值的,但是deptId,createTime,updateTime这几个字段是没有值的,而数据库中是有对应的字段值的,这是为什么呢?
原因如下:
- 实体类属性名和数据库表查询返回的字段名一致,mybatis会自动封装。
- 如果实体类属性名和数据库表查询返回的字段名不一致,不能自动封装。
解决方案:
- 起别名
- 结果映射 @Results
- 开启驼峰命名
# 在application.properties中添加:
mybatis.configuration.map-underscore-to-camel-case=true
要使用驼峰命名前提是 实体类的属性 与 数据库表中的字段名严格遵守驼峰命名。
1.6.3 条件查询
查询:
- 姓名:要求支持模糊匹配
- 性别:要求精确匹配
- 入职时间:要求进行范围查询
SQL语句:
select id, username, password, name, gender, image, job, entrydate, dept_id, create_time, update_time
from emp
where name like '%张%'
and gender = 1
and entrydate between '2010-01-01' and '2020-01-01 '
order by update_time desc;
接口方法:
- 方式一
@Mapper
public interface EmpMapper {
@Select("select * from emp " +
"where name like '%${name}%' " +
"and gender = #{gender} " +
"and entrydate between #{begin} and #{end} " +
"order by update_time desc")
public List<Emp> list(String name, Short gender, LocalDate begin, LocalDate end);
}
- 方式二(解决SQL注入风险)
- 使用MySQL提供的字符串拼接函数:concat(‘%’ , ‘关键字’ , ‘%’)
@Mapper
public interface EmpMapper {
@Select("select * from emp " +
"where name like concat('%',#{name},'%') " +
"and gender = #{gender} " +
"and entrydate between #{begin} and #{end} " +
"order by update_time desc")
public List<Emp> list(String name, Short gender, LocalDate begin, LocalDate end);
}
2. Mybatis的XML配置文件
Mybatis的开发有两种方式:
- 注解
- XML
2.1 XML配置文件规范
使用Mybatis的注解方式,主要是来完成一些简单的增删改查功能。如果需要实现复杂的SQL功能,建议使用XML来配置映射语句,也就是将SQL语句写在XML配置文件中。
在Mybatis中使用XML映射文件方式开发,需要符合一定的规范:
- XML映射文件的名称与Mapper接口名称一致,并且将XML映射文件和Mapper接口放置在相同包下(同包同名)
- XML映射文件的namespace属性为Mapper接口全限定名一致
- XML映射文件中sql语句的id与Mapper接口中的方法名一致,并保持返回类型一致。
2.2 XML配置文件实现
第1步:创建XML映射文件
第2步:编写XML映射文件
xml映射文件中的dtd约束,直接从mybatis官网复制即可
<?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">
<mapper namespace="">
</mapper>
配置:XML映射文件的namespace属性为Mapper接口全限定名
配置:XML映射文件中sql语句的id与Mapper接口中的方法名一致,并保持返回类型一致
3. Mybatis动态SQL
3.1 什么是动态SQL
在页面原型中,列表上方的条件是动态的,是可以不传递的,也可以只传递其中的1个或者2个或者全部。
SQL语句会随着用户的输入或外部条件的变化而变化,我们称为:动态SQL。
3.2 动态SQL-if
-
<if>
-
用于判断条件是否成立,如果条件为true,则拼接SQL
-
形式:
<if test="name != null"> … </if>
-
-
<where>
- where元素只会在子元素有内容的情况下才插入where子句,而且会自动去除子句的开头的AND或OR
-
<set>
- 动态地在行首插入 SET 关键字,并会删掉额外的逗号。(用在update语句中)
3.3 动态SQL-foreach
- 使用
<foreach>
遍历deleteByIds方法中传递的参数ids集合
<foreach collection="集合名称" item="集合遍历出来的元素/项" separator="每一次遍历使用的分隔符"
open="遍历开始前拼接的片段" close="遍历结束后拼接的片段">
</foreach>
3.4 动态SQL-sql&include
<sql>
:定义可重用的SQL片段<include>
:通过属性refid,指定包含的SQL片段
SQL片段: 抽取重复的代码
<sql id="commonSelect">
select id, username, password, name, gender, image, job, entrydate, dept_id, create_time, update_time from emp
</sql>
通过<include>
标签在原来抽取的地方进行引用。操作如下:
<select id="list" resultType="com.itheima.pojo.Emp">
<include refid="commonSelect"/>
<where>
<if test="name != null">
name like concat('%',#{name},'%')
</if>
<if test="gender != null">
and gender = #{gender}
</if>
<if test="begin != null and end != null">
and entrydate between #{begin} and #{end}
</if>
</where>
order by update_time desc
</select>