【JavaEE】懒人的福音-MyBatis框架—[单表]增删改查等常规操作

【JavaEE】MyBatis框架要点总结(2)

在这里插入图片描述

文章目录

  • 【JavaEE】MyBatis框架要点总结(2)
    • 1. 单表查看操作
      • 1.1 (条件查询)通过id查找用户
        • 1.1.1 接口上声明方法
        • 1.1.2 xml文件中去实现方法
        • 1.1.3 测试
      • 1.2 传递参数的重点问题:sql注入问题
        • 1.2.1 ${}方式
        • 1.2.2 #{}方式
        • 1.2.3 必须用到${}的情景
        • 1.2.4 ${}和#{}的区别和注意事项
    • 2. 简单的增删改操作
      • 2.1 修改操作
      • 2.2 删除操作
      • 2.3 增加操作
    • 3. 模糊匹配like
    • 4. 常见疑问
      • 4.1 返回对象的属性名与字段名对应不上
        • 4.1.1 修改成一致
        • 4.1.2 重命名列名
        • 4.1.3 返回字典
        • 4.1.4 注解TableField
      • 4.2 sql关键字作为属性名
      • 4.3 传入的参数是多个对象

【JavaEE】MyBatis框架要点总结(2)

在上一篇文章中,我们主要讲解的内容就是MyBatis是什么,MyBatis环境的搭建,简单地体验了MyBatis的写法去查询数据库

  • 传送门:【JavaEE】懒人的福音-MyBatis框架—介绍、搭建环境以及初步感受_s:103的博客-CSDN博客

而本文的内容就是,MyBatis更深入的讲解,以及更多的数据库操作,如增删改查…

  • 值得注意的是,写法就是写法,记住它就好了,要使用框架就要遵守写法的规定,熟悉什么地方应该写什么…
    1. 没有 “为什么这么写” 等问题,就是规定
    2. 开发者不需要过多注意底层原理,“坐享其成”即可~
    3. 知道代码意味着什么,这么写框架会帮我们做什么就行

**知道怎么进行开发,这才是重点!**之后再去了解一下xml文件去实现接口的一些原理~

1. 单表查看操作

1.1 (条件查询)通过id查找用户

1.1.1 接口上声明方法

参数最好不要写基本数据类型,这是因为前端不传参数过来的话,可以传默认值

  • 但是基本数据类型的默认值是有含义的,例如0、0.0、‘/u0000’、false
  • 并且,如果前端没有传相应的参数,是会赋值为null的,基本数据类型无法赋值为null!

在这里插入图片描述

  • 服务器报错,服务器并不会关闭,只是捕捉到了异常打印了日志

对象中的成员是基本数据类型除外:

在这里插入图片描述

只有null表示真正意义的空

在这里插入图片描述

这个@Param注解的作用就是,确定这个参数替换到sql语句的哪~

  • 这里爆红是因为我们【还没在xml中实现】/或者【没有正确实现】这个方法(这个提示是MyBatisX这个插件提供的)

1.1.2 xml文件中去实现方法

在这里插入图片描述

  • resultType,顾名思义,也就是返回的类型,设置为UserInfo,其实不加也行,因为可以通过方法的返回值类型来判断,不过一些版本不支持~
  • 这里的返回值UserInfo类型的

返回规则:根据返回的信息,也就是一张结果表,列名对应属性名

  1. 结果的列名有对应的属性,赋值给属性的值
  2. 列有的却没有对应的属性,赋值给了空气
  3. 属性有的却没有对应的列,无能为力,属性只能是默认值
  4. 如果有多个结果对象,则返回的是个集合List

接口内就不报错了:

在这里插入图片描述

在这里插入图片描述

  • 参数的处理可以使用这种方式:${id}这个花括号里的id对应的就是那个参数的注解括号里面的值
    • ${}的方式去写,原理就是简单的字符串拼接,所以如果传递的是字符串的话,还得自己传引号过去,比较麻烦
    • 并且这种写法,MyBatis并不是运行[一整条传参过来的自己拼接的sql字符串]而是提前定好[sql语句的模板]
      • 这里不是java代码,是xml,当然不能用+号拼接
    • 你也发现它不需要引号包裹,因为MyBatis规定这标签之间的值就是要执行的sql代码,不应该将写代码看成写字符串~
  • 包装类对象也会自动转化到sql字符串的,也就是对应的值~

