编译软件:IntelliJ IDEA 2019.2.4 x64
操作系统:win10 x64 位 家庭版
Maven版本:apache-maven-3.6.3
Mybatis版本:3.5.6
文章目录
- 一. 在sql映射文件中如何写注释?
- 二. 什么是动态sql?
- 三. 动态sql常用标签有哪些?
- 3.1 if标签
- 3.2 where标签
- 3.3 trim标签
- 3.4 set标签
- 3.5 choose标签
- 3.6 foreach标签
- 3.7 sql标签
一. 在sql映射文件中如何写注释?
关于XXXMapper接口对应的映射文件里SQL中的注释
👉语法
①方式一
//mysql的注释
-- 1=1
②方式二
//xml的注释
<!-- 1=1 -->
❓使用这两种注释方式各有什么不同呢?
👉请看如下测试
代码示例如下:
①使用第一种注释
<!-- 根据查询条件查找对应的员工信息(条件不确定) 即采用动态的sql去查询 --><select id="selectEmpByopr" resultType="employee">SELECT`id`,`last_name`,`email`,`salary`,`dept_id`FROM`tbl_employee`WHERE-- 1=1<if test="id !=null">and id=#{id}</if><if test="lastName != null">and last_name=#{lastName}</if><if test="email != null">and email=#{email}</if><if test="salary != null">and last_name=#{salary}</if></select>
②使用第二种注释
<!-- 根据查询条件查找对应的员工信息(条件不确定) 即采用动态的sql去查询 --><select id="selectEmpByopr" resultType="employee">SELECT`id`,`last_name`,`email`,`salary`,`dept_id`FROM`tbl_employee`WHERE
<!-- 1=1--><if test="id !=null">and id=#{id}</if><if test="lastName != null">and last_name=#{lastName}</if><if test="email != null">and email=#{email}</if><if test="salary != null">and last_name=#{salary}</if></select>
💡结论
通过以上二者运行测试结果对比,所以在需要使用注释时,推荐使用第二种注释方式
二. 什么是动态sql?
👉定义
- 动态sql指的是sql语句可动态化
- Mybatis的动态sql中支持OGNL表达式语言,OGNL(Object Graph Navigation
Language)是对象图导航语言
❗注意
👉用法案例
不指定查询条件,查询对应员工信息,即当你传入id,程序就根据id去查,传入什么条件,就去根据此条件去查(多个条件不确定)
代码示例如下
①在EmployeeMapper接口下书写相应的方法
//动态的sql方式,即不指定查询条件,查询对应员工信息
public List<Employee> selectEmpByopr(Employee employee);
②在EmployeeMapper接口相应的sql
<!-- 根据查询条件查找对应的员工信息(条件不确定) 即采用动态的sql去查询 --><select id="selectEmpByopr" resultType="employee">SELECT`id`,`last_name`,`email`,`salary`,`dept_id`FROM`tbl_employee`WHERE<if test="id !=null">and id=#{id}</if><if test="lastName != null">and last_name=#{lastName}</if><if test="email != null">and email=#{email}</if><if test="salary != null">and last_name=#{salary}</if></select>
③测试
@Test
public void test01(){try {String resource = "mybatis-config.xml";InputStream inputStream = Resources.getResourceAsStream(resource);SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);//通过SqlSessionFactory对象调用openSession();SqlSession sqlSession = sqlSessionFactory.openSession();//获取EmployeeMapper的代理对象EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);//动态参数(无参会报错,没有第一个参数也会报错)Employee employee=new Employee();List<Employee> employees = employeeMapper.selectEmpByopr(employee);//遍历集合employeesfor (Employee employee1 : employees) {System.out.println(employee1);}} catch (IOException e) {e.printStackTrace();}}
❓但是这样会出现一个问题,即不传参会报错,没有第一个参数也会报错
💡原因分析
不传参时,mybatis解析sql的过程中走到where的部分,无参,会进入where里,但不会执行里面的任意if判断,where后没有任何赋值表达式,此sql为非法sql,故报错。没有第一个参数时也会报类似的问题。
👉解决方案
①在第二步中的where里加上 1=1,作为条件恒等式(老版本的解决措施)
②使用where标签
代码示例如下:
<!-- 根据查询条件查找对应的员工信息(条件不确定) 即采用动态的sql去查询 --><select id="selectEmpByopr" resultType="employee">SELECT`id`,`last_name`,`email`,`salary`,`dept_id`FROM`tbl_employee`<where><if test="id !=null">and id=#{id}</if><if test="lastName != null">and last_name=#{lastName}</if><if test="email != null">and email=#{email}</if><if test="salary != null">and last_name=#{salary}</if></where></select>
三. 动态sql常用标签有哪些?
3.1 if标签
👉功能
用于完成简单的判断
示例代码如下:
//如果属性id不为空,就将传入的参数id赋值给sql中的字段id<if test="id !=null">id=#{id}</if>
3.2 where标签
👉功能:
用于解决where关键字及where后第一个and或or的问题
示例代码如下:
<where><if test="id !=null">and id=#{id}</if><if test="lastName != null">and last_name=#{lastName}</if><if test="email != null">and email=#{email}</if><if test="salary != null">and last_name=#{salary}</if>
</where>
3.3 trim标签
👉功能
可以在条件判断完的SQL语句前后添加或者去掉指定的字符
👉属性
prefix
:添加前缀prefixOverrides
:去掉前缀suffix
:添加后缀suffixOverrides
:去掉后缀
👉用法案例
不指定查询条件,查询对应员工信息(trim标签优化版)
代码示例如下:
①在EmployeeMapper接口定义相应的方法
//不指定查询条件,查询对应员工信息
public List<Employee> selectEmpByEmpTrim(Employee employee);
②在EmployeeMapper接口对应的映射文件中定义相应的sql
<!-- 根据查询条件查找对应的员工信息(条件不确定) 动态的sql(trim标签优化版) -->
<select id="selectEmpByEmpTrim" resultType="employee">SELECT`id`,`last_name`,`email`,`salary`,`dept_id`FROM`tbl_employee`<!-- 给下面的sql语句加上前缀 where,去掉后缀and --><trim prefix="where" suffixOverrides="and"><if test="id !=null">id=#{id} and</if><if test="lastName != null">last_name=#{lastName} and</if><if test="email != null">email=#{email} and</if><if test="salary != null">salary=#{salary} and</if></trim>
</select>
③测试
@Testpublic void test02(){try {String resource = "mybatis-config.xml";InputStream inputStream = Resources.getResourceAsStream(resource);SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);//通过SqlSessionFactory对象调用openSession();SqlSession sqlSession = sqlSessionFactory.openSession();//获取EmployeeMapper的代理对象EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);//动态参数Employee employee=new Employee();/* employee.setLastName("jack");employee.setSalary(5600.0);
*/List<Employee> employees = employeeMapper.selectEmpByEmpTrim(employee);//遍历集合employeesfor (Employee employee1 : employees) {System.out.println(employee1);}} catch (IOException e) {e.printStackTrace();}}
trim标签运行流程详解
3.4 set标签
👉功能
主要用于解决set关键字及多出一个【,】问题
👉用法案例
修改员工的信息
代码示例如下:
①在EmployeeMapper接口中定义修改员工的信息的方法
//修改员工的信息
public void updateEmp(Employee employee);
②在EmployeeMapper接口对应的映射文件中书写相应的sql
问题版(会出现多一个【,】问题
)
<update id="updateEmp">updatetbl_employeeset<if test="lastName != null">last_name=#{lastName} ,</if><if test="email != null">email=#{email} ,</if><if test="salary != null">salary=#{salary} ,</if>whereid=#{id}
</update>
set标签解决问题版
<update id="updateEmp">updatetbl_employee<set><if test="lastName != null">last_name=#{lastName} ,</if><if test="email != null">email=#{email} ,</if><if test="salary != null">salary=#{salary} ,</if></set>whereid=#{id}
</update>
③测试
@Test
public void test03(){try {String resource = "mybatis-config.xml";InputStream inputStream = Resources.getResourceAsStream(resource);SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);//通过SqlSessionFactory对象调用openSession();SqlSession sqlSession = sqlSessionFactory.openSession();//获取EmployeeMapper的代理对象EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);//动态参数Employee employee=new Employee();employee.setId(1);employee.setLastName("tom");employee.setSalary(16800.0);employeeMapper.updateEmp(employee);xml} catch (IOException e) {e.printStackTrace();}
}
使用问题版的sql进行测试
使用set标签解决问题版的sql进行测试
3.5 choose标签
👉功能
类似java中if-else【switch-case】结构
👉应用场景
应用于单个条件不确定的业务场景
👉用法案例
不指定查询条件,查询对应的员工信息(单个条件不确定的)
代码示例如下:
①在EmployeeMapper接口书写相应的方法
//不指定查询条件,查询对应员工信息(单个条件不确定的)
public List<Employee> selectEmpByOneOpr(int empId);
②在EmployeeMapper接口对应的映射文件中书写相应的sql
<!-- 根据查询条件查找对应的员工信息(条件不确定) 动态的sql(trim标签优化版) -->
<select id="selectEmpByOneOpr" resultType="employee">SELECT`id`,`last_name`,`email`,`salary`,`dept_id`FROM`tbl_employee`<where><choose><when test="id !=null">id=#{id}</when><when test="lastName != null">last_name=#{lastName}</when><when test="email != null">email=#{email}</when><otherwise>salary=#{salary}</otherwise></choose></where></select>
③测试
@Test
public void test04(){try {String resource = "mybatis-config.xml";InputStream inputStream = Resources.getResourceAsStream(resource);SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);//通过SqlSessionFactory对象调用openSession();SqlSession sqlSession = sqlSessionFactory.openSession();//获取EmployeeMapper的代理对象EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);List<Employee> employees = employeeMapper.selectEmpByOneOpr(1);System.out.println(employees);} catch (IOException e) {e.printStackTrace();}
}
3.6 foreach标签
👉功能
类似java中for循环
👉标签属性
collection
:要迭代的集合item
:当前从集合中迭代出的元素separator
:元素与元素之间的分隔符open
:开始字符close
:结束字符
👉应用场景
🚩 ①遍历迭代
用法案例
通过多个id获取员工的信息 【EmpIds:员工id的集合】
代码示例如下:
a.在EmployeeMapper接口定义相应的方法
/*** 通过多个id获取员工的信息 【EmpIds:员工id的集合】* @param EmpIds* @return*/
public List<Employee> selectEmpByIds(@Param("ids") List<Integer> EmpIds);
b.在EmployeeMapper接口对应的映射文件中定义相应的sql
<select id="selectEmpByIds" resultType="employee">SELECT`id`,`last_name`,`email`,`salary`,`dept_id`FROM`tbl_employee`<where>`id` in(<foreach collection="ids" item="id" separator=",">#{id}</foreach>)</where></select>
c.测试
@Test
public void test04(){try {String resource = "mybatis-config.xml";InputStream inputStream = Resources.getResourceAsStream(resource);SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);//通过SqlSessionFactory对象调用openSession();SqlSession sqlSession = sqlSessionFactory.openSession();//获取EmployeeMapper的代理对象EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);List<Employee> employees = employeeMapper.selectEmpByOneOpr(1);System.out.println(employees);} catch (IOException e) {e.printStackTrace();}
}
🚩②批量导入
用法案例
批量添加员工数据
代码示例如下:
a.在EmployeeMapper接口定义相应的方法
//批量添加员工数据public void batchInsertEmp(@Param("emps") List<Employee> employees);
b.在EmployeeMapper接口对应的映射文件中定义相应的sql
// 批量添加员工数据,使用insert标签书写相应的sql
<insert id="batchInsertEmp">insert intotbl_employee(last_name,email,salary)values<foreach collection="emps" item="emp" separator=",">(#{emp.lastName},#{emp.email},#{emp.salary})</foreach></insert>
c.测试
@Test
public void test06(){try {String resource = "mybatis-config.xml";InputStream inputStream = Resources.getResourceAsStream(resource);SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);//通过SqlSessionFactory对象调用openSession();SqlSession sqlSession = sqlSessionFactory.openSession();//获取EmployeeMapper的代理对象EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);//定义要添加的员工集合List<Employee> list=new ArrayList<>();list.add(new Employee("zhangsan","sdhjsd@qq.com",6700.0));list.add(new Employee("wangwu","dddhjsd@123.com",9700.0));employeeMapper.batchInsertEmp(list);sqlSession.commit();} catch (IOException e) {e.printStackTrace();}
}
3.7 sql标签
👉功能
提取可重用SQL片段
❗注意
该SQL片段可以是一个完整的sql语句,也可以是一个sql语句中的某个片段)
👉用法案例
使用sql标签对3.6小节中的应用场景1的案例里映射文件里的的”select xxx,xxxx,xxx from
xxxx”部分提取出来,作为一个可重用的sql片段,在select>标签内引入该sql片段
代码示例如下:
①使用sql标签抽取映射文件中”select xxx,xxxx,xxx from xxxx”部分片段作为可重用的sql片段
<!-- 抽取映射文件中”select xxx,xxxx,xxx from xxxx”部分片段作为可重用的sql片段 -->
<sql id="select_employee">SELECT`id`,`last_name`,`email`,`salary`,`dept_id`FROM`tbl_employee`</sql><select id="selectEmpByIds" resultType="employee"><!-- 将刚才抽取的sql片段select_employee引入进来 --><include refid="select_employee"></include><where>`id` in(<foreach collection="ids" item="id" separator=",">#{id}</foreach>)</where></select>
②测试运行