当前位置: 首页> 教育> 高考 > 金华疫情最新消息_大气的公司名字_个人网页制作完整教程_百度网站入口

金华疫情最新消息_大气的公司名字_个人网页制作完整教程_百度网站入口

时间:2025/7/8 23:19:23来源:https://blog.csdn.net/m0_59176231/article/details/145741934 浏览次数:0次
金华疫情最新消息_大气的公司名字_个人网页制作完整教程_百度网站入口

MyBatisPlus自定义sql

在说怎么实现之前我们要先明白一个概念,就是mybatis-plus是在mybatis的基础上进行增强,并不做改变,所以mybatis的操作在mybatis-plus中也是一样可以使用的,咱们直接上代码.

1、单纯地使用注解自定义SQL

image-20230715121432056

image-20230715121542720

image-20230715121549283

image-20230715121556142

image-20230715121601683

image-20230715121609607

image-20230715121616776

image-20230715121624576

数据库数据:

image-20230715121653508

执行测试方法后结果如下:

image-20230715121730509

注意:这里我们把MybatisPlusConfig这个类注释掉,持久层的类使用@Mapper注解,也是一样可以运行的哈。

image-20230715121811876

image-20230715121940139

结果:

image-20230715122039249

2、使用注解加标签做自定义sql

展示1:使用if标签

image-20230715134039362

image-20230715134358902

image-20230715134349472

image-20230715134415320

结果:

image-20230715134546780

展示2:使用foreach标签

image-20230715140024541

image-20230715140133377

image-20230715140144203

image-20230715140154121

结果:

image-20230715140255069

展示3:使用foreach标签

下面我们使用id来查找一下:

image-20230715141029044

image-20230715141056024

image-20230715141108839

image-20230715141122343

结果:

image-20230715141149419

扩展知识点:{} 和 ${} 的区别?

一、区别概述
1.1、主要区别:

1、#{} 是预编译处理,${} 是直接替换

2、${} 存在SQL注入的问题,而 #{} 不存在;

Ps:这也是面试主要考察的部分~

1.2、细节上:

1、${} 可以实现排序查询,#{} 不能实现排序查询。

2、${} 可以直接进行模糊查询(但不建议,存在 SQL 注入问题),#{} 不可以直接进行模糊查询,但可以通过 mysql 内置函数 concat() 实现模糊查询(不存在 SQL 注入问题)。

二、具体描述
2.1、预编辑处理 vs 直接替换

预编辑处理:是指 MyBatis 在处理 #{} 时,就是把 #{} 替换成了 ?号,使用 PreparedStatement 的 set 方法来赋值。也就是说 #{} 会把 {} 内的整体看成 value ,最后再给 value 加上单引号,重点强调引号内部是一个整体( #{} 不会发生 SQL 注入的根本原因)。

直接替换:是指 MyBatis 在处理 ${} 时,会把 ${} 替换成变量的值(不会加引号处理)。

2.2、SQL 注入问题
2.2.1、引发 SQL 注入

例如现在有一个登陆程序,需要输入正确的账户和密码才能登录,当使用了 SQL 注入就可以在不知道密码的情况下进行登录,如下

xml 文件如下:

    <select id="login" resultType="com.example.demo.entity.Userinfo">select * from userinfo where username = '${username}' and password = '${password}'</select>

接口如下:

    /*** 登录逻辑* @param username* @param password* @return*/Userinfo login(@Param("username") String username,@Param("password") String password);

测试方法如下:

    @Testvoid login() {String username = "admin";String password = "' or 1 = '1";Userinfo userinfo = userMapper.login(username, password);System.out.println("登录状态:" + (userinfo == null ? "失败" : "成功"));}

执行结果如下:

image-20230715141958720

2.2.2、SQL 注入分析

可以在运行结果的日志中看到,我们最后执行的SQL语句如下:

image-20230715142046172

在 MySQL 中 1 = ‘1’ 结果必然为 true,所以不难分析出,如上 SQL 一定会将这张表中的用户全部返回(即使账号都填写错了,照样返回,因为1 = ‘1’ 必然为 true );

使用 ${} 的注意事项:一定是可以穷举的值,在使用之前一定要对传递的值进行合法性验证(在Controller中通过穷举的方式验证安全性)。

2.3、排序查询

使用 ${} 可以实现排序查询,而 #{} 不可以实现排序查询,因为使用 #{} 查询时,如果传递的值为 String 就会加单引号,导致 sql 错误。

例如你期望的 sql 语句为:select * from userinfo order by id desc;

