为什么需要动态SQL?有时候需要根据实际传入的参数来动态的拼接SQL语句。 最常用的就是:where和if标签 1.参考官方文档 ? if:字符判断 ? choose (when, otherwise):分支选择 ? trim (where, set):字符串截取;其中where标签封装查询条件,set标签封装修改条件 ? foreach 2.if案例: 1)在EmployeeMapper接口中添加一个方法: //携带了哪个字段,查询条件就带上哪个字段的值 public List<Employee> getEmployeeByConditionIf(Employee employee); 2).如果要写下列的SQL语句,只要是不为空,就作为查询条件,如下所示,这样写实际上是有问题的,所以我们要写成动态SQL语句: <select id="getEmployeeByConditionIf" resultType="com.neuedu.entity.Employee"> select *from tbl_employee where id = #{id} and user_name = #{userName} and email = #{email} and gender = #{gender} </select> 3)用if标签改写为动态SQL,如下所示: <select id="getEmployeeByConditionIf" resultType="com.neuedu.entity.Employee"> select *from tbl_employee where <!-- test:判断表达式(OGNL) OGNL参照PPT或者官方文档。 c:if test 从参数中取值进行判断 遇见特殊符号,应该去写转义字符:参考W3CSchool>>HTML>>ISO8859 --> <if test="id != null"> id = #{id} </if> <if test="userName != null && userName !=‘‘"> and user_name = #{userName} </if> <if test="email != null and email.trim() != """> and email = #{email} </if> <!-- ognl会进行字符串和数字的转换判断;"0"==0,"1"==1 --> <if test="gender == 0 or gender == 1"> and gender = #{gender} </if> </select> 4).测试代码: @Test public void testGetEmployee(){ EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class); Employee employee = new Employee(); employee.setId(1); employee.setUserName("张三丰"); employee.setEmail("[email protected]"); employee.setGender(1); List<Employee> list = mapper.getEmployeeByConditionIf(employee); System.out.println(list); } #测试结果没问题 但是仔细来说,上面的sql语句是有问题的,当我们不给动态sql语句传递id值的时候,sql语句的拼装就会有问题! 解决办法: 1.给where后面加上1=1,以后的条件都可以使用and xxx了 2.mybatis可以使用where标签来将所有的查询条件包括在内。mybatis就会将where标签中拼装的sql, 多出来的and或者or去掉!//需要注意:where标签只会去掉第一个多出来的and或者or 3.也就是说使用where标签有时候还是不能解决问题的,那怎么办呢?我们这里可以使用trim标签! 2.trim标签:可以自定义字符串的截取规则 <select id="getEmployeeByConditionIf" resultType="com.neuedu.entity.Employee"> select *from tbl_employee <!-- 后面多出的and或者or where标签不能够解决 prefix="":前缀:trim标签体重是整个字符串拼串后的结果。 prefix给拼串后的整个字符串加一个前缀 prefixOverrides="": 前缀覆盖:去掉整个字符串前面多余的字符 suffix="":后缀 suffix给拼串后的整个字符串加一个后缀 suffixOverrides="": 后缀覆盖:去掉整个字符串后面多余的字符 --> <trim prefix="where" suffixOverrides="and"> <if test="id != null"> id = #{id} and </if> <if test="userName != null && userName !=‘‘"> user_name = #{userName} and </if> <if test="email != null and email.trim() != """> email = #{email} and </if> <!-- ognl会进行字符串和数字的转换判断;"0"==0,"1"==1 --> <if test="gender==0 or gender==1"> gender = #{gender} </if> </trim> </select> 3.choose标签:分支选择,类似于Java中的带了break的switch...case choose (when, otherwise):如果带了id,就用id查,如果带了userName就用userName查,只会进入其中一个! 案例演示: 1.在EmployeeMapper接口中添加一个方法: public List<Employee> getEmployeeByConditionChoose(Employee employee); 2.sql映射文件 <!-- public List<Employee> getEmployeeByConditionChoose(Employee employee); --> <select id="getEmployeeByConditionChoose" resultType="com.neuedu.entity.Employee"> select *from tbl_employee <where> <!-- 如果带了id,就用id查,如果带了userName就用userName查,只会进入其中一个! --> <choose> <when test="id != null"> id = #{id} </when> <when test="userName != null"> user_name like #{userName} </when> <when test="email != null"> email = #{email} </when> <otherwise> 1=1 </otherwise> </choose> </where> </select> 4.trim 中的set标签(where, set):字符串截取;其中where标签封装查询条件,set标签封装修改条件 set元素会动态前置set关键字,同时也会消除无关的逗号。 1).在EmployeeMapper中添加一个更新的方法,如下所示: public void updateEmp(Employee employee); 2)在sql映射文件中,填写相应的sql语句,如下所示【set标签可以将字段后面的逗号去掉】: <update id="updateEmp"> update tbl_employee <set> <if test="userName != null"> user_name = #{userName}, </if> <if test="email != null"> email = #{email}, </if> <if test="gender != null"> gender = #{gender}, </if> </set> where id = #{id} </update> 测试类代码为: @Test public void testGetEmployee(){ EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class); Employee employee = new Employee(); employee.setId(1); employee.setUserName("哈哈"); employee.setEmail("[email protected]"); employee.setGender(1); mapper.updateEmp(employee); } //当然上面的set标签我们也可以使用trim标签来代替,如下所示: <update id="updateEmp"> update tbl_employee <trim prefix="set" suffixOverrides=","> <if test="userName != null"> user_name = #{userName}, </if> <if test="email != null"> email = #{email}, </if> <if test="gender != null"> gender = #{gender}, </if> </trim> where id = #{id} </update> 5.foreach:遍历元素 动态SQL的另一个常用的操作是需要对一个集合进行遍历,通常在构建in条件语句的时候! foreach元素允许指定一个集合,声明集合项和索引变量,并可以指定开闭匹配的字符串以及在迭代之间放置分隔符。 案例演示: 1.在EmployeeMapper接口中加入一个方法,如下所示: public List<Employee> getEmpsByConditionForeach(@Param("ids") List<Integer> ids); 2.在MyBatis的sql映射文件中写相应的代码: <!-- public List<Employee> getEmpsByConditionForeach(List<Integer> ids); --> <select id="getEmpsByConditionForeach" resultType="com.neuedu.entity.Employee"> select * from tbl_employee where id in <!-- collection:指定要遍历的集合 item:将当前遍历出的元素赋值给指定的变量 separator:每个元素之间的分隔符 open:遍历出所有记过拼接一个开始的字符 close:遍历出所有结果拼接一个结束的字符 --> <foreach collection="ids" open="(" close=")" separator="," item="id"> #{id} </foreach> </select> 3.测试类代码为: @Test public void testGetEmployee(){ EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class); List<Integer> asList = Arrays.asList(1,2,3,4); List<Employee> emps = mapper.getEmpsByConditionForeach(asList); for (Employee employee : emps) { System.out.println(employee); } } foreach标签还可以用于批量保存数据,如下所示: 1.在EmployeeMapper接口类中添加批量插入的方法: public void addEmps(@Param("emps") List<Employee> emps); 2.在EmployeeMapper.xml的sql映射文件中添加响应的语句: <!-- public void addEmps(@Param("emps") List<Employee> emps); --> <!-- MySQL下批量保存:可以foreach遍历,mysql支持values(),(),()语法 --> <insert id="addEmps"> INSERT INTO tbl_employee(user_name,gender,email,d_id) VALUES <foreach collection="emps" item="emp" separator=","> (#{emp.userName},#{emp.gender},#{emp.email},#{emp.depart.id}) </foreach> </insert> 3.测试代码: @Test public void testGetEmployee(){ EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class); List<Employee> emps = new ArrayList<Employee>(); emps.add(new Employee(0, 1, "allen", "[email protected]", new Department(1))); emps.add(new Employee(0, 0, "tom", "[email protected]", new Department(2))); emps.add(new Employee(0, 1, "mux", "[email protected]", new Department(1))); mapper.addEmps(emps); }
时间: 2024-11-08 14:45:09