前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >PreparedStatement接口与调用存储过程

PreparedStatement接口与调用存储过程

作者头像
端碗吹水
发布2020-09-23 10:41:34
1.5K0
发布2020-09-23 10:41:34
举报
文章被收录于专栏:程序猿的大杂烩

PreparedStatement接口:

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

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

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

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

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

1a42cd7b63be44b794bbcde6287f50fb.png
1a42cd7b63be44b794bbcde6287f50fb.png

运行结果:

582cf6079d4c254b7e3862d654b0d5a0.png
582cf6079d4c254b7e3862d654b0d5a0.png

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

  代码示例:

2d8c43432a4477fc7764bb0b6057fc10.png
2d8c43432a4477fc7764bb0b6057fc10.png

运行结果:

db9cf3898ed621a57b1a99d369989d96.png
db9cf3898ed621a57b1a99d369989d96.png

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

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

代码示例:

1e032888be39ca369cba53f6b96a55d5.png
1e032888be39ca369cba53f6b96a55d5.png

运行结果:

5e954a6f3efa2baba2e9f217fa0ee651.png
5e954a6f3efa2baba2e9f217fa0ee651.png

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

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

  insert语句代码示例:

51bde168e10d4abcbb086a1fecb06023.png
51bde168e10d4abcbb086a1fecb06023.png

运行结果:

a4ee0b6aeb65e3a984e1116e323161c8.png
a4ee0b6aeb65e3a984e1116e323161c8.png

数据库:

af87f1215d64fdd7b030ced9a3151431.png
af87f1215d64fdd7b030ced9a3151431.png

update语句代码示例:

b84c9e81120f144cf04fa35372e79af8.png
b84c9e81120f144cf04fa35372e79af8.png

运行结果:

854ce930000e8080775c603d2bc55b51.png
854ce930000e8080775c603d2bc55b51.png

delete语句代码示例:

85e10cd6afcc1e9cedcc6d9a39dd064e.png
85e10cd6afcc1e9cedcc6d9a39dd064e.png

运行结果:

b41e52dc270cc170766d482d903c8103.png
b41e52dc270cc170766d482d903c8103.png

数据库:

a0224f8764dd723272685dbd97b0ca61.png
a0224f8764dd723272685dbd97b0ca61.png

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

daf92c6da6efe32568f9a7504c10f480.png
daf92c6da6efe32568f9a7504c10f480.png

运行结果:

f7857a3a5985e6c138307c6e12b10748.png
f7857a3a5985e6c138307c6e12b10748.png

数据库:

021830f8507d8bc09c4b6dc406cc5a3f.png
021830f8507d8bc09c4b6dc406cc5a3f.png

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

  代码示例:

87f326f5dbba7a0d332e89610fef50bf.png
87f326f5dbba7a0d332e89610fef50bf.png

运行结果:

737883c00536a99a5c424e89ef6cdf33.png
737883c00536a99a5c424e89ef6cdf33.png

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

6f81687c177064d3379aa21a804cf375.png
6f81687c177064d3379aa21a804cf375.png
2fd7826cf18fd9a2c7101f8bf17f05e4.png
2fd7826cf18fd9a2c7101f8bf17f05e4.png

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

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

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

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

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

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

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

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

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

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

465d6db885d35515f8c6eb27784c5925.png
465d6db885d35515f8c6eb27784c5925.png

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

  SHOW VARIABLES LIKE '%max_allowed_packet%';

86c6b04d50676d00d9c1f873163b5387.png
86c6b04d50676d00d9c1f873163b5387.png

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

max_allowed_packet = 20M

53a06739ba844607d5380fc9220721fa.png
53a06739ba844607d5380fc9220721fa.png

修改方法:

1) 方法1

可以编辑my.ini来修改(Linux下my.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
f2ef63031596643a1febf0bce92ac9a9.png

运行结果:

aa8c1981b8153da2e015a6b17ed4877d.png
aa8c1981b8153da2e015a6b17ed4877d.png

数据库:

8dbdba5c13a25f0c2fb25875d07f398e.png
8dbdba5c13a25f0c2fb25875d07f398e.png

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

  代码示例:

5644c7e2a3020618e5b0a31aadae7d9b.png
5644c7e2a3020618e5b0a31aadae7d9b.png

运行结果:

97ec95eb7717ac8bfe04c453aa335a0e.png
97ec95eb7717ac8bfe04c453aa335a0e.png

文件:

9cb84daf5222f5e043052bc00b27f8e3.png
9cb84daf5222f5e043052bc00b27f8e3.png
27ceb25bf5b803b10dfce88d9d36605b.png
27ceb25bf5b803b10dfce88d9d36605b.png

调用存储过程:

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

代码示例:

7ddececa36a0837de9a6e32d41268027.png
7ddececa36a0837de9a6e32d41268027.png

运行结果:

323efe7d8faee968d828a1eb8e847d56.png
323efe7d8faee968d828a1eb8e847d56.png
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2017/10/28 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
云数据库 SQL Server
腾讯云数据库 SQL Server (TencentDB for SQL Server)是业界最常用的商用数据库之一,对基于 Windows 架构的应用程序具有完美的支持。TencentDB for SQL Server 拥有微软正版授权,可持续为用户提供最新的功能,避免未授权使用软件的风险。具有即开即用、稳定可靠、安全运行、弹性扩缩等特点。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档