而 #{sort} 中传入的是一个 String 类型的值为 “desc”;

那么最终实际的 sql 语句为:select * from userinfo order by id ‘desc’;这必然是错误的~

2.4、like 查询
2.4.1、${} 模糊查询
方式一:直接替换 
<select id="likeSelect" resultType="com.example.demo.entity.Userinfo">select * from userinfo where username like '%${key}%'
</select>方式二:使用concat进行字符串拼接
<select id="likeSelect" resultType="com.example.demo.entity.Userinfo">select * from userinfo where username like concat('%', '${key}', '%')
</select>

Ps:虽然可以这样,但并不建议使用 ${} 进行模糊查询,因为存在 SQL 注入问题。

2.4.2、#{} 模糊查询
<select id="likeSelect" resultType="com.example.demo.entity.Userinfo">    select * from userinfo where username like concat('%', #{key}, '%')
</select>
2.4.3、#{} 模糊查询问题分析

你期望的 sql 语句:select * from user where username = ‘%abc%’;

然而当你使用 #{} 传入的参数会自带引号,于是就变成了:select * from user where username = ‘%’ abc ‘%’;

注意:

注意一点:接口里面的形参如果没有使用@Param注解,那么你sql里面就不能直接用${}

image-20230715145409957
1)使用@Param注解当以下面的方式进行写SQL语句时:@Select("select column from table where userid = #{userid} ")public int selectColumn(int userid);当你使用了使用@Param注解来声明参数时,如果使用 #{} 或 ${} 的方式都可以。@Select("select column from table where userid = ${userid} ")public int selectColumn(@Param("userid") int userid);当你不使用@Param注解来声明参数时,必须使用使用 #{}方式。如果使用 ${} 的方式,会报错。@Select("select column from table where userid = ${userid} ")public int selectColumn(@Param("userid") int userid);2)不使用@Param注解不使用@Param注解时,参数只能有一个,并且是Javabean。在SQL语句里可以引用JavaBean的属性,而且只能引用JavaBean的属性。// 这里id是user的属性@Select("SELECT * from Table where id = ${id}")Enchashment selectUserById(User user);

3、注解使用条件构造器来做查询条件

扩展知识点Wrapper中的方法

关于Wrapper中的一些方法,介绍如下:

  1. eq:等于,ne:不等于

  2. gt:大于,ge:大于等于,lt:小于,le:小于等于

  3. between:在值1和值2之间,notBetween:不在值1和值2之间

  4. like:’%值%’,notLike:’%值%’,likeLeft:’%值’,likeRight:‘值%’

  5. isNull:字段 IS NULL,isNotNull:字段 IS NOT NULL

  6. in:字段 IN (v0, v1, …),notIn:字段 NOT IN (value.get(0), value.get(1), …)

  7. or:拼接 OR,AND 嵌套

    注意事项:

主动调用or表示紧接着下一个方法不是用and连接!(不调用or则默认为使用and连接)

  1. exists:拼接 EXISTS ( sql语句 ),notExists:拼接 NOT EXISTS ( sql语句 )

  2. orderByAsc:排序:ORDER BY 字段, … ASC,orderByDesc:排序:ORDER BY 字段, … DESC

想要了解详细点可以看:https://blog.csdn.net/llllllkkkkkooooo/article/details/108216957

使用QueryWrapper

演示如下:

image-20230715152832978

image-20230715152849768

image-20230715152901915

image-20230715152927059

效果:

image-20230715153005548

使用LambdaQueryWrapper

上面的这个条件构造器也可以使用LambdaQueryWrapper来做。

比如:

image-20230715153859139

效果如下:

image-20230715153956343

e w . s q l S e g m e n t 相当于是拿到条件构造器里面的查询条件们,但是注意:条件构造器中,其实,不止有 {ew.sqlSegment}相当于是拿到条件构造器里面的查询条件们,但是注意:条件构造器中,其实,不止有 ew.sqlSegment相当于是拿到条件构造器里面的查询条件们,但是注意:条件构造器中,其实,不止有{ew.sqlSegment}可以使用。还有 e w . s q l S e l e c t , {ew.sqlSelect}, ew.sqlSelect{ew.customSqlSegment}, e w . s q l S e t 等等。他们都相当于是 e w 对象中的属性, {ew.sqlSet}等等。他们都相当于是ew对象中的属性, ew.sqlSet等等。他们都相当于是ew对象中的属性,{}只是用来取那些属性的。

关于ew

