MyBatis查询数据库之三(#{}vs${},like查询,resultMap,as,多表查询)

目录

查询操作

1.单表查询

1.1 参数占位符#{}和${}

1.2 ${}的优点

1.3 sql注入问题

​编辑

面试常问:${}与#{}的区别

1.4 like查询

2.多表查询

2.1 返回字典映射:resultMap

2.2 多表查询

(1)建立 Articalinfo 实体类:

(2)在 ArticleMapper 接口中写出通过用户id查询用户的方法

(3)在ArticleMapper.xml中实现接口的方法

(4)生成测试方法


查询操作

1.单表查询

下面我们来实现⼀下根据用户 id 查询用户信息的功能

UserController 实现代码如下:


    @RequestMapping("/getuserbyid")
    public Userinfo geUserById(Integer id){
        if (id==null)
            return null;
        return userService.getUserById(id);
    }

UserMapper 实现代码如下:

/**
     * 根据用户id查询用户信息
     * @param id
     * @return
     */
    Userinfo getUserById(@Param("id") Integer id);

UserMapper.xml 实现代码如下:

<select id="getUserById" resultType="com.example.ssmdemo1.entity.Userinfo">
        select * from userinfo where id=${id}
</select>

1.1 参数占位符#{}和${}

  • #{}:预编译处理
  • ${}:字符直接替换

预编译处理是指:MyBatis 在处理#{}时,会将 SQL 中的 #{} 替换为?号,使用 PreparedStatement 的 set 方法来赋值。

直接替换:是MyBatis 在预处理 ${} 时,就会把 ${} 替换成变量的值。

在正常的我们用id来查询用户时:

都是没问题的,但是当我们用username来查询时:

可以看到在我们使用 # 符时是占位符,使用 $ 符则是直接替换了,int类型的自然没有问题,但是字符串类型的就有问题了

对于MySQL是要加单引号的,而$是啥都不加,所以是错误的!!

1.2 ${}的优点

有人会说,#{}这么好使的话为什么还会有${}的存在呢?

在进行排序时(需要传递关键字时)需要使用到${},而 #{sort} 就不能实现排序查询了,因为使用 #{sort} 查询时, 如果传递的值为 String 则会加单引号,就会导致 sql 错误。 

当使用#{}的时候呢? 

使用$是啥都不管,直接使用原样去替换,#会加上'' 

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

1.3 sql注入问题

先看两则对比:

在这里${}完美体现了它自身的特性,但是当我们改变一下password:

 这里就细思极恐了,当我们使用'${}'替换#{}的时候会这样,那不是只要我们知道别人的账号就可以登录别人的账户了吗!,我们来看看#{}会不会这样:

我们可以看到 $ 符是存在SQL注入的问题,而 # 不存在

我们使用了一个奇怪的字符时为什么会成功呢?

那 # 为什么不会这样呢?

它使用的是JDBC的预处理的方式,它就把password当成字符串即values来处理,只是值的替换,而不是SQl语句,这就是机制的不同的区别 

面试常问:${}与#{}的区别

  1. $ 存在失去了注入问题,而 # 不存在
  2. $ 是直接替换,# 是预处理

1.4 like查询

在使用like查询时,使用#{}会报错,下面我们来看看是怎么回事:

这是因为使用#{}会当作字符串进行替换,就变成下面这样了 

而使用 $ :

这里我们可以看到使用 $ 符是可以的,但是我们说过使用 $ 符一定要能穷举,但是这里的 '李' 是不能够穷举的 ,前面说了使用${}有SQL注入的风险,所有这是不能直接使用 ${},可以考虑使用 mysql 的内置函数 concat() 来处理,实现代码如下: 

<select id="findUserByName3" resultType="com.example.demo.model.User">
     select * from userinfo where username like concat('%',#{username},'%')
</select>

所以在使用like查询时应该搭配concat()函数使用。

2.多表查询

2.1 返回字典映射:resultMap

前面在xml 的 标签中写返回类型 resultType 时,直接就是定义到某个实体类就行,但这种情况只适用于字段名称和程序中属性名相同的情况下,这种就是写起来方便

但如果是字段名称和属性名不同时,继续使用 resultType 就会报错,此时就要使用 resultMap 来配置映射

在一对一、一对多关系中可以使用 resultMap 映射并查询数
 

使用场景:实现程序中属性和表中字段映射的功能(当程序中的属性和表中的字段不一致时,可以强行的映射到一起)

我们更改一下userinfo中的属性:

 

 

 

或者使用as关键字(数据库重命名)

 

 当程序中的属性与数据库中的字段不一致时解决方案:

  1. 使用 resultMap 标签(在 mapper.xml 中定义);
  2. 使用数据库别名 as 重命名。

2.2 多表查询

(1)建立 Articalinfo 实体类:

@Data
public class Articleinfo  {
    private int id;
    private String title;
    private String content;
    private String createtime;
    private String updatetime;
    private int uid;
    private int rcount;//阅读量
    private int state;
}

新增一个ArticleinfoVO实体类来帮助完成:

@Data
public class ArticleinfoVO extends Articleinfo implements Serializable {
    private String username;
}

(2)在 ArticleMapper 接口中写出通过用户id查询用户的方法

@Mapper
public interface ArticleMapper  {
    ArticleinfoVO getById(@Param("id") Integer id);
}

(3)在ArticleMapper.xml中实现接口的方法

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.mapper.ArticleMapper">

    <select id="getById" resultType="com.example.demo.eneity.vo.ArticleinfoVO">
        select a.*,u.username from articleinfo a
        left join userinfo u on u.id=a.uid
        where a.id=#{id}
    </select>
</mapper>

(4)生成测试方法

@SpringBootTest
class ArticleMapperTest {

    @Autowired
    private ArticleMapper articleMapper;


    @Test
    void getById() {
        ArticleinfoVO articleinfoVO = articleMapper.getById(1);
        System.out.println(articleinfoVO);
    }
}

我们发现:

 明明上面已经有结果了,但是下面的打印只有扩展字段,基类的字段去哪了?

 我们来梳理一下多表查询所经历的历程:

  1. 查询
  2. 打印

我们通过打点来看看是哪一步出现了错误:

我们可以得到:查询操作是没有问题的

所以问题出在了打印这里了

我们去查看字节码后发现

我使用的是Lombok的toString,而它只给我打印了一个拓展字段

这时候我们不需要Lombok的打印了,我们重写toString方法

在toString的时候加上父类的toString

 

 

 当存在Lombok的toString方法和用户的toString方法时,打印选择的是用户的方法!!用户大于一切

最终的一个实现:联表查询语句(left join/inner join)+XXXVO 解决。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/67649.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Qt 使用QLabel的派生类实现QLabel的双击响应

1 介绍 在QLabel中没有双击等事件响应&#xff0c;需要构建其派生类&#xff0c;自定义信号(signals)、重载事件函数(event)&#xff0c;最后在Qwidget中使用connect链接即可&#xff0c;进而实现响应功能。 对于其余没有需求事件响应的QObject同样适用。 此外&#xff0c;该功…

【OpenVINOSharp】 基于C#和OpenVINO2023.0部署Yolov8全系列模型

基于C#和OpenVINO2023.0部署Yolov8全系列模型 1 项目简介1.1 OpenVINOTM 2 OpenVinoSharp2.1 OpenVINOTM 2023.0安装配置2.2 C 动态链接库2.3 C#构建Core推理类2.4 NuGet安装OpenVinoSharp 3 获取和转换Yolov8模型3.1 安装ultralytics3.2 导出yolov8模型3.3 安装OpenVINOTM Pyt…

XXL-Job 具体通过docker 配置,再通过springboot执行注册实现完整流程

【2023】XXL-Job 具体通过docker 配置安装容器&#xff0c;再通过springboot执行注册实现 一、概述二、安装1、拉取镜像2、创建数据库3、创建容器并运行3、查看容器和日志4、打开网页 127.0.0.1:9051/xxl-job-admin/ 三、实现注册测试1、创建一个SpringBoot项目、添加依赖。2、…

python 基础

1.Python 1.1 环境搭建&#xff1a;官网下载python&#xff0c;编译器&#xff1a;pycharm或jupyter 1.2 变量 &#xff08;1&#xff09;语法&#xff1a;变量名变量 &#xff08;2&#xff09;标识符命名规则&#xff1a;由数字、字母、下划线组成&#xff1b;不能以数字…

ORACLE和MYSQL区别

1&#xff0c;Oracle没有offet,limit&#xff0c;在mysql中我们用它们来控制显示的行数&#xff0c;最多的是分页了。oracle要分页的话&#xff0c;要换成rownum。 2&#xff0c;oracle建表时&#xff0c;没有auto_increment&#xff0c;所有要想让表的一个字段自增&#xff0c…

Dockerfile 简单实战

将flask项目打包成镜像 1. 准备flask文件 创建 app.py 文件&#xff0c;内容如下 from flask import Flask app Flask(__name__)app.route(/) def hello_world():return Hello Worldif __name__ __main__:app.run(host0.0.0.0, port8000, debugTrue) 并开启外网访问&#xf…

【2.1】Java微服务: Nacos的使用

目录 Nacos介绍 Nacos安装 下载和安装 修改端口 启动 服务注册与发现 导入Nacos管理依赖 导入服务依赖 配置Nacos的服务地址 启动服务&#xff0c;查看已注册的服务 服务分级存储模型 分级存储模型介绍 具体结构 配置实例集群 同集群优先的负载均衡策略 服务权重配置…

电力系统电流三段式保护MATLAB仿真模型

整体模型如下&#xff1a; Matlab/Simulink搭建的电力系统电流保护模型采用辐射型单电源供电的运行方式 Ⅰ段保护的搭建 Ⅰ段保护为瞬时速断保护&#xff0c;根据Ⅰ段整定原则确定整定值。线路发生短路故障时&#xff0c;短路电流急剧增大&#xff1b;超过设置的整定值时&…

06微服务间的通信方式

一句话导读 微服务设计的一个挑战就是服务间的通信问题&#xff0c;服务间通信理论上可以归结为进程间通信&#xff0c;进程可以是同一个机器上的&#xff0c;也可以是不同机器的。服务可以使用同步请求响应机制通信&#xff0c;也可以使用异步的基于消息中间件间的通信机制。同…

栈和队列OJ题讲解

&#x1f493;博主个人主页:不是笨小孩&#x1f440; ⏩专栏分类:数据结构与算法&#x1f440; 刷题专栏&#x1f440; C语言&#x1f440; &#x1f69a;代码仓库:笨小孩的代码库&#x1f440; ⏩社区&#xff1a;不是笨小孩&#x1f440; &#x1f339;欢迎大家三连关注&…

vue3多条件搜索功能

搜索功能在后台管理页面中非常常见&#xff0c;本篇就着重讲一下vue3-admin-element框架中如何实现一个顶部多条件搜索功能 一、首先需要在vue页面的<template></template>中写入对应的结构 <!-- 搜索 --><div style"display: flex; justify-content…

【大数据】Flink 从入门到实践(一):初步介绍

Flink 从入门到实践&#xff08;一&#xff09;&#xff1a;初步介绍 Apache Flink 是一个框架和分布式处理引擎&#xff0c;用于在 无边界 和 有边界 数据流上进行 有状态 的计算。Flink 能在所有常见集群环境中运行&#xff0c;并能以内存速度和任意规模进行计算。 1.架构 1…

[mongo]应用场景及选型

应用场景及选型 MongoDB 数据库定位 OLTP 数据库横向扩展能力&#xff0c;数据量或并发量增加时候架构可以自动扩展灵活模型&#xff0c;适合迭代开发&#xff0c;数据模型多变场景JSON 数据结构&#xff0c;适合微服务/REST API基于功能选择 MongoDB 关系型数据库迁移 从基…

测试人员该怎样写软件缺陷报告?

软件测试过程中&#xff0c;每个公司都制订了软件的缺陷处理流程&#xff0c;每个公司的软件缺陷处理流程不尽相同&#xff0c;但是它们遵循的最基本流程是一样的&#xff0c;都要经过提交、分配、确认、处理、复测、关闭等环节&#xff0c;如图1所示。 缺陷处理流程 关于图1所…

Windows环境下通过 系统定时 执行脚本方式 压缩并备份文件夹 到其他数据盘

环境配置 压缩时需要使用7-zip进行调用&#xff0c;因此根据自己电脑进行安装 官网&#xff1a;https://www.7-zip.org/ 脚本文件 新建记事本文件&#xff0c;重命名为git_back_up.bat echo off rem 设置utf-8可以正常显示中文 chcp 65001 > nulrem 获取当前日期和时间&…

系统架构设计师-系统可靠性分析与设计

目录 一、可靠性相关基本概念 二、可靠性指标 1、串联系统与并联系统可靠性指标计算 2、混合系统 三、可靠性设计 1、影响软件可靠性的主要因素&#xff1a; 2、增加可靠性的解决方案 2.1 避错技术 2.2 降低复杂度设计 2.3 检错技术 2.4 容错技术 3、双机容错 一、可靠性相关…

【算法|数组】滑动窗口

算法|数组——滑动窗口 引入 给定一个含有 n 个正整数的数组和一个正整数 target 。 找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl1, ..., numsr-1, numsr] &#xff0c;并返回其长度**。**如果不存在符合条件的子数组&#xff0c;返回 0 。 示例…

Vue [Day5]

自定义指令 全局注册 和 局部注册 inserted在指令所在的元素 被插入到页面中时&#xff0c;触发 main.js import Vue from vue import App from ./App.vueVue.config.productionTip false// 1.全局注册指令 Vue.directive(focus, {// inserted在指令所在的元素 被插入到页…

机器学习中训练数据的重要性

人工智能技术发展至今&#xff0c;训练数据的重要性已经是我们老生常谈的问题。在重声训练数据为什么重要之前&#xff0c;我们先重新回顾下AI技术大爆炸的三大初始概念&#xff1a;机器学习是什么&#xff1f;人工智能是什么&#xff1f;训练数据又是什么&#xff1f; 机器学…

阿里云内容审核服务使用(图片审核)

说明&#xff1a;在项目中&#xff0c;我们经常会对用户上传的内容&#xff08;如文字、图片&#xff09;等资源内容进行审核&#xff0c;审核包括两方面&#xff0c;一方面是内容与描述不符&#xff0c;一方面是违反法律法规。本文介绍使用阿里提供的内容审核服务&#xff0c;…