「MyBatis」数据库相关操作2

🎇个人主页

🎇所属专栏:Spring

🎇欢迎点赞收藏加关注哦!


#{} 和 ${}

我们前面都是采用 #{} 对参数进行赋值,实际上也可以用 ${}

客户端发送⼀条 SQL 给服务器后,大致流程如下:
1. 解析语法和语义, 校验SQL语句是否正确
2. 优化SQL语句, 制定执⾏计划
3. 执行并返回结果
一条 SQL如果走上述流程处理, 我们称为即时 SQL
#{} 用的是预编译SQL,通过 ? 占位的方式提前编译 SQL(类似 C 语言的 printf 的占位符),然后把参数填充到 SQL 语句中,它还 会根据参数类型自动拼接引号
${} 则是即时 SQL,它直接替换字符,⼀起编译 SQL。如果参数为字符串,需要加上引号
@Mapper
public interface UserInfoMapper {@Select("select password from userinfo where username = #{name}")UserInfo queryByName1(String name);@Select("select password from userinfo where username = '${name}'")UserInfo queryByName2(String name);
}
@SpringBootTest
class UserInfoMapperTest {@Autowiredprivate UserInfoMapper userInfoMapper;@Testvoid queryByName1() {userInfoMapper.queryByName1("lisi");}@Testvoid queryByName2() {userInfoMapper.queryByName2("wangwu");}
}

运行结果:

探讨二者的区别其实就是在讨论预编译 SQL 和即时 SQL 的区别

1. 预编译 SQL 性能更高

大多数情况下某条 SQL 语句可能会被反复调用执行,或者每次执行时只有个别值不同(比如 select 的 where 子句值不同、update 的 set 子句值不同、insert 的 values 值不同)。如果每次都需要经过上面的语法解析、SQL 优化、SQL 编译这些步骤,也就是即时 SQL,则效率显然不行
而预编译 SQL 编译一次之后就会将编译后的 SQL 语句 缓存起来 。后面再次执行这条语句时,不会再次编译(只是输入的参数不同),这样就省去解析优化等过程,提高了效率这个原理和常量池类似

2. 预编译 SQL 可以防止 SQL 注入,更安全

SQL 注入是一种通过操作输入的数据来修改事先定义好的 SQL 语句,执行代码后对服务器进行攻击的技术

${} 会有 SQL 注入的风险,所以尽量使用 #{} 完成查询

下面演示一下 SQL 注入

@Mapper
public interface UserInfoMapper {@Select("select password from userinfo where username = '${name}'")List<UserInfo> queryByName2(String name);
}
@SpringBootTest
class UserInfoMapperTest {@Autowiredprivate UserInfoMapper userInfoMapper;@Testvoid queryByName2() {List<UserInfo> userInfoList = userInfoMapper.queryByName2("' or 1='1");System.out.println(userInfoList);}
}

可以看到把所有的 password 都查询出来了,这显然是不合理的


3. 有一些场景 #{} 实现不了,需要用 ${},比如排序

@Mapper
public interface UserInfoMapper {@Select("select id,username,age,gender,phone,delete_flag,create_time,update_time " +"from userinfo order by id #{sort}")List<UserInfo> queryAllUserBySort1(String sort); //传入排序方式:排升序 or 降序@Select("select id,username,age,gender,phone,delete_flag,create_time,update_time " +"from userinfo order by id ${sort}")List<UserInfo> queryAllUserBySort2(String sort);
}
@SpringBootTest
class UserInfoMapperTest {@Autowiredprivate UserInfoMapper userInfoMapper;@Testvoid queryAllUserBySort1() {List<UserInfo> list = userInfoMapper.queryAllUserBySort1("asc");System.out.println(list);}@Testvoid queryAllUserBySort2() {List<UserInfo> list = userInfoMapper.queryAllUserBySort2("desc");System.out.println(list);}
}

#{sort} 查询结果如下:

使用  #{sort} 查询时, asc 前后会自动加上引号,导致 sql 错误;而我们不想它加引号,所以只能用 ${sort},因为这个的引号一定要我们自己手动加上去

按照 id 排降序:


模糊匹配(like 查询)