具体的如下:

  1. ew.customSqlSegment相当于是ew中定义的所有查询条件,并且会直接在sql中会在使用的时候先添加 where,即,你sql中可以不用写那个where了

    使用例子如下:

    @Select(select * from sys_user ${ew.customSqlSegment}List<SysUser> listPage(@Param(Constants.WRAPPER)  QueryWrapper queryWrapper)
    
  2. ew.sqlSegment属性相当于是ew中定义的所有的查询条件,但是不会加where

    使用例子如下:

     @Select(select * from sys_user  where ${ew.sqlSegment}List<SysUser> listPage@Param(Constants.WRAPPER) QueryWrapper queryWrapper)
    
  3. ew.sqlSelect属性相当于是ew中所有你通过queryWrapper.select(……) 所定义查询的字段

    @Select(select ${ew.sqlSelect} from sys_user  )
    List<SysUser> listPage(@Param(Constants.WRAPPER) QueryWrapper queryWrapper)
    
    <select id="selectUser" resultType="com.example.demo.entity.User">select<if test="ew != null and ew.sqlSelect != null and ew.sqlSelect != ''">${ew.sqlSelect}</if>fromsys_userwhere is_deleted != 1<if test="ew != null"><if test="ew.nonEmptyOfWhere">AND</if>${ew.sqlSegment}</if></select>
    
  4. ew.sqlSet属性用于update语句

    例子:

    Mapper接口:

    @Mapper
    @Repository
    public interface UserMapper extends BaseMapper<User> {List<User> queryAll(@Param("tableName") String tableName,@Param(Constants.WRAPPER) Wrapper wrapper);boolean updateById(@Param("tableName") String tableName,@Param("id") int id,@Param(Constants.WRAPPER) Wrapper wrapper);//若变量名为ew则无需注解
    }
    

    XML:

    <select id="queryAll" resultType="cn.alan.mybatis.POJO.User">select ${ew.sqlSelect} from ${tableName} ${ew.customSqlSegment};
    </select><update id="updateById">update ${tableName} set ${ew.sqlSet} ${ew.customSqlSegment};
    </update>
    

    等效select SQL:select * from user where age = 10;

    等效update SQL:update user set name = 5 where id = 5;

    Controller(或Test):

        @AutowiredUserServiceImpl userService;@RequestMapping("/query")public List<User> queryAll(){QueryWrapper<User> wrapper = new QueryWrapper<>();wrapper.select("*").eq("age","10");return  userService.queryAll("user",wrapper);//return userService.queryAll("user", Wrappers.query().select("*").eq("age","10"));}@RequestMapping("/update")public boolean upDateById(){UpdateWrapper<User> wrapper = new UpdateWrapper<>();wrapper.set("name","5").eq("id","5");return userService.updateById("user",5,wrapper);//return userService.updateById("user",5,Wrappers.update().set("name","5").eq("id",5));}
    }
    
  5. ew.nonEmptyOfNormal这个属性定义在Wrapper类中,用于判断查询条件是否不为空

  6. ew.nonEmptyOfWhere这个属性是用于判断你的这个ew中查询条件是否不为空的。

  7. ew.emptyOfWhere这个属性定义在Wrapper类中,用于判断where条件是否为空的。

下面具体演示一些上面这些ew属性的使用:

image-20230715164955345

image-20230715165007582

image-20230715165019299

image-20230715165036002

结果:

image-20230715165135691

使用条件构造器多表联查

注意:

使用${ew.sqlSegment}的话,如果是多表查询且查询条件是多个表的字段,那么则需在service层拼接查询条件时字段前指定别名,而且不能用lambda的条件构造器来做查询了。因为多表查询的话,如果你两个表里面有需要区分的字段,比如两个表里面都有name,你sql里面的where后面一般写为where user.name=‘张三’ and ……这种的,这个“表名.字段名”这种东西用lambda的条件构造器是写不出来的。但是如果直接用字段名就可以区分的情况,就可以用lambda的条件构造器,没有关系的。

直接用字段名就可以区分的情况,例子:

数据库里面的edu_course如下:

image-20230716113022998

image-20230716111926562

image-20230716112010679

image-20230716112026352

image-20230716112044355

运行,但是结果如下:

image-20230716110955705

解决方案一:修改数据源的版本

解决方案二:你新建一个实体类来接收返回的数据,不用List<Map<String,Object>>类型来接收了,但是注意你新建的这个实体类要是包含两个表的字段了,因为是多表查询的结果对应的实体类嘛,然后我们在这个新建的实体类里面我们让create_time这个字段被Date类型的实体类属性来接收就行了,就像是单表查询里面我们写的实体类那样。

我们之前单表对应的实体类的接收create_time字段的属性的类型是Date类型的,所以之前没有出现这个问题,如下:

image-20230716111319048

这里我们采用第一种解决方法,修改druid的版本号为1.1.21或者1.1.21以上的版本就行了。

image-20230716111037733

修改后,运行结果如下:

image-20230716112703339

就相当于是数据库里面是这样的sql:

image-20230716112912701

可以看到sql里面没有需要区分的字段,所以可以用lambda的写法。

但是如果我们把id也作为查询条件呢?

image-20230716113251073

因为两个表都有id,所以会查询失败。上面这里就相当于这样的sql执行:

image-20230716113356852

看到错误一样。

解决方法就是用“表名.字段名”来表示查询使用哪个表的id作为查询条件。

image-20230716113539659

但是LambdaQueryWrapper是根据字段来映射的,是自动的,所以你不好改变查询条件里面的字段名。而且,上面LambdaQueryWrapper这个例子里面,这里你查询结果是有两个id字段的,那么查询结果将会用哪个id放在我们返回对象里面呢?我们看到,上面的例子里面,返回结果里面就封装了edu_teacher表里面的id,而edu_course里面的id是被舍弃了,反正,不管取哪一个,都会有一个id消失了。即,查询结果中名字重复的字段只会保留一个。这样不好。

所以,建议还是用QueryWrapper来做多表的查询条件,不用LambdaQueryWrapper做多表的查询条件。

例子:

image-20230716120817855

image-20230716120829193

image-20230716120842334

image-20230716121126057

结果:

image-20230716121159696

对于上面这个QueryWrapper,我们其实都没有用到这个EduTeacher,所以我们这样写也行:

image-20230716121559444

image-20230716121612057

image-20230716121622796

但是这样,我们不能用链式编程了:

image-20230716121737852

但是我们可以这样写:

image-20230716121758354

执行结果:

image-20230716121833058

其实相当于下面这样的sql执行:

image-20230716122018231

当然哈,你也可以自己新建一个实体类,然后用这个新建的实体类接收查询的结果。但是你要是嫌麻烦的话,还是用上面这个List<Map<String,Object>>来接收吧。

例子1:

image-20230716162613207

image-20230716162310015

image-20230716162629741

image-20230716162641735

image-20230716162656937

结果:

image-20230716162728345

4、自定义查询加上分页

其实就是先写好分页插件的配置,然后dao层接口方法的形参上面写一个IPage的参数,返回值改为IPage,到时候调用的时候把设置好参数后的IPage传过来就可以了,不用在dao层的方法上面写什么其他东西的。

具体如下:

image-20230716172054966

image-20230716172258205

image-20230716172311356

image-20230716172322469

image-20230716172512073

结果:

image-20230716172627217

要给自定义的多表查询加上分页也一样哈,就写好分页插件的配置,然后dao层接口分页方法的形参上面写一个IPage的参数,返回值改为IPage,到时候调用的时候把设置好参数后的IPage传过来就可以了,不用在dao层的方法上面写什么其他东西。

例子如下:

image-20230716173950505

image-20230716174123823

image-20230716174135836

image-20230716174200291

结果:

image-20230716174253819

数据查询结果不是封装到一个实体类里面的,而是放在一个Map集合里面的,那么我们得怎么加上分页呢?也是和前面一样的,就是接口的那个方法里面的第一个参数写的IPage中泛型改为Map<String,Object>就行了。

例子:

image-20230716175523527

image-20230716175539917

image-20230716175550863

image-20230716175622073

结果:

image-20230716175737976

5、使用第三方工具做多表查询

上面我们做多表查询都是要自己写sql的,还是比较麻烦的,下面介绍一种不用自己写sql的方式来完成多表查询。

这个第三方工具是一个大佬封装的一个jar包,即mybatis-plus-join架包,这个架包可以支持MyBatis-Plus的多表联查。

官网如下:https://mybatisplusjoin.com/

或者你看这个博主写的也行:https://blog.csdn.net/weixin_39555954/article/details/128217887

快速入门的使用

一、引依赖

注意:要求mybatis plus version >= 3.4.0

<dependency><groupId>com.github.yulichang</groupId><artifactId>mybatis-plus-join</artifactId><version>1.2.4</version>
</dependency>
二、使用方法

mapper继承MPJBaseMapper (必选)
service继承MPJBaseService (可选)
serviceImpl继承MPJBaseServiceImpl (可选)

三、(实战)多表查询
MPJLambdaWrapper<Map> mpjLambdaWrapper = new MPJLambdaWrapper();
mpjLambdaWrapper.select(ChatRecord::getId,ChatRecord::getRedMoney).select(OfShopMembers::getUsablePoint).select(ChatMultiList::getName).leftJoin(OfShopMembers.class,OfShopMembers::getId,ChatRecord::getId).leftJoin(ChatMultiList.class,ChatMultiList::getId,ChatRecord::getMultiId).eq(ChatRecord::getMemberId,3213);
List list = chatRecordMybatisJoinMapper.selectJoinList(Map.class, mpjLambdaWrapper);

对应查询语句

SELECT t.id,t.red_money,t1.username,t2.name 
FROM chat_record t 
LEFT JOIN of_shop_members t1 ON (t1.id = t.id) 
LEFT JOIN chat_multi_list t2 ON (t2.id = t.multi_id) 
WHERE (t.member_id = 3213)

参数说明
1、select:表示查询的指定字段,一个select只能查一个表的
2、leftJoin:
第一个参数: 参与连表的实体类class
第二个参数: 连表的ON字段,这个属性必须是第一个参数实体类的属性
第三个参数: 参与连表的ON的另一个实体类属性
3、默认主表别名是t,其他的表别名以先后调用的顺序使用t1,t2,t3…

四、(实战)多表分页查询
MPJLambdaWrapper<Map> mpjLambdaWrapper = new MPJLambdaWrapper();mpjLambdaWrapper.select(ChatRecord::getId,ChatRecord::getRedMoney).select(OfShopMembers::getUsablePoint).select(ChatMultiList::getName).leftJoin(OfShopMembers.class,OfShopMembers::getId,ChatRecord::getId).leftJoin(ChatMultiList.class,ChatMultiList::getId,ChatRecord::getMultiId).eq(ChatRecord::getMemberId,3213).orderByDesc(ChatRecord::getAddTime);Page page = new Page(1,2);IPage<Map> mapIPage = chatRecordMybatisJoinMapper.selectJoinPage(page, Map.class, mpjLambdaWrapper);

对应查询语句

SELECT t.id,t.red_money,t1.usable_point,t2.name 
FROM chat_record t 
LEFT JOIN of_shop_members t1 ON (t1.id = t.id) 
LEFT JOIN chat_multi_list t2 ON (t2.id = t.multi_id)
WHERE (t.member_id = 3213) 
ORDER BY t.add_time 
DESC 
LIMIT 2

我的测试:

一、引入依赖

这里我们测试的项目使用的是3.4.1的mybatis-plus-boot-starter

image-20230716181148224

我们进去看看里面指定的mybatis-plus的版本:

image-20230716181234084

看到是3.4.1版本的mybatis-plus,所以可以放心引入依赖了。

引入好后如下:

image-20230716181350962

二、建表

我们新建三个表用来演示:

这三个表如下:

image-20230717092513762

image-20230717092533898

image-20230717092545652

三、新建实体类

image-20230717103553780

image-20230717103612983

image-20230717103634367

image-20230717104016887

这个DTO里面写你要多表查询的全部数据。

四、新建dao层的接口

image-20230717143723744

image-20230717143813308

image-20230717143824957

五、我们直接测试
测试一:多表查询

你可以把下面的测试代码当作service层的代码。

image-20230717143949138

结果:

image-20230717144026858

我们修改一下查询条件,看看结果:

image-20230717144136302

结果:

image-20230717144149992

测试二:多表分页查询

image-20230717145108414

结果:

image-20230717145205752

数据库我们执行sql的结果如下(下面的这个sql执行的时候是没有带分页的limit的):

image-20230717145449784

看到,两个一组,第一组里面就是id为4和id为5的数据。所以测试完全正确。

但是要注意:这里之前是配置了分页插件的,要是没有配置分页插件,上面的执行结果不会有分页效果的。

image-20230717145631612

测试三:多表分页查询且自定义别名

image-20230717151346435

结果:

image-20230717151413394

测试四:多表查询分页且不把数据封装到实体类里面

image-20230717152103699

结果:

image-20230717152132917

测试五:多表分页查询,不封装到实体类,自定义别名

image-20230717153006733

结果:

image-20230717153050937

关键字:金华疫情最新消息_大气的公司名字_个人网页制作完整教程_百度网站入口

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

责任编辑: