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

news2024/11/26 20:01:01

【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)


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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【LeetCode周赛】LeetCode第358场周赛

LeetCode第358场周赛 数组中的最大数对和翻倍以链表形式表示的数字限制条件下元素之间的最小绝对差 数组中的最大数对和 给你一个下标从0开始的整数数组nums。请你从nums中找出和最大的一对数,且这两个数数位上最大的数字相等。 返回最大和,如果不存在满…

手机商城网站的分析与设计(论文+源码)_kaic

目录 摘 要 1 1 绪论 2 1.1选题背景意义 2 1.2国内外研究现状 2 1.2.1国内研究现状 2 1.2.2国外研究现状 3 1.3研究内容 3 2 网上手机商城网站相关技术 4 2.1.NET框架 4 2.2Access数据库 4 2.3 JavaScript技术 4 3网上手机商城网站分析与设…

基于grpc从零开始搭建一个准生产分布式应用(3) - GRPC实现

本章开始会进入GRPC子专题,先实现前面章节中提到的例子。然后就使用的知识点展开全面的描述。本章代码任务:1、实现一个简单的GRPC服务;2、实现GRPC拦截器。 本章的代码承接上一章的代码进行迭代。因模块间存在相互依赖关系,读者一…

SpringBoot复习:(42)WebServerCustomizer的customize方法是在哪里被调用的?

ServletWebServletAutoConfiguration类定义如下: 可以看到其中通过Import注解导入了其内部类BeanPostProcessorRegister。 BeanPostProcessor中定义的registerBeanDefinition方法会被Spring容器调用。 registerBeanDefinitions方法调用了RegistrySyntheticBeanIf…

【MongoDB】一文带你快速掌握MongoDB数据库和集合基础操作

文章目录 前言一、案例需求二、数据库操作1. 选择和创建数据库2. 数据库的删除 三、集合操作1. 集合的显式创建(了解)2. 集合的隐式创建3. 集合的删除 总结 前言 为了巩固所学的知识,作者尝试着开始发布一些学习笔记类的博客,方便…

pycorrector一键式文本纠错工具,整合了BERT、MacBERT、ELECTRA、ERNIE等多种模型,让您立即享受纠错的便利和效果

pycorrector:一键式文本纠错工具,整合了Kenlm、ConvSeq2Seq、BERT、MacBERT、ELECTRA、ERNIE、Transformer、T5等多种模型,让您立即享受纠错的便利和效果 pycorrector: 中文文本纠错工具。支持中文音似、形似、语法错误纠正,pytho…

激活函数总结(七):激活函数补充(Softsign、Threshold、Sinc)

激活函数总结(七):激活函数补充 1 引言2 激活函数2.1 Softsign激活函数2.2 Threshold (Unit step activation function) 激活函数2.3 Sinc激活函数 3. 总结 1 引言 在前面的文章中已经介绍了介绍了一系列激活函数 (Sigmoid、Tanh、ReLU、Lea…

Java-运算符和控制语句(下)(基于c语言的补充)

输出到控制台 System.out.println(msg); // 输出一个字符串, 带换行 System.out.print(msg); // 输出一个字符串, 不带换行 System.out.printf(format, msg); // 格式化输出 从键盘输入 使用 Scanner 读取字符串/整数/浮点数 首先需要导入util包 自动导入util包 这里把回车看…

21-因子个数

题目 一个正整数可以分解成一个或多个数组的积。例如362*2*3*3,即包含2和3两个因子。NowCoder最近在研究因子个数的分布规律,现在给出一系列正整数,他希望你开发一个程序输出每个正整数的因子个数。 输入描述: 输入包括多组数据。 每组数…

Ubuntu22开机后正上方弹出“Printer addded(已添加打印)”等提示框

一、问题描述 Ubuntu22开机后正上方弹出“Printer addded(已添加打印)”等提示框。如下 二、问题分析 1、列出当前所有开机启动服务 service --status-all msmoshui:~$ service --status-all[ - ] alsa-utils[ - ] anacron[ ] apparmor[ ] app…

预测算法|改进粒子群算法优化极限学习机IDM-PSO-ELM

回归拟合: 分类 本文是作者的预测算法系列的第四篇,前面的文章中介绍了BP、SVM、RF及其优化,感兴趣的读者可以在作者往期文章中了解,这一篇将介绍——极限学习机 过去的几十年里基于梯度的学习方法被广泛用于训练神经网络&am…

全网最详细,Pytest自动化测试框架-Fixture固件实战,你要的都有...

目录:导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结(尾部小惊喜) 前言 什么是固件 Fixt…

SpringBoot整合Redis完整篇

SpringBoot整合Redis完整篇 1、在springboot项目的pom.xml <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schem…

用HARU-Net增强核分割:一种基于混合注意的残差u块网络

文章目录 Enhancing Nucleus Segmentation with HARU-Net: A Hybrid Attention Based Residual U-Blocks Network摘要本文方法损失函数后处理消融实验 Enhancing Nucleus Segmentation with HARU-Net: A Hybrid Attention Based Residual U-Blocks Network 摘要 核图像分割是…

B3716 分解质因子 3

#include <bitset> #include <vector> #include <iostream> #include <algorithm>const int maxn 100000008;std::vector<int> prm, pre; // pre is the min-factor array. bool np[maxn];void getPrime(const int N 100000000) {//线性筛&am…

Fast SAM与YOLOV8检测模型一起使用实现实例分割以及指定物体分割(有代码)

Fast SAM与YOLOV8检测模型一起使用 VX 搜索”晓理紫“ 关注并回复yolov8fastsam获取核心代码 晓理紫 1 使用场景 实例分割数据集的获取要比检测数据的获取更加困难&#xff0c;在已有检测模型不想从新标注分割数据进行训练但是又想获取相关物体的mask信息以便从像素级别对物体进…

Redis原理简述

Redis原理简述 Redis 有哪些特性 1. 特性 key-value 型内存数据库单线程——原子化操作支持lua脚本发布与订阅可持久化逐出与过期……2. 持久化 RDB:经过压缩的二进制文件;fork子进程进行操作AOF:保存所有写命令;先写缓存再同步至AOF文件;文件过大时会触发AOF重写3. 过期…

4. 发布确认

4.1. 发布确认原理 生产者将信道设置成 confirm 模式&#xff0c;一旦信道进入 confirm 模式&#xff0c;所有在该信道上面发布的 消息都将会被指派一个唯一的 ID(从 1 开始)&#xff0c;一旦消息被投递到所有匹配的队列之后&#xff0c;broker 就会发送一个确认给生产者(包含消…

[python]RuntimeError: Can‘t decrement id ref count (unable to close file...

使用spectralspatial模型进行EEG分类时&#xff0c;出现以下错误 RuntimeError: Cant decrement id ref count (unable to close file, errno 5, error message Input/output error) Segmentation fault (core dumped) 猜测是因为存储的model太大了导致的&#xff0c;找到了…

QGIS3.28的二次开发八:显示shp的属性表

这里实现两个基本的 GIS 软件需求&#xff1a;矢量图层的属性表显示&#xff0c;以及根据属性筛选要素。 具体需求如下&#xff1a; 加载一个矢量图层并打开其属性表&#xff1b;输入筛选条件确认无误后&#xff0c;画布上和属性表中均只显示筛选后的要素。 QGIS 提供了若干…