@Select("select id, username, age, gender, phone, delete_flag, create_time, 
update_time " +"from userinfo where username like '%#{key}%' ")
List<UserInfo> queryAllUserByLike(String key);

like 查询使用 #{} 会报错,需要用 ${},但它存在 SQL 注入的问题,所以不能直接使用

解决办法就是使用 mysql 内置函数 concat() 来实现字符串拼接

    @Select("select id,username,age,gender,phone,delete_flag,create_time,update_time " +"from userinfo where username like concat('%',#{key},'%')")List<UserInfo> queryAllUserByLike(String key);
    @Testvoid queryAllUserByLike() {List<UserInfo> list = userInfoMapper.queryAllUserByLike("S");System.out.println(list);}


数据库连接池

数据库连接池顾名思义,就是存放数据库连接的池子,它负责分配、管理和释放数据库连接,允许应用程序重复使用一个现有的数据库连接, 而不是再重新建立一个连接

没有使用数据库连接池的时候,每次执行 SQL 语句都要先创建一个新的连接对象, 然后执行 SQL 语句,执行完再关闭连接对象释放资源。这种重复创建连接、销毁连接的行为比较消耗资源

而如果使用数据库连接池,那么在程序启动时,会在数据库连接池中创建⼀定数量的 Connection 对象, 当客户端需要访问数据库时,会从数据库连接池中获取 Connection 对象, 然后执行 SQL, 执行完再把 Connection 放回连接池

优点:

1. 减少了网络开销
2. 资源重用
3. 提升系统的性能

常见的数据库连接池有:Hikari、Druid、C3P0、DBCP。其中 SpringBoot 默认使用的数据库连接池是 Hikari

我们也可以把默认的数据库连接池切换为 Druid,只需引入下述的依赖:

<dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>1.1.17</version>
</dependency>


总结

1. 命名规则:表名和字段名使用 小写字母或数字 ,单词之间以下划线分割,尽量避免出现数字开头、两个下划线、中间只出现数字这些情况

2. 表中一定有这三个字段:id、create_time、update_time。其中 id 必为主键,它的类型为 bigint unsigned,单表时自增;create_time 和 update_time 的类型均为 datetime

3. 在表查询中, 应避免使用 * 查询

4. #{} 和 ${} 区别

1. #{}:预编译处理, ${}:字符直接替换
2. #{} 可以防止 SQL 注入,${} 存在SQL注入的风险。查询语句中推荐使用 #{}
3. 但是⼀些场景 #{} 没法完成要求,比如排序功能,表名, 字段名作为参数时,需要使用 ${}
4. 模糊查询虽然 ${} 可以完成,但由于存在 SQL 注入的问题,所以通常使用 mysql 内置函数concat 来完成

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

51单片机之动态数码管显示

一、硬件介绍 LED数码管是一种由多个发光二极管&#xff08;LED&#xff09;封装在一起&#xff0c;形成“8”字型的显示器件。它广泛用于仪表、时钟、车站、家电等场合&#xff0c;用于显示数字、字母或符号。 通过控制点亮a b c d e f g dp来显示数字&#xff0c;本实验开发板…

前端八股文笔记【三】

JavaScript 基础题型 1.JS的基本数据类型有哪些 基本数据类型&#xff1a;String&#xff0c;Number&#xff0c;Boolean&#xff0c;Nndefined&#xff0c;NULL&#xff0c;Symbol&#xff0c;Bigint 引用数据类型&#xff1a;object NaN是一个数值类型&#xff0c;但不是…

十三、代理模式

文章目录 1 基本介绍2 案例2.1 Sortable 接口2.2 BubbleSort 类2.3 SortTimer 类2.4 Client 类2.5 Client 类的运行结果2.6 总结 3 各角色之间的关系3.1 角色3.1.1 Subject ( 主体 )3.1.2 RealObject ( 目标对象 )3.1.3 Proxy ( 代理 )3.1.4 Client ( 客户端 ) 3.2 类图 4 动态…

Java网络编程、TCP、UDP、Socket通信---初识版

标题 InetAddress----IP地址端口号协议&#xff08;UDP/TCP&#xff09;JAVA操作-UDP一发一收模式多发多收 JAVA操作-TCP一发一收多发多收 实现群聊功能BS架构线程池优化 InetAddress----IP地址 端口号 协议&#xff08;UDP/TCP&#xff09; JAVA操作-UDP 一发一收模式 多发多收…

React 性能优化

使用 useMemo 缓存数据 &#xff08;类似 vue 的 computed&#xff09;使用 useCallback 缓存函数异步组件 ( lazy )路由懒加载( lazy )服务器渲染 SSR用 CSS 模拟 v-show 循环渲染添加 key使用 Fragment &#xff08;空标签&#xff09;减少层级 不在JSX 中定义函数&#xff0…

一篇教会搭建ELK日志分析平台

日志分析的概述 日志分析是运维工程师解决系统故障&#xff0c;发现问题的主要手段日志主要包括系统日志、应用程序日志和安全日志系统运维和开发人员可以通过日志了解服务器软硬件信息、检查配置过程中的错误及错误发生的原因经常分析日志可以了解服务器的负荷&#xff0c;性…

使用本地大模型从论文PDF中提取结构化信息

1 安装ollama 点击前往网站 https://ollama.com/ &#xff0c;下载ollama软件&#xff0c;支持win、Mac、linux 2 下载LLM ollama软件目前支持多种大模型&#xff0c; 如阿里的&#xff08;qwen、qwen2&#xff09;、meta的(llama3、llama3.1)&#xff0c; 读者根据自己电脑…

C语言:求最大数不用数组

&#xff08;1&#xff09;题目&#xff1a; 输入一批正数用空格隔开&#xff0c;个数不限&#xff0c;输入0时结束循环&#xff0c;并且输出这批整数的最大值。 &#xff08;2&#xff09;代码&#xff1a; #include "stdio.h" int main() {int max 0; // 假设输入…

Qt——多线程

一、QThread类 如果要设计多线程程序&#xff0c;一般是从QThread继承定义一个线程类&#xff0c;并重新定义QThread的虚函数 run() &#xff0c;在函数 run() 里处理线程的事件循环。 应用程序的线程称为主线程&#xff0c;创建的其他线程称为工作线程。主线程的 start() 函数…

计算机网络408考研 2014

1 计算机网络408考研2014年真题解析_哔哩哔哩_bilibili 1 111 1 11 1

MyBatis:Maven,Git,TortoiseGit,Gradle

1&#xff0c;Maven Maven是一个非常优秀的项目管理工具&#xff0c;采用一种“约定优于配置&#xff08;CoC&#xff09;”的策略来管理项目。使用Maven不仅可以把源代码构建成可发布的项目&#xff08;包括编译、打包、测试和分发&#xff09;&#xff0c;还可以生成报告、生…

短视频SDK,支持Flutter跨平台框架,加速产品上线进程

在数字内容爆炸式增长的今天&#xff0c;短视频已成为连接用户、传递情感、展现创意的重要桥梁。为助力开发者快速融入这股潮流&#xff0c;美摄科技匠心打造了一款专为Flutter框架优化的短视频SDK解决方案&#xff0c;旨在降低技术门槛&#xff0c;加速产品迭代&#xff0c;让…

主题与分区

主题和分区是Kafka的两个核心概念&#xff0c;分区的划分不仅为Kafka提供了可伸缩性、水平扩展的功能&#xff0c;还通过多副本机制来为Kafka提供数据冗余以提高数据可靠性。 主题创建 主题和分区都是提供给上层用户的抽象&#xff0c;而在副本层面或更加准确地说是Log层面&a…

Unity效果优化之抗锯齿

Unityde 基于HDRP渲染管线的抗锯齿处理的设置参考图&#xff1a; 前提&#xff1a;需要导入HDRP的插件包才行&#xff0c; 该参数设置能保证在PC版上抗锯齿效果非常好&#xff0c; 英文版&#xff1a;

AWS Lambda 十年回顾:功能总览、更新记录与入门指南

这次&#xff0c;我为2014年11月发布的AWS Lambda创建了一个历史时间表。AWS Lambda 是一项无服务器、全托管的代码执行服务&#xff0c;今年2024年11月将迎来其宣布发布的十周年纪念。虽然提前了一些&#xff0c;但为了提前庆祝这一重要时刻&#xff0c;我写了这篇文章。 文章…

论文解读 | ACL 2024:自我蒸馏在语言模型微调中架起分布差异的桥梁

点击蓝字 关注我们 AI TIME欢迎每一位AI爱好者的加入&#xff01; 杨兆瑞 浙江大学CAD&CG全国重点实验室博士生 导师为陈为教授 概述 大型语言模型&#xff08;LLMs&#xff09;的兴起彻底改变了自然语言处理领域&#xff0c;但对它们进行特定任务的微调常常面临在平衡性能…

C++ | (一)C++入门基础

从本篇文章开始&#xff0c;我们正式进行C的系统学习。C是在C语言的基础上添加了面向对象编程的特性&#xff0c;是C语言的延伸&#xff0c;并遵循C语言的绝大多数语法。如果想学习C&#xff0c;必须要有一定的C语言基础&#xff0c;这样学起来才不会太过痛苦。 本文章即假设读…

【实战】Spring Security Oauth2自定义授权模式接入手机验证

文章目录 前言技术积累Oauth2简介Oauth2的四种模式授权码模式简化模式密码模式客户端模式自定义模式 实战演示1、mavan依赖引入2、自定义手机用户3、自定义手机用户信息获取服务4、自定义认证令牌5、自定义授权模式6、自定义实际认证提供者7、认证服务配置8、Oauth2配置9、资源…

【数据结构】—— 队列

1、队列的概念2、队列的结构如何选择合适的数据结构实现队列&#xff08;数组or链表&#xff09; 3、队列的链式存储3.1 队列的链式存储结构3.2 队列的常见接口3.3 队列的接口实现初始化判空入队列出队列获取队头元素获取队尾元素获取节点个数销毁 3.4 源代码 4、队列的顺序存储…

k8s持久化存储PV和PVC

一、PV和PVC 1.PersistentVolume (PV) PersistentVolume (PV) 是外部存储系统中的⼀块存储空间&#xff0c;由管理员创建和维护。与 Volume⼀样&#xff0c; PV 具有持久性&#xff0c;⽣命周期独⽴于 Pod&#xff1b; 2.PersistentVolumeClaim (PVC) PersistentVolumeClaim…