PreparedStatement接口与调用存储过程

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介:

PreparedStatement相对于Statement最重要的一个优点就是可以进行SQL预处理,以此防止SQL语句的注入问题。

所谓SQL注入,就是通过把SQL命令插入到用户输入的文本中,最终达到欺骗数据库服务器执行恶意的SQL命令。具体来说,它是利用现有应用程序,将(恶意的)SQL命令注入到后台数据库引擎执行的能力,它可以通过在Web表单中输入(恶意)SQL语句得到一个存在安全漏洞的网站上的数据库,而不是按照设计者意图去执行SQL语句。

使用PreparedStatement就可以防止一些SQL注入的问题,保证了一定的安全性,而且PreparedStatement能够使用提供参数的方式来避免拼错SQL语句,在调用PreparedStatement里的setStringsetInt等方法的时候,会自动把你提供的参数转换成数据库里的数据类型。

就算没有被恶意的被SQL注入攻击,也可能会出现用户输入的内容碰巧转换成了SQL语句,或者在程序运行过程中出现符号转换的问题,这些都会导致数据库误以为是SQL命令而去执行。

下面我们使用Statement写几句简单的代码模拟一下用户的登录操作:

1a42cd7b63be44b794bbcde6287f50fb.png


运行结果:

582cf6079d4c254b7e3862d654b0d5a0.png


接着做个简单的小实验,模拟利用简单的SQL注入原理来达到不输入用户和密码也能登录的情况:

  代码示例:

2d8c43432a4477fc7764bb0b6057fc10.png


运行结果:

db9cf3898ed621a57b1a99d369989d96.png

从结果可以看到没有输入用户和密码也登录成功了,如果这种漏洞问题出现真正的程序,想想也知道会有多严重。而且这仅仅是一个很简单的例子,借助SQL注入能做到的事情可不止这一点。

 


现在换成PreparedStatement来进行同样的试验:

代码示例:

1e032888be39ca369cba53f6b96a55d5.png


运行结果:

5e954a6f3efa2baba2e9f217fa0ee651.png

从结果可以看到不会因为用户输入的内容是SQL命令或符号,而出现SQL注入的问题了。


 

Statement一样PreparedStatement也能够执行数据库的两大类语句,更新语句(DML)和查询语句(DQL),并且也支持批量SQL语句执行。

  insert语句代码示例:

51bde168e10d4abcbb086a1fecb06023.png


运行结果:

a4ee0b6aeb65e3a984e1116e323161c8.png


数据库:

af87f1215d64fdd7b030ced9a3151431.png


update语句代码示例:

b84c9e81120f144cf04fa35372e79af8.png


运行结果:

854ce930000e8080775c603d2bc55b51.png


数据库:

918b19992b6537af67fe036b0e455e39.png


delete语句代码示例:

85e10cd6afcc1e9cedcc6d9a39dd064e.png


运行结果:

b41e52dc270cc170766d482d903c8103.png


数据库:

a0224f8764dd723272685dbd97b0ca61.png


批量SQL语句执行代码示例:

daf92c6da6efe32568f9a7504c10f480.png


运行结果:

f7857a3a5985e6c138307c6e12b10748.png


数据库:

021830f8507d8bc09c4b6dc406cc5a3f.png



PreparedStatement里设置值的时候可以调用setObject方法,此方法能够自动将你提供的参数转换成相对应的数据库数据类型,也就是说即便你懒得写具体的类型或者不知道提供的值是什么类型的话均可使用这个方法。

  代码示例:

87f326f5dbba7a0d332e89610fef50bf.png


运行结果:

737883c00536a99a5c424e89ef6cdf33.png



我们看一下这个方法的实现代码,就知道此方法是如何实现的和支持哪些类型了:

6f81687c177064d3379aa21a804cf375.png

2fd7826cf18fd9a2c7101f8bf17f05e4.png







从数据库中进行文件上传/下载:

我们可以上传文件到数据库中,相对也能从数据库中下载文件,不过很少人会这么做,这种骚操作了解一下记得有这个操作就可以了,一般情况下用不上。

因为把文件存放在数据库要面临以下几个问题:

· 1.对数据库的读/写的速度永远都赶不上文件系统处理的速度

· 2.数据库备份变的巨大,越来越耗时间

· 3.对文件的访问需要穿越你的应用层和数据库层

这后两个是真正的杀手。把图片缩略图存到数据库里?很好,那你就不能使用nginx或其它类型的轻量级服务器来处理它们了。

So给自己行个方便吧,在数据库里只简单的存放一个磁盘上你的文件的相对路径,或者使用S3或CDN之类的服务。

虽然把文件存到数据库中不是什么好的操作,但是为了预防万一或应急情况还是需要了解一下这个操作的:

  1.首先创建一张表格使用blob作为文件的数据类型,当然也可以使用其他可以存储文件的类型:

