ssm学习笔记day08mybatis
动态mysql if标签、where标签
现在思考一个情况,如果给你两个参数name和salary,让你寻找符合这两个条件的员工,但是只给了一个name或者salary,如果不采用动态标签,则找到的是否是我们想要的呢,即只满足name或者salary。
如果目前采用这种判断,一定是找满足emp_name = name && emp_salary = salary的。如果只给一个name,salary为空,找到的一定是满足emp_name = name && emp_salary = null,这和我们想要的答案不一致,我们想要的是emp_name = name。
这时候<if>
标签登场了。
<if>
有test属性,对test输入判断语句,只针对函数的输入的参数做出判断,如下图所示,只有满足非空才能插进去。
<select id="queryEmpByNameAndSalary" resultType="com.atguigu.mybatis.bean.Emp">select * from t_empwhere<if test="name != null">emp_name = #{name}</if><if test="salary != null">and emp_salary = #{salary}</if></select>
但是这个语句是否正确呢,如果name为空,salary非空,或者两者为空,会不会出现问题。
name为空,salary非空的情况:
通过测试发现
会出现**where and emp_salary = ?**的错误。
现在我们来纠正这个写法,我们可以使用在最前面加一个1=1后面跟and **。
<select id="queryEmpByNameAndSalary" resultType="com.atguigu.mybatis.bean.Emp">select * from t_emp where1 = 1<if test="name != null">and emp_name = #{name}</if><if test="salary != null">and emp_salary = #{salary}</if></select>
使用改写法后无问题。
两者为空:
如果采用原写法,则会出现以下问题
采用修改后的写法如下,查询正常返回
那是否有更美观更简洁的写法呢,有的。采用<where>
标签即可解决问题。<if>
标签语句仍正常书写即可。
<select id="queryEmpByNameAndSalary" resultType="com.atguigu.mybatis.bean.Emp">select * from t_emp<where><if test="name != null">emp_name = #{name}</if><if test="salary != null">and emp_salary = #{salary}</if></where></select>
采用where标签后会自动帮你清除错误。
动态mysql set标签
和where标签类似,不过用于update中。如下所示
<update id="updateEmp">update t_emp<set><if test="empName != null">emp_name = #{empName},</if><if test="empSalary != null">emp_salary = #{empSalary},</if><if test="age!= null">age = #{age}</if></set>where id = #{id}</update>
动态mysql trim标签
有一个标签很强大,可以把<where>
和<set>
标签替代,这就是我们要讲的<trim>
标签。
代替<where>
如下
<select id="queryEmpByNameAndSalary" resultType="com.atguigu.mybatis.bean.Emp">select * from t_emp<trim prefix="where" prefixOverrides="and || or"><if test="name != null">emp_name = #{name}</if><if test="salary != null">and emp_salary = #{salary}</if></trim></select>
以下的几个主要属性
prefix:在 trim 的内容前面添加指定内容。
prefixOverrides:去除 trim 内容前面多余的字符,以空格作为分隔,会从最后一个分隔的字符开始判断是否去除。
suffix:在 trim 的内容后面添加指定内容。
suffixOverrides:去除 trim 内容后面多余的字符,以空格作为分隔,会从第一个分隔的字符开始判断是否去除。
上面的语句中,对where语句后面的,可能开头会出现and、or,我们要去掉才能得到一个合法的sql语句,所以prefixOverrides=“and || or”。
代替<set>
如下
<update id="updateEmp">update t_emp<trim prefix="set" prefixOverrides="," suffix="where id = #{id}"><if test="empName != null">emp_name = #{empName},</if><if test="empSalary != null">emp_salary = #{empSalary},</if><if test="age!= null">age = #{age}</if></trim></update>
与<where>
不同的是<set>
多了一个suffix。
动态mysql 分支选择choose、when、otherwise标签
<if>
标签只有判断,如果我们要分支选择怎么办呢,即<choose>
,<when>
,<otherwise>
标签。
使用方法如下
<select id="queryEmpByNameAndSalary" resultType="com.atguigu.mybatis.bean.Emp">select * from t_emp<where><choose><when test="name!=null">emp_name = name</when><when test="salary!=null">emp_salary = salary</when><otherwise></otherwise></choose></where>
</select>
choose套在外面,when相当于if,otherwise相当于else
动态mysql foreach标签
这个标签作为动态mysql功能最强的标签,也是我们学习的核心之一
主要属性
collection:必填属性,指定要遍历的集合。它的值根据传入参数类型的不同而不同。
如果传入的是单个集合对象(如List、Set),值为list。
如果传入的是数组,值为array。
若传入的是Map类型,collection指定Map中对应集合属性的键。
item:表示集合中每一个元素进行迭代时的别名。
index:指定在迭代过程中,当前元素在集合中的索引。在遍历List集合时,index是元素的下标;遍历Map时,index是Map的键。
open:表示该 SQL 语句以什么开始,比如(。
close:表示该 SQL 语句以什么结束,比如)。
separator:表示元素之间的分隔符,比如AND、,等。
示例
如果批量插入数据该怎么写,首先自己写一个SQL语句观察观察
insert into t_emp(emp_name , age , emp_salary) values ('zhangsan',18,33.2) , ('zhangsan2',19,33.2) , ('zhangsan3',20,34.2)
可以发现后面的(?,?,?)是重复的,我们对这个用<foreach>
标签书写,如下所示,collection对应的是函数参数的名字,item是单个元素的别名,seperator是多个语句用什么分开。
<insert id="addEmps">insert into t_emp(emp_name , age , emp_salary) values<foreach collection="emps" item = "emp" separator=",">(#{emp.empName},#{emp.age},#{emp.empSalary})</foreach></insert>
同理,也搞一个批量修改的操作。
update t_emp SET emp_name = 'zhangsan01', age=18, emp_salary = 3.2 where id = 8 ;
update t_emp SET emp_name = 'zhangsan01', age=19, emp_salary = 34.2 where id = 9 ;
update t_emp SET emp_name = 'zhangsan01', age=20, emp_salary = 34.2 where id = 10 ;
update t_emp SET emp_name = 'zhangsan01', age=21, emp_salary = 34.6 where id = 11 ;
不过与插入不同的时,不能缩成一句话,必须写成多句话,然后xml语句如下。
<update id="updateBatchEmp"><foreach collection="emps" item="emp" separator=";">update t_emp<set><if test="emp.empName!=null">emp_name = #{emp.empName},</if><if test="emp.age!=null">age=#{emp.age},</if><if test="emp.empSalary!=null">emp_salary = #{emp.empSalary}</if></set>where id = #{emp.id}</foreach></update>
ps:需要注意的是item不要写成index,我就因为这个然后报There is no getter for property named 'empName' in 'class java.lang.Integer'
的错误,只能说下次遇到这个错误就知道什么问题了,然后后面的update批量操作,springboot默认是不认识这个分号’;'的,所以需要在application.prosperites上修改配置,在spring.datasource.url=jdbc:mysql://localhost:3306/mybatis-example
后面加上?allowMultiQueries=true
即可
动态sql sql、include标签
有些地方复用性比较高,于是我们对这些判断定义为公共变量。如下:
<select id="getEmpById" resultType="com.atguigu.mybatis.bean.Emp">SELECT id , emp_name empName, age , emp_salary empSalary FROM t_emp WHERE id = #{id}</select>
比如id , emp_name empName, age , emp_salary empSalary
的复用性比较高,我们对这个片段设置一个公共变量,然后复写到当前函数。<sql>
标签是定义公共变量,<include>
是引用<sql>
标签的内容,用id指定对应的<sql>
。
<sql id="columns">id , emp_name empName, age , emp_salary</sql><!-- 在里面写方法 , id绑定方法名 #{变量名} resultType返回类型--><select id="getEmpById" resultType="com.atguigu.mybatis.bean.Emp">SELECT <include refid="columns"></include> empSalary FROM t_emp WHERE id = #{id}</select>