在这里插入图片描述

不加注解,那么它对应的就是参数的名字,但是不是所有的电脑都适合这种写法,而注解则是所有人都适合

在这里插入图片描述

1.1.3 测试

在这里插入图片描述

在这里插入图片描述

  • 如果id为null的话,sql语句就为select * from userinfo where id = null,显然是错误的,那么后端就会传500的响应,代表服务器出现异常,在前端就会被ajax的error属性接受,没被success接受,那么这次请求就相当于失效了

Postman中发送请求:

在这里插入图片描述

前端不传id过去,Integer就为空:

在这里插入图片描述

1.2 传递参数的重点问题:sql注入问题

sql注入是什么?

${} 和 #{} 有什么区别?

这是MyBatis中很常见的面试题!

1.2.1 ${}方式

可见这是一种简单的替换,可以理解为字符串拼接,也就是说,字符串类型的数据我们要手动加引号:

以用户名查找用户为例:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

效果:

在这里插入图片描述

在这里插入图片描述

但是如果不加双引号:

在这里插入图片描述

就会报错,这个是sql语句执行失败的意思~

  • (我们之前的一个配置让sql执行就打印相关日志)~

在这里插入图片描述

并且,字符串拼接的话,就会出现影响原sql语句结构的问题,即sql注入问题:

例如传的字符串是这样的:

在这里插入图片描述

sql语句变为:

在这里插入图片描述

那么,就可能会出现危险的一种情况,就是改变原sql语句的结构,然后多加一条sql语句,对数据库进行攻击!

轻则sql语句因为非法而失效,服务器报500

重则:

  1. 查询你的表的其他信息!
    • 加个or 1 = 1,根据其他条件查询信息,甚至暴露其他库其他表的所有信息…
    • 例如,破解密码:即使输入密码是错的,加上or 1 = 1也能查询得到
      • 或者 1 = ‘1’,sql语法中数字是可以跟字符串进行比较的~
  2. 删除/修改你的数据!
    • 修改用户信息,删库删表…

总之,可以 巧妙地设计 出很多==危险的sql语句==

也就是说,${}是**即使执行的,比较危险!**

例子:

  • 用户登录密码错误仍能登录成功:

在这里插入图片描述

在这里插入图片描述

正常情况下:
在这里插入图片描述

恶意传参:

  • 不需要密码也能登录

在这里插入图片描述

服务器的日志:

在这里插入图片描述

1.2.2 #{}方式

而这个方式对应就不会出现这个问题:

在这里插入图片描述

在这里插入图片描述

查看日志:

在这里插入图片描述

这也就是 之前JDBC的 ? 占位符,然后用参数【value替换】的思想,也就是username的值就是这个String类型的值,id就是这个Integer类型的值

【可以这么理解】:String类型默认加引号,并且字符串内部的每一个字符都是用其unicode码的转义代替,内部在代码看来就是只是存粹的数据,没 有引号的概念,自然不会出现引号将字符串分割而导致的错误

在这里插入图片描述

  • mybatis这一点就省去了原本的繁琐步骤,因为传过来的参数就能决定是setInt还是setString了…

底层帮我们去正确地赋值(避免了手动对字符串类型加引号的过程,也保证了不会出现添加字符串是危险sql语句而导致数据库被恶意影响的情况出生,因为只会被看成一个整体,一个普通的字符串的内容而已)~

  • 所以#{}也可以完成一些奇葩字符串的保存进表里,例如"''"'""',这种字符串如果拼接的话,很有可能会错(因为外部引号包裹的规定)
  • 但是#{}会把这个看成整体,就跟普通字符串除了值不同外没啥区别,就是一坨二进制数据,并不会有所影响

在这里插入图片描述

在这里插入图片描述

  • 被视为了整体字符串~