465d6db885d35515f8c6eb27784c5925.png



3.查看一下数据库能接收多大的数据,如果要存放的文件大小大于数据库能接收的大小就会报错,使用以下SQL命令查看,单位是字节:

  SHOW VARIABLES LIKE '%max_allowed_packet%';

86c6b04d50676d00d9c1f873163b5387.png


如果要改变mysql数据库的数据接收大小,需要去配置my.ini文件,写上这句代码:

max_allowed_packet = 20M

53a06739ba844607d5380fc9220721fa.png




修改方法

1) 方法1

可以编辑my.ini来修改(Linuxmy.cnf,在[mysqld]段或者mysql的server配置段进行修改。

max_allowed_packet = 20M

Linux系统中如果找不到my.ini可以通过

mysql --help | grep my.ini

命令去寻找my.ini文件。

 

2) 方法2

(很妥协,很纠结的办法)

进入mysql server

mysql 命令行中运行

set global max_allowed_packet = 2*1024*1024*10

然后关闭掉这此mysql server链接,再进入。

show VARIABLES like '%max_allowed_packet%';

查看下max_allowed_packet是否编辑成功

编写Java代码通过JDBC将文件上传到数据库中:

f2ef63031596643a1febf0bce92ac9a9.png


运行结果:

aa8c1981b8153da2e015a6b17ed4877d.png


数据库:

8dbdba5c13a25f0c2fb25875d07f398e.png



接下来我们从数据库中把这个文件下载下来,先使用查询语句先把文件查找出来,然后调用getBinaryStream方法得到一个InputStream 对象,这个方法需要传递一个列的序号,接着使用FileOutputStream把文件写入到磁盘里。

  代码示例:

5644c7e2a3020618e5b0a31aadae7d9b.png


运行结果:

97ec95eb7717ac8bfe04c453aa335a0e.png


文件:

9cb84daf5222f5e043052bc00b27f8e3.png


27ceb25bf5b803b10dfce88d9d36605b.png








调用存储过程:

使用CallableStatement 接口可以调用数据库中的存储过程,需要先使用Connection 对象调用prepareCall方法并提供调用存储过程的SQL语句来获得CallableStatement 对象,不过语法和数据库中的调用存储过程的SQL语句有点不一样,需要加上大括号括起来。使用CallableStatement 对象调用registerOutParameter方法并且提供存储过程带出值的类型,就可以获得存储过程的带出值。

代码示例:

7ddececa36a0837de9a6e32d41268027.png



运行结果:

323efe7d8faee968d828a1eb8e847d56.png




本文转自 ZeroOne01 51CTO博客,原文链接:http://blog.51cto.com/zero01/1977008,如需转载请自行联系原作者

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
19天前
|
存储 SQL NoSQL
|
1月前
|
存储 SQL 关系型数据库
MySql数据库---存储过程
MySql数据库---存储过程
35 5
|
1月前
|
存储 关系型数据库 MySQL
MySQL 存储过程返回更新前记录
MySQL 存储过程返回更新前记录
48 3
|
1月前
|
存储 SQL 关系型数据库
MySQL 存储过程错误信息不打印在控制台
MySQL 存储过程错误信息不打印在控制台
61 1
|
3月前
|
存储 关系型数据库 MySQL
Mysql表结构同步存储过程(适用于模版表)
Mysql表结构同步存储过程(适用于模版表)
48 0
|
3月前
|
存储 SQL 关系型数据库
MySQL 创建存储过程注意项
MySQL 创建存储过程注意项
42 0
|
4月前
|
存储 SQL 关系型数据库
(十四)全解MySQL之各方位事无巨细的剖析存储过程与触发器!
前面的MySQL系列章节中,一直在反复讲述MySQL一些偏理论、底层的知识,很少有涉及到实用技巧的分享,而在本章中则会阐述MySQL一个特别实用的功能,即MySQL的存储过程和触发器。
|
4月前
|
存储 SQL 数据库
MySQL设计规约问题之为什么要避免使用存储过程、触发器和函数
MySQL设计规约问题之为什么要避免使用存储过程、触发器和函数
|
5月前
|
存储 SQL 关系型数据库
MySQL数据库进阶第四篇(视图/存储过程/触发器)
MySQL数据库进阶第四篇(视图/存储过程/触发器)
|
5月前
|
存储 SQL 关系型数据库
MySQL存储过程和存储函数的使用
MySQL的存储过程和存储函数在功能和用法上有明显的区别。存储过程是一组为了完成特定功能的SQL语句集,经编译后存储在数据库中,通过指定名称和参数(如果有)来调用执行,可以返回多个值或结果集,但不直接返回值。而存储函数则是一个有返回值的特殊存储过程,它返回一个值或表对象,可以直接嵌入SQL语句中使用,如SELECT语句中。两者都是为了提高SQL代码的重用性和性能,但使用场景和方式有所不同。
4293 4