mybatis笔记(下)
动态语句简介
什么是mybatis动态语句?
是指在sql映射文件中,根据动态生成的sql语句的功能。通过使用mybatis提供的动态的sql元素,可以根据不同条件生成不同的sql语句避免在代码中拼接字符串。
动态语句的标签
注意使用标签前先将不用标签将正常desql语句写一遍,在用标签将其拆分
where与if标签:
<!--List<Employee> query(@Param("name") String name, @Param("salary") Double salary);
要求:两个属性可传,可不传
如果传入属性,就判断相等,如果不传入,就不加对应条件
where
if 判断传入的参数,最终是否添加语句
<if test=""> sql语句 </if>
test属性 内部作比较运算 ,最终 true将标签内的sql语句进行拼接 false不拼接标签内部语句
判断语句:"key 比较符号 值 and|or key 比较符号 值"
注意:可以直接取传入的值
大于和小于 不推荐直接写符号 >==> <==<
直接使用<if标签可能会出现的问题
假如两个都满足: where emp_name=#{name} and emp_salary=#{salary}
假如第一个满足第二个不满足:where emp_name=#{name}
假如第二个满足第一个不满足:where and emp_salary=#{salary} 错误
假如两个都不满足:where 错误
如和解决这一问题呢?
使用<where标签将所有的<if标签包裹起来
<where 标签的作用;
①自动添加where关键字 where内部有任何一个if满足,自动添加where关键字
②自动去掉多余的and|or关键字
综上所述:<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 salary > 100">
and emp_salary=#{salary}
</if>
</where>
</select>
set标签(用在update标签中)
<!--
//更具员工id更新员工数据,要求传入的name和salary不为null的才更新
int update(Employee employee);
参数可传,可不传
全部满足:没问题
第一个满足:多了个"," 错误
第二个满足: 没问题
都不满足:语法错误
如何解决呢?
将set变为<set标签将<if标签包裹
<set标签的作用:
①自动去掉多余的逗号
②自动添加set关键字
注意:如果if中的条件都不满足还是会报错的,所以至少有一个要满足
-->
<insert id="update">
update t_emp
<set>
<if test="empName != null">
emp_name=#{empName},
</if>
<if test="empSalary != null">
emp_salary=#{empSalary}
</if>
</set>
where emp_id=#{empId}
</insert>
trim标签
使用trim标签控制条件部分两端是否包含某些字符
- prefix属性:指定要动态添加的前缀
- suffix属性:指定要动态添加的后缀
- prefixOverrides属性:指定要动态去掉的前缀,使用“|”分隔有可能的多个值
- suffixOverrides属性:指定要动态去掉的后缀,使用“|”分隔有可能的多个值
<!--
方法:
List<Employee> queryTrim(@Param("name") String name, @Param("salary") Double salary);
int updateTrim(Employee employee);
Trim标签可以替代where标签和set标签
-->
<select id="queryTrim" resultType="employee">
select * from t_emp
<trim prefix="where" prefixOverrides="and|or">
<if test="name != null">
emp_name=#{name}
</if>
<if test="salary != null and salary > 100">
and emp_salary=#{salary}
</if>
</trim>
</select>
<insert id="updateTrim">
update t_emp
<trim prefix="set" suffixOverrides=",">
<if test="empName != null">
emp_name=#{empName},
</if>
<if test="empSalary != null">
emp_salary=#{empSalary}
</if>
</trim>
where emp_id=#{empId}
</insert>
Choose/when/otherwise标签
在多个分支条件中,仅执行一个。
- 从上到下依次执行条件判断
- 遇到的第一个满足条件的分支会被采纳
- 被采纳分支后面的分支都将不被考虑
- 如果所有的when分支都不满足,那么就执行otherwise分支
<!--
//根据两个条件查询,如果姓名不为null使用姓名查询,如果姓名为null,薪水不为null使用薪水查询!都为null查询全部
List<Employee> queryChoose(@Param("name") String name, @Param("salary") Double salary);
-->
<select id="queryTrim" resultType="employee">
select * from t_emp where
<choose>
<when test="name != null">
emp_name=#{name}
</when>
<when test="salary != null">
emp_salary=#{salary}
</when>
<otherwise>1=1</otherwise>
</choose>
</select>
总结:对比if的不同点
if可以有多个同时满足,而choose只能有一个满足
foreach标签
<!--foreach
//根据id的批量查询(传入一个list的int类型的集合)
List<Employee> queryBatch(@Param("ids") List<Integer> ids);
[1,2,3]
在mysql中的写法
select * from t_emp where emp_id(1,2,3)#查询id为1,2,3的员工们的信息
-->
<select id="queryTrim" resultType="employee">
select * from t_emp
where emp_id in
<!--
<foreach标签(遍历传入的集合)
collection ="形参集合的标识(@Param)|arg0...|list" 指定要遍历的集合
open 在遍历之前要追加的字符串
close 在遍历之后要追加的字符串
separator 每次遍历的分割符号,如果是最后一次,不会追加
item="id" 获取每个遍历项(将每次遍历的值放在id变量中)——————在<foreach的sql语句中会被引用
-->
<foreach collection="ids" open="(" separator="," close=")" item="id">
<!-- 遍历的内容,#{遍历项 item指定的key} -->
#{id}
</foreach>
</select>
<!--
//根据id的批量增删改
int deleteBatch(@Param("ids") List<Integer> ids);
int insertBatch(@Param("list") List<Employee> employeeList);
int updateBatch(@Param("list") List<Employee> employeeList);
-->
<delete id="deleteBatch">
delete from t_emp where emp_id in
<foreach collection="ids" open="(" separator="," close=")" 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},#{empSalary})
</foreach>
</insert>
<!--
当找不到那块有遍历规律时,直接将整个sql语句遍历 (相当于一个标签设置多个语句)
如果一个标签设计多个sql语句,需要设置允许指定多语句:
此时需要在数据库连接信息的URL地址中设置:atguigu.dev.url=jdbc:mysql:///mybatis-example?allowMultiQueries=true
-->
<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片段
<!--
使用sql标签抽取重复片段:
①使用<sql标签抽取 id属性是代表此片段的标识
②使用<include标签来引用重复片段 refid属性填写要引用的重复sql片段的标识
-->
<sql id="selectSql">
select * from t_emp
</sql>
<select id="query" resultType="employee">
<include refid="selectSql"></include>
<where>
<if test="name != null">
emp_name=#{name}
</if>
<if test="salary != null and salary > 100">
and emp_salary=#{salary}
</if>
</where>
</select>
mapper按包批量扫描
1. 需求
Mapper 配置文件很多时,在全局配置文件中一个一个注册太麻烦,希望有一个办法能够一劳永逸。
2.配置方式
Mybatis 允许在指定 Mapper 映射文件时,只指定其所在的包:
<mappers>
<package name="com.atguigu.mapper"/>
</mappers>
此时这个包下的所有 Mapper 配置文件将被自动加载、注册,比较方便。
资源创建要求
- Mapper 接口和 Mapper 配置文件名称一致
- Mapper 接口:EmployeeMapper.java
- Mapper 配置文件:EmployeeMapper.xml
在mybatis-config文件中:
<mappers>
<!-- 单个文件映射 <mapper resource="mappers/EmployeeMapper.xml"/>-->
<!-- 批量处理mapper指令
1 要求mapperxml文件和mapper接口的命名必须相同
2 最终打包后的位置要一致 都是指定的包地址下
如何实现:
方案一:将xml文件也加入到接口所在的包(不推荐)
方案二:resource文件夹创建对应的(与mapper接口文件夹结构一致)文件夹结构即可
注意:resource下直接创建多层文件夹 使用/分割,如果使用的是.那么就只会创建一个文件夹
-->
<package name="org.example.mapper"/>
</mappers>
分页插件
如何使用分页插件:
①引入依赖
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.1.11</version>
</dependency>
②在 MyBatis 的配置文件mybatis-config中添加 PageHelper 的插件:
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor">
<property name="helperDialect" value="mysql"/>
</plugin>
</plugins>
③使用
public class MyBatisTest {
private SqlSession sqlSession;
@BeforeEach//每次执行测试方法前,先走初始化方法
public void start() throws IOException {
InputStream ips = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory build = new SqlSessionFactoryBuilder().build(ips);
sqlSession = build.openSession();
}
@AfterEach//每次执行测试方法后,先走此方法
public void end(){
sqlSession.close();
}
@Test
public void test1(){
/**
* 使用步骤:
* ①设置查看的页数和页容量
* 通过PageHelper调用startPage()函数,传入pageNum与PageSize
* ②正常执行函数调用查询语句
* ③创建pageInfo对象
* 通过PageInfo构造器,传入查询结果
* ④通过PageInfo对象调用getList()得到当前页的数据
*/
EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
//调用之前,设置分页数据(当前是第几页,每页显示多少个)
PageHelper.startPage(1,2);
//注意:不能将两条查询装到一个分页区(startPage与PageInfo之间)
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();
//获取当前是第几页
int pageNum = pageInfo.getPageNum();
//获取页容量
int pageSize = pageInfo.getPageSize();
//查看是否有下一页
boolean hasNextPage = pageInfo.isHasNextPage();
System.out.println(list1);
}
}