所以,#{}预执行的,比较安全!

  • 可以防止sql注入!

1.2.3 必须用到${}的情景

那么${} 这么危险,为什么还存在呢?

  • 这是因为一些情况下,是#{} 无法实现的
  • 例如, 传过去的字符串,是sql语句的关键字/本体的一部分!

一个典型的例子就是:

select * from userinfo order by id ${option};

在sql后面如果是desc,就是逆序;如果是asc或者啥也没有,就是顺序~

  • 当然,这个也能用动态sql来解决的,但现在的情景是,传参过来的静态sql

在这里插入图片描述

效果:

  1. desc

在这里插入图片描述

日志:

在这里插入图片描述

  1. asc

在这里插入图片描述

日志:

在这里插入图片描述

空字符串也可以:

在这里插入图片描述

1.2.4 ${}和#{}的区别和注意事项

  1. ${}可以实现的,#{}基本都能实现,所以能用#{}就用#{}
    • 因为${}是及时执行的,而#{}是预执行的,可以防止sql注入的问题
    • sql注入就是通过字符串替换语句中的${}巧妙地构造出危险的sql语句
  2. 但是${}也是有使用场景的,在传参的值是sql语句的本体的一部分/关键字的时候,则必须使用${}
    • 因为#{},被字符串替换,代表的含义一定是“值”而不是关键字,跟不能被认定为sql语句本体的一部分(可以理解为带了引号)
    • ${}是不安全的,所以应该为${option}提供有限个选项(可枚举的),不能有用户自主输入传递的字符串,而是选择,并且这些选项不能让sql语句最终是危险的!
      • 这样,最终的sql语句的执行的各种情况都是意料之中的,是可控的
    • 例如刚才的例子,就只有三个选项
      1. “desc”
      2. “asc”
      3. “”

2. 简单的增删改操作

对于这三个操作,语句的返回值一定是int型的“受影响行数”

我想,你现在有很多想法,试着根据刚才这些规则去实现吧!

2.1 修改操作

在这里插入图片描述

在这里插入图片描述

测试:

在这里插入图片描述

将username为ad的用户的state置为0:

在这里插入图片描述

查看数据库:

在这里插入图片描述

2.2 删除操作

在这里插入图片描述

测试:

在这里插入图片描述

在这里插入图片描述

数据库:

在这里插入图片描述

2.3 增加操作

目前我们的知识只能运行我们固定的去传值:

insert into userinfo (username, password) values('张三', '123456')

我的意思就是,这一段是我们写死了的:

在这里插入图片描述

不能根据实体类值的属性而决定,如属性值为空则添加的时候不设置,不为空则这里就会设置,因为我们现在是sql结构写死了的静态sql,所以无法实现这种情况,等待下一篇文章“动态sql”的学习!

在这里插入图片描述
在这里插入图片描述

测试:
在这里插入图片描述

效果:

在这里插入图片描述

在这里插入图片描述

数据库中:

在这里插入图片描述

补充:

  • 有时候我们增加完成之后,是需要用到自增id的~
  • 因为这个自增id我们不需要自己去设,自然不知道它的值(如果不查表的话)
    • 也就是说我们传递的对象id属性是null值(一般情况下我们传递的是实体类对象,而不是一个个参数,即使如此,也应该有id参数)

例如:提交博客后,跳转到刚才的博客的详情页里;或者注册用户信息后,跳转到主页(省略一次登录)

  • 这些功能就需要这个自增id~

写法:

  1. 设置useGeneratedKeys
    • 意思就是“使用 自主生成的 键值对”,为true,否则框架不会在sql执行后专门返回这个键值对,我们目前知道的自增键值对就是我们的自增主键!
  2. 设置映射关系,keyColumn和keyProperty
    • 也就是让自增主键返回到哪里
    • keyColumn为列名
    • keyProperty为赋值给对象的哪个属性的属性名

在这里插入图片描述

在这里插入图片描述

xml实现的方法的返回值,依旧是影响的行数,而id返回给对象
在这里插入图片描述

测试:

在这里插入图片描述

这个UserInfo对象参数,身兼数职

  1. 信息输入型参数
  2. 输出型参数

