文章目录
Mybatis 动态sql
一.准备工作
mybatisX插件下载
mybatis代理开发(mapper接口和xml的对应)
二.xml增删改查
1.所有代码基本思路(接口方法–>xml–>测试)
mapper接口方法: 返回值 参数
xml中的statement : sql语句
测试:test测试代码
2. 查(重点!!!)
(略)查询所有(resultMap标签)和查询详情(#和$占位符,特殊符号处理)
查询所有:在一个界面中,显示一整张表(从数据库中查询所有信息)
- 基本语句:
<select id="selectAll" resultType="brand">
select *
from tb_brand;
</select>
-
问题:数据库中是company_name ,属性字段中是companyName,会发现这个数据查出来是null
-
解决(resultMap出现啦):
- (略)as命名(麻烦)
<select id="selectAll" resultType="brand"> select id,brand_name as brandName,company_name as companyName,order,description,status from tb_brand; </select>
- (略)include标签导入sql片段(当你要查询几个特定属性时,也麻烦)
<sql id="brand_column"> id,brand_name as brandName,company_name as companyName,order,description,status </sql>//sql片段设置 <select id="selectAll2" resultType="brand"> select <include refid="brand_column"/> //include标签导入sql片段 from tb_brand; </select>
- (重点)resultMap-result解决:
<resultMap id="brandMapper" type="brand"> <result column="brand_name" property="brandName"/> <result column="company_name" property="companyName"/> </resultMap> //将pojo类和数据库中不同名的在这里一次性设置好 // resultMap的type属性对应设置的pojo类名(因为在mybatis核心配置文件中用了 typeAliases 别名标签,所以可以忽略大小写,即brand和Brand均可) // column 对应数据库中的列名 // property 对应pojo类中的属性名
<select id="selectAll" resultMap="brandMapper"> //这里的属性是 resultMap 而非 resultType 了!!!(直接整个导入) select * from tb_brand; </select>
所以,后续创建一个xml时,第一件事就是来一个resultMap标签,将数据库和类名匹配,之后需要用到就直接用 resultMap
查询详情:点击该表中某个对象的查询按钮,跳转到另一个界面,显示该对象所有信息
-
基本语句
<select id="selectById" resultMap="brandMapper"> select * from tb_brand where id = #{id};//这里我们用#占位符,而非$,可以防止sql注入 </select>
-
小小拓展
当你要查询的条件是id<6的所有数据,要用到"<"号,但这是标签符号,所以,对于这种特殊符号,处理方式:
(1)用转义字符
<select id="selectMulById" resultType="com.kikky.pojo.Brand"> select * from tb_brand where id < #{id}; //看这里的“<”的特殊字符!但是此方法不适用于有很多特殊字符的时候哦 </select>
(2)用CDATA区(设置一个区, 写个CD,就会有提示)
<select id="selectMulById" resultType="com.kikky.pojo.Brand"> select * from tb_brand where id <![CDATA[ <= ]]>#{id}; //这里只要打个CD,就会有提示,把字符放里面即可,当作纯文本处理 </select>
总结:
(重点)条件查询
基础语句(多参数的三种解决办法)
-
情景:
用户输入很多条件,要根据id、companyName等查询对象,这时,我们又遇到了方法中形参和xml中占位符怎么对应的问题
举例:接口方法中,写的是:
Brand selectByConditions(String cName, String bName);
<select id="selectByConditions" resultMap="brandMapper">
select *
from tb_brand
where company_name = #{companyName}//计算机并不知道这个companyName是谁,所以,我们要将方法中的形参和#中的占位符绑定,让sql语句可以识别并拿到用户输入的条件
and
brand_name = #{brandName}
</select>
-
三种解决方式:
- 接口和对应的测试代码
1. 散装,用@Param注解(注解名 要和statement中占位符名一致 )
//mapper接口方法示例:对每一个参数设置注解,让其可以在statement中被识别
List<Brand> selectByCondition(@Param("status")int status, @Param("companyName") String company_name, @Param("brandName") String brand_name);
//测试代码示例:注意模糊查询的通配符使用
int status = 1;
String company_name = "华为";
String brand_name = "华为";
company_name ="%"+company_name+"%";
brand_name ="%"+brand_name+"%";
//注意sql语句用到了like,参数要有 通配符 % !(模糊查询)
List<Brand> brands = mapper.selectByCondition(status,company_name,brand_name);
2. 封装成对象 (**对象的属性名 要和xml中占位符一致** )
//mapper接口方法示例:形参是一个Brand对象
//这里就要注意Brand类中的属性名和 对应statement中的占位符 一样!!!
List<Brand> selectByCondition( Brand brand);
//测试代码示例:
Brand brand = new Brand();
brand.setStatus(status);
brand.setBrandName(brand_name);
brand.setCompanyName(company_name);//Brand类的属性名要与占位符一致
List<Brand> brands = mapper.selectByCondition(brand);
3. 封装成map集合(**集合的键名 要和statement中占位符名一致**)
//mapper接口方法示例:形参是一个map集合
List<Brand> selectByCondition(Map map);
//测试代码示例:
Map map =new HashMap();
map.put("status",status);
map.put("brandName",brand_name);
map.put("companyName",company_name);//键名要与占位符一致
List<Brand> brands = mapper.selectByCondition(map);
- xml中的statement
<select id="selectByConditions" resultMap="brandMapper">
select *
from tb_brand
where status = #{status}
and company_name like #{companyName}
and brand_name like #{brandName};
-- 多条件查询有个问题就是,sql语句中的占位符到底对应mapper方法中哪一个参数,重点学习和掌握!!!
-- 注意这里sql语句左侧是数据库中列名,右侧占位符一般写成 类的属性名,(与BrandMapper方法中不同的参数,散装、对象、map集合对应)
</select>
总结:
多条件动态查询( where if 标签)
-
情景:用户只输入了 status 和 company_name就点击了查询,其他条件为null!
-
解决:if判读呀–>if标签
<select id="selectByCondition" resultMap="brandMapper"> select * from tb_brand where <if test="status !=null"> //这里根据参数封装情况不同,也可以写成status!=0 status = #{status} </if> <if test="companyName !=null and companyName!=''"> and company_name like #{companyName} </if> <if test="brandName !=null and brandName!=''"> and brand_name like #{brandName} </if> </select>
-
新问题:and 必须根据情况 决定 有没有–>where标签
当我只输入了company_name时,语句变成了
select * from tb_brand where and company_name like ? ;//要报错啊
有恒等式和标签方法,这里重点介绍mybatis提供的标签(mybatis:我都帮你弄好了~~)
-
恒等式:
那怎么办,我们在status语句前也写上and ,然后在where 后面直接加一个 1=1 !
<select id="selectByCondition" resultMap="brandMapper"> select * from tb_brand //动态sql where 1=1 <if test="status !=null"> and status = #{status} </if> <if test="companyName !=null and companyName!=''"> and company_name like #{companyName} </if> <if test="brandName !=null and brandName!=''"> and brand_name like #{brandName}; </if> // 注意这里sql语句左侧是数据库中列名,右侧占位符一般写成 类的属性名,(与BrandMapper方法中不同的参数,散装、对象、map集合对应) </select>
-
标签
看官网给where标签(元素)的定义:
where 元素只会在子元素返回任何内容的情况下才插入 “WHERE” 子句。而且,若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除
所以,当where标签会自动智能地决定 where关键字和and的去留,你只管写就好了(但别忘了要加and)
<select id="selectByCondition" resultMap="brandMapper"> select * from tb_brand <where> //智能的where标签 <if test="status !=null"> and status = #{status} </if> <if test="companyName !=null and companyName!=''"> and company_name like #{companyName} </if> <if test="brandName !=null and brandName!=''"> and brand_name like #{brandName}; </if> </where> </select>
-
单条件动态查询(choose-when-otherwise )
-
情景:用户只选择一个条件进行查询,比如,在第一个文本框中选择 公司名,在第二个文本框中输入 华为 ,我们事先并不知道他要选哪个条件(你可能会想,这不是用上面的就能实现嘛,但是标签设计的用途不一样嘛,就像你可以用if-else if-else 也可以用switch-case-default一样)
-
示例:
类比:choose-when-otherwise 相当于 switch-case-default
<select id="selectBySingleCondition" resultMap="brandMapper"> select * from tb_brand where <choose> //相当于 switch ,最后只会有一个条件成立 <when test=" status !=null"> //相当于 case status = #{status} </when> <when test="companyName !=null and companyName !=''"> company_name like #{companyName} </when> <when test="brandName !=null and brandName !=''"> brand_name like #{brandName} </when> <otherwise> // 相当于default 1 = 1 </otherwise> </choose> </select>
3. 增(Mybatis的事务问题、主键返回)
增就没什么标签了,我们老老实实地用对象封装参数
<insert id="add" >
insert into tb_brand (brand_name,company_name,ordered,description,status)
values (#{brandName},#{companyName},#{ordered},#{description},#{status});
</insert>
sqlSession自动提交
但是,在按照正常流程写完代码后,你发现运行都正常,但是在数据库中就是没有新添加的结果,为什么呢,因为mybatis的事务问题,看日志会发现,添加成功后它没有提交,所以又回滚了;
那么我们可以手动用sqlSession设置开启事务,或者是在创建sqlSession的时候就设置自动开启
//自动开启事务
SqlSession sqlSession = sqlSessionFactory.openSession(true);
int status = 1;
String company_name = "当当";
int ordered = 50;
String brand_name = "挡挡";
String description = "致力于";
Brand brand = new Brand(company_name,brand_name,ordered,description,status);
mapper.add(brand);
//最后手动开启事务
sqlSession.commit();
sqlSession.close();
主键返回
我们想得到新添加的对象的id,于是有以下代码:
mapper.add(brand);
System.out.println(brand.getId());//获取这个对象的id,但是结果是0(没有设置时的默认值)
实际上在insert语句执行的时候就已经有Id了,只是还没有与对象绑定,我们只要在insert标签中设置这useGeneratedKeys ** 和keyProperty** 两个属性即可:
//添加的statement
//设置useGeneratedKeys为true,设置keyProperty为对象中的id字段(所以用对象封装参数!!!)
<insert id="add" keyProperty="id" useGeneratedKeys="true">
insert into tb_brand (brand_name,company_name,ordered,description,status)
values (#{brandName},#{companyName},#{ordered},#{description},#{status});
</insert>
这样一来,就可以查询到新添加的对象id了
4. 改(set 标签 )
-
修改全部字段
简单的sql语句:
<update id="updateById"> update tb_brand set status =#{status}, company_name = #{companyName}, brand_name = #{brandName}, ordered = #{ordered}, description = #{description}, //封装成对象或者map集合都可 where id = #{id} </update>
-
修改动态字段
有时不是要修改所有,所以还是和查一样,我们用 if标签 判断,用set标签 解决多余的逗号和set关键字问题
<update id="updateById" > update tb_brand <set> <if test="status !=0"> status = #{status}, </if> <if test="companyName!=null and companyName!=''"> company_name = #{companyName}, </if> <if test="brandName!=null and brandName!=''"> brand_name = #{brandName}, </if> <if test="ordered!=0"> ordered = #{ordered}, </if> <if test="description!=null and description!=''"> description = #{description}, </if> </set> where id = #{id} </update>
5.删
删除一个(基础语句)
<delete id="deleteById">
delete
from tb_brand
where
id = #{id}
</delete>
批量删除(for each标签 )
当用户选择了很多商品需要删除时
我们将ids封装成一个数组,或是list集合均可,下面代码是封装成集合的代码:
- mapper接口方法:
int deleteByMulId(List<Integer> ids);
- 对应statement:
<delete id="deleteByMulId">
delete
from tb_brand
where id in
<foreach collection="list" separator="," item="id" open="(" close=")">
#{id}
</foreach>
</delete>
- 对于for each标签中的属性:
- collection属性:
根据mapper中形参的不同,分别对应:
array 当形参为数组时
list 当形参为list集合时 (比如我这个例子)
或者是arg0(和后面mybatis封装参数的底层原理)
或者是你对形参进行@params注解的参数名称!如下:
int deleteByMulId(@Param("ids") List<Integer> ids);
于是,我们才可以在collection属性中用 “ids”,否则会报错!!!
<foreach collection="ids" separator="," item="id" open="(" close=")">
#{id}
</foreach>
- item属性:很简单,就是给每一个元素的名字
- seperator属性:分隔符,因为在sql语句中, in 后面要加的一系列值是用逗号分隔开的
- open和close属性:表示此语句分别以open和close中的字符开始和结束(这样左右括号就不用打在外面了)