摘要:主要讲述mybatis修改、删除以及最后的查询操作以及其中遇到的问题我们如何演变的!
1、先说修改商品的测试修改操作案例
(1)在上一次创建的mybatis项目的,test测试包下的product下创建一个mapper包,包下创建一个BrandMapperTest测试类,主要对商品做一个修改。(项目目录结构看(3)第三步骤的图片)
@Test
void testUpdateById() {
Brand brand = new Brand();
brand.setId(11L);
brand.setName("测试品牌-011");
brand.setPinyin("ceshipinpai-011");
//brand.setLogo("http://www.alibaba.com/brand-11.png");
int rows = mapper.updateById(brand);
log.debug("根据id修改品牌完成,受影响的行数={}", rows);
}
(2)BrandMapper.xml中我们配置如下,使用动态SQL:修改数据。对比这两个代码有什么区别而已,比如SET中我们修改为了<set>。因为使用SET字段的sql语句,而不用<set>标签的话,我们在修改名称或者拼音等字段,而不添加<if ...>....description....</if>修改description的时候,我们就会发现数据库description字段的值突然为null了,我们希望description在其他修改的同时不跟着其他字段一起改变。所以我们需要用到<set>。这里建议结合数据库进行操作。
<!-- int updateById(Brand brand); -->
<update id="updateById">
UPDATE
pms_brand
<set>
<if test="name != null">
name=#{name},
</if>
<if test="pinyin != null">
pinyin=#{pinyin},
</if>
<if test="logo != null">
logo=#{logo},
</if>
<if test="description != null">
description=#{description},
</if>
<if test="keywords != null">
keywords=#{keywords},
</if>
<if test="sort != null">
sort=#{sort},
</if>
<if test="sales != null">
sales=#{sales},
</if>
<if test="productCount != null">
product_count=#{productCount},
</if>
<if test="commentCount != null">
comment_count=#{commentCount},
</if>
<if test="positiveCommentCount != null">
positive_comment_count=#{positiveCommentCount},
</if>
<if test="enable != null">
enable=#{enable},
</if>
</set>
WHERE
id=#{id}
</update>
(3)第三步最后一步,我们把java包下的mapper中的BrandMapper创建出来,因为代码量比较少,这里不放其他代码了出来了。然后总的项目结构如图。
注意事项:我们一般插入、删除、修改但除了查询之外,都是返回整数类型,以便于我们查看以后插入了多少条数据。
2、关于删除操作
在xml中我们关于删除的操作,我们根据是【需求】根据若干个id删除品牌数据,然后关于批量删除操作的sql语句先奉上
DELETE FROM pms_brand WHERE id=? OR id=? …… OR id=?;
DELETE FROM pms_brand WHERE id IN (?, ?, .... ?);
(1)我们首先将上面的sql语句放入到xml文件当中,代码如下
注意事项,item必须和下面的item的值必须一致,第二关于collection以及separator的值的问题。
关于
<foreach>
标签的属性:
collection
:表示被遍历的参数对象,当抽象方法的参数只有1个时,如果参数类型是List
,则此属性值为list
,如果参数类型是数组(或可变参数),则此属性值为array
item
:遍历过程中的每个元素的名称,是自定义的名称,并且,在<foreach>
标签内部,使用#{}
时的名称也就是此属性的值(此处自定义的名称)separator
:遍历过程中在值之前添加的分隔符号
(这里解释一下为什么要separator=',' , 比如我遍历后得到的id为13579,反正我们的意思是id=1,id=3 ... id=9..... 但是计算机不一样,他会认为这是“id等于一万三千五百七十九”。
所以本来我们要在#{id}后面加个逗号,变成 "#{id}," 但这还不够,毕竟之后这样就是id=1,id=3,id=5......id=9,??? 后面逗号明显少了一位就会造成语法错误。
所以我们要在逗号后面加个不存在的id值,比如我加个id=998或者你自己想取一个随意且不存在的值都可以。比如id=-1或id=-998,变成了id=1,id=3,id=5......id=9,id=-998这样语法就正确了。但是我们也不这么干,太麻烦了所以就有(1)中的图。加入了separator的值,比如他有8个值就会给7个逗号,不会给多的)
最后,完成后,在BrandMapperTests
中编写并执行测试:
3、关于查询
关于查询首先引入一个问题案例,从而引出为什么会有pojo这个东东并学习阿里的规范
根据一般套路:查询不写入create和modified,即创建的时间和修改的时间,因为一般这两个字段是用来在日志中排查问题的。比如如果是年代久远的话比如QQ账号在1998年记录太远了,所以我们一般不加入查询问题。(当我插入insert或者修改update才把这两个数据给上。)sql语句如下
紧接下面Test的内容
问题一:假如mapper和sql都是我写的,红色方块中是你在查询。那么我就可以在mapper调用这个对象的get方法,但是但是你来调用getGmtCreate和getGmtModified调用并返回的值,我们都知道最后的返回是没有值的,因为我查询的时候sql语句根本没查询这两个字段。团队存在歧义。
再说了:一般返回值是Brand类型的, 但是包含了所有字段,但是我们查询就包括了所有字段,和数据表对应,包括了创建时间和修改时间,但我们一般不查这两个字段。就耗费了计算的资源。
问题二:以下文字慎重看,还未简写总结!
(就是比如我一个团队,这个mapper以及前面的sql是我写的),你来调用getByUsername方法用于登录,突然发现User中信息有些字段比如getPassword有值,但有些字段比如getNickName()没有值。但是你再查询用户详细信息比如getById()突然所有属性都有值了。
就是说,问题在于你getByUsername()方法中,调用我的mapper后调用的sql语句有时候,我没写没查询对应的字段比如NickName,但是我getById()方法对应的sql语句却有提供了属性字段。总结来说就是你调用mapper查询方法的时候,有时候有查询这个属性字段有值,有时候没有值。要么就是我sql中有查询有写这个字段,要么就是数据库中这个值本来就没有。这个也很难区分。
总结就是,虽然返回都是user,但查询的结果就是有些属性结果有值,有些属性结果没有值怎么办?这就导致团队沟通有歧义。
所以不建议实体类型作为查询结果,因为有些字段是没有值,要么sql语句没有提供,所以我们引入了POJO类型,总结一句就是我们不修改sql语句情况下,我们sql要查什么就使用什么类型来接收,不适用原来固定的entity类型接收,从而对entity类型再做一个区分,比如我们sql查询结果以前用brand类型接收,但你sql语句没有查询nickname,以前的entity类型中除了创建时间和修改时间,比如品牌的类划分了,第一个接收全部但除了查标题,第二个接收但除了查姓名。
查看阿里开发手册
注意的点,就是不是因为遵从驼峰命名而第一个D大写,第二个O小写,而是要两个都大写
好嘞,以上为第一步,以下为第二步
得到了有效结果
第二个问题,关于字段名,列名,类属性名冲突的问题
区分一下,字段名就是数据库创建开始的时候每一列的名字。列名是我们在sql语句查询出来的结果中的一列叫列名(注意说到列名就联想到是结果),类属性名就是我们的类中的属性。
接着以上的项目,名称查出来了,但是往后看会发现产品数量等一些属性查不出来,但是这个字段在数据库中是有值的,原因就是我们类中的属性名和数据库的字段名有一部分比如姓名和年龄是一致的,但是后面的是不一致的。因为我类属性中的名称是private Integer productCount但是和途中的product_count不相同所以导致查不出来。
我们之前学过sql语句,我们可以给sql语句提供别名,如图:
但是也不符合我们的需求,我们不能给每个字段都这么写,因为不规范,我们参考了注解的方式
让他字段自适应,但是我们要再application.properties中做好配置
所以如红色部分所示,(因为代码后期有修改,但是不怕,照着写就可以了)
注意,主键一定要用id配置,而不是result来表示
我们对这个sql语句节点做一定的优化,为了让代码复用性、维护性更好
当然refied或id等值要规范点,最后就如下了
resultMap对应<sql>的id 和 refied对应resultMap的id,对上图进行一定说明
注意:就是idea对于mysql 有时候会报红色的下划线,但是并不会影响运行,不妨跑一下项目就知道了
最后关于idea的误判,这个是lombok插件引起的问题
解决方案就在BrandMapper中添加@Repositry注解,如图
第二个报错细节
解决方案要么就是关掉mysql的检查(极力不推荐),第二种就是加入<if>节点就不会报错了,如图
最后就是作业了,资料文章还未整理完成!希望各位等等
好嘞,今天暂时这样,有错误或者问题评论,请求指正!