3. 模糊匹配like

在这里插入图片描述

根据我们目前的理解,应该写成这样:

在这里插入图片描述

  • 即,找到用户名包含likeString的用户并返回~

在这里插入图片描述

测试:

在这里插入图片描述

命令行报错:

在这里插入图片描述

原因可想而知,就是因为预执行的问题,导致的语法错误

这么说的话那么“拼接sql”,及时执行的${} 可以解决咯?

在这里插入图片描述

  • 确实可以解决
  • 但是会出现sql注入的问题!

我们可以用mysql中的concat(字符串拼接)方法来有效解决这个问题!

  • 可以用#{}了~

在这里插入图片描述

效果:

在这里插入图片描述

查看日志:

在这里插入图片描述

4. 常见疑问

4.1 返回对象的属性名与字段名对应不上

疑问:为什么有时候一些字段是存在值的,但是属性却是null值?

  • 大概率是因为你字段名和返回对象的属性名对应不上~

在这里插入图片描述

在这里插入图片描述

这里提供几个解决方案:

其实这种对应不上的问题,在一开始写代码的时候规定下来就完事了,统一一下命名就行了,也就是写代码的时候规范一点,一般就不会出现

但是,有时候重复利用一段代码作用于另一个是实体类的时候,确实可能会出现这种情况~

  • 当然也有其他的原因~

4.1.1 修改成一致

这是个简单直接的代码,就是改变定义咯, name变为username

如果用了@Data 注解,修改定义就比较简单,改属性名后方法会自动重新定义

  • 但是,比较麻烦的就是,你的代码可能已经用到了Getter和Setter方法,一个个去修改有点麻烦
  • 修改定义不可能修改数据库表定义的表名的!
    • 貌似IDEA有个功能或者插件可以解决,可以去了解一下~

在这里插入图片描述

在这里插入图片描述

4.1.2 重命名列名

这也是比较有效的方法,利用的原理就是:

  • 返回值的赋值的依据,根据的是 最终呈现出来的表
  • 并不是将表转化为一个独立的对象,然后刚好是UserInfo对象,而是 可以赋值就赋值

也就是说,属性名和列名对应的上,也是可能出现属性名没有被赋值的情况的:

在这里插入图片描述

在这里插入图片描述

所以就可以通过重命名的方式来展现:

在这里插入图片描述

在这里插入图片描述

4.1.3 返回字典

通过定义resultMap的,将属性名和字段名进行手动规定的映射

resultMap的定义:

在这里插入图片描述

  • 含义就是,返回UserInfo对象,对这个对象进行手动赋值,或者叫做手动建立映射关系

select标签定义:

在这里插入图片描述

效果:

  • 值得一提的是,这个映射表只是起到一个 “补充” 的作用,其优先级会比**“名字对应得上就赋值,对应不上就不负责”**要高~
  • 也就是说,如果你在映射表中不写其他属性和列的对应关系,也没有关系,会根据属性名和列名的对应关系进行赋值~
    • 当然建议做戏做全套~

在这里插入图片描述

在这里插入图片描述

如果啥也没有,就跟之前的写法一致:

在这里插入图片描述

在这里插入图片描述

4.1.4 注解TableField

不过这个注解来自MyBatisPlus框架的,使用方法如下:

@TableField("username");
private String name;

这样就可以建立对应关系了~

不过MyBatis plus 我暂不讲解,感兴趣的同学可以去了解一下~

  • 传送门:MyBatis-Plus (baomidou.com)

4.2 sql关键字作为属性名

疑问:会不会因为需要反引号去包起来属性名,才能正确的返回值?

如果是在sql语句中写字段名,那么就需要 反引号` 去包起来;

如果是作为返回值赋值给对象的属性的话,因为显示出来的列名本来就没有反引号

  • 所以就不需要担心对应不上的问题~

测试表:

在这里插入图片描述

测试:(代码省略)

在这里插入图片描述

4.3 传入的参数是多个对象

在这里插入图片描述

写代码是根据实际情况的,传入多个自定义对象作为参数很不合理!

  1. 传入多个对象,可以是List对象,后面复杂sql语句可以用到
  2. 传入多个对象,是自定义对象,甚至是多个不一样的自定义对象,是不合理的,即使框架有解决方法,也没啥意义,因为代码不是这么写的,不考虑实际情况的!

不要制造没有意义的冲突!

  • 如果要传递自定义对象,就只能单参传递,不然会导致“not found”!

我们要学的是正常的开发所用到的,而不是去研究一些奇葩的特殊情况的现象是咋样的,咋处理的,这样写会咋样,这样的不常规写法会咋样,研究这些作死一点的写法,返回的结果是咋样,这些都没意义!写正常的代码就行了!


文章到此结束!谢谢观看
可以叫我 小马,我可能写的不好或者有错误,但是一起加油鸭🦆

代码仓库:mybatis_demo · 游离态/马拉圈2023年8月 - 码云 - 开源中国 (gitee.com)


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

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

相关文章

监控Elasticsearch的关键指标

Elasticsearch 的核心职能就是对外提供搜索服务,所以搜索请求的吞吐和延迟是非常关键的,搜索是靠底层的索引实现的,所以索引的性能指标也非常关键,Elasticsearch 由一个或多个节点组成集群,集群自身是否健康也是需要我…

虚拟机的创建与使用

一、虚拟机的下载 链接:百度网盘下载链接 提取码:a9p4 二、新建虚拟机系统 需要有版本序列号 注意: 选择 第一个是纯dos 的窗口指令 桌面没有任何东西 选择第二个就是正常的操作系统.有文件夹 我的电脑之类的 三、从主机中复制文件到虚拟机中需要安装 …

阿里云服务器搭建Magento电子商务网站图文教程

本文阿里云百科分享使用阿里云服务器手动搭建Magento电子商务网站全流程,Magento是一款开源电商网站框架,其丰富的模块化架构体系及拓展功能可为大中型站点提供解决方案。Magento使用PHP开发,支持版本范围从PHP 5.6到PHP 7.1,并使…

如何通过CSS选择器选择一个元素的子元素?如何选择第一个子元素和最后一个子元素?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 选择一个元素的子元素⭐ 选择第一个子元素和最后一个子元素⭐ 注意事项⭐ 写在最后 ⭐ 专栏简介 前端入门之旅:探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航前端之旅 欢迎来到前端入门之旅&…

spark 图计算 助力解决 dataframe中的链式依赖

链式依赖说明 name newName a b c d b c 我们需要的结果 即我们可以支持获取到链式转换的 起点 重点 以及链式的中间转换过程顺序数组. 特别说明: 出版只支持 单向 无分叉的图,其他复杂场景暂时未测试. 场景举例: 比如某件商品价格变化,我们需要知…

gitee(码云)如何生成并添加公钥配置用户信息

一,简介 在使用Gitee的时候,公钥是必须的,无论是克隆还是上传。本文主要介绍如何本地生成和添加公钥到服务器,然后配置自己的用户信息,方便日后拉取与上传代码。 二,步骤介绍 2.1 本地生成公钥 打开git ba…

接口测试之Jmeter+Ant+Jenkins接口自动化测试平台

平台简介 一个完整的接口自动化测试平台需要支持接口的自动执行,自动生成测试报告,以及持续集成。Jmeter支持接口的测试,Ant支持自动构建,而Jenkins支持持续集成,所以三者组合在一起可以构成一个功能完善的接口自动化…

CDN(Content Delivery Network)内容分发网络

从DNS域名系统到CDN内容分发网络 DNS什么是DNS直接使用DNS的缺点 CDNCDN加速过程使用CDN的优势 DNS 什么是DNS 输入域名www.baidu.com后,浏览器先检查缓存和本地Host文件,看有没有对应的ip地址,有则直接使用,没有就会向本地DNS服…

Shader 编程:三角形、矩形等多边形绘制

该原创文章首发于微信公众号:字节流动 未经作者(微信ID:Byte-Flow)允许,禁止转载 SDF 有向距离场 上节其实牵扯到 SDF 算法,因为后面涉及高级特效的时候会经常用到,这里先提前对它做个简单的介…

Git 代码分支规范

目的 俗话说:没有规矩,不成方圆。遵循一个好的规章制度能让你的工作事半功倍。同时也可以展现出你做事的认真的态度以及你的专业性,不会显得杂乱无章,管理困难。Git分支规范也是一样。当遵循了某种约定的Git分支,在代…

《合成孔径雷达成像算法与实现》Figure3.8

与图3.7的代码区别只在于原始信号的表达式对了一个时间偏移 代码复现如下: clc clear all close all%参数设置 TBP 100; %时间带宽积 T 10e-6; %脉冲持续时间 tc …

Apollo Planning2.0决策规划算法代码详细解析 (1):环境搭建

背景: apollo开源团队近期更新了planning版本,对代码进行了一定程度上的重构。 重构后代码结构更加清晰,对扩展更为友好;此外,也更新了dreamview对pnc的支持,使得调试更加方便。 本教程将继续更新对于Apollo Planning2.0决策规划算法代码的详细解析,便于大家更好理解…

在x86下运行的Ubuntu系统上部署QEMU用于模拟RISC-V硬件环境

1.配置工作环境 sudo apt install gcc bison flex libncurses-dev ninja-build \pkg-config build-essential zlib1g-dev pkg-config libglib2.0-dev \binutils-dev libboost-all-dev autoconf libtool libssl-dev \libpixman-1-dev python-capstone virtualenv software-prop…

数据结构入门:栈

目录 前言 1. 栈 1.1栈的概念及结构 1.2 栈的实现 1.2.1 栈的定义 1.2.2 栈的初始化 1.2.3 入栈 1.2.4 出栈 1.2.5 栈的元素个数 1.2.6 栈顶数据 1.2.7 栈的判空 2.栈的应用 2.1 题目一:括号匹配 2.1.1 思路 2.1.2 分析 2.1.3 题解 总结 前言 无论你是计算机科学专…

从源码Debug深入spring事件机制,基于观察者模式仿写spring事件监听骨架

文章目录 1.测试案例2.DEBUG源码分析3. 异步监听4.ApplicationListener子接口5. 注解支持6. 基于观察者模式高仿spring事件监听6.1 先定义自定义一个事件6.2 定义两个监听器6.3 定义一个持有所有监听器的对象,类似spring的SimpleApplicationEventMulticaster6.4 事件…

【C++起飞之路】初级—— auto、范围for循环、宏函数和内联函数

auto、范围for、内联函数、宏函数和nullptr 一、auto — 类型推导的魔法(C 11)1、auto 是什么?2、工作原理3、优势4、限制和注意事项 二、范围for (C11)1、基本语法2、优势3、工作原理4、注意事项5、C11: 范围 for 循环的扩展: 三…

数据结构:力扣OJ题

目录 ​编辑题一:链表分割 思路一: 题二:相交链表 思路一: 题三:环形链表 思路一: 题四:链表的回文结构 思路一: 链表反转: 查找中间节点: 本人实力…

找不到资产文件project.assets.json

NuGet 在“obj”文件夹中写入名为 project.assets.json 的文件,.NET SDK 使用该文件来获取有关要传递到编译器的包的信息 。 如果在生成过程中找不到资产文件 project.assets.json,则会发生此错误。 1.执行命令的方式解决 点击工具,分别展开命…

【简单认识zookeeper+kafka分布式消息队列集群的部署】

文章目录 一、zookeeper1、定义2、工作机制3、Zookeeper 特点4、Zookeeper 数据结构5、Zookeeper 应用场景6、Zookeeper 选举机制(1)第一次启动选举机制(2)非第一次启动选举机制 7、部署zookeeper群集 二、消息队列概述1、为什么需…

释放AI创作潜能:从大模型训练到高产力应用

文章目录 每日一句正能量前言什么是人工智能生成内容(AIGC)人工智能生成内容(AIGC)能做什么为什么要用人工智能生成内容(AIGC)创作成果用Java实现冒泡排序算法学生信息收集系统学生请假管理系统需求分析教务…