jdbc-PrepareStatement
- PrepareStatement的作用
预编译SQL语句并执行;预防SQL注入问题
- SQL注入的说明:
sql注入是通过操作输入来修改事先准备定义好的SQL语句,用以达到执行代码对服务器进行进攻的方法
比如我们在进行登录时:需要输入账号和密码,当我们在输入密码为 ‘or’1’='1时会产生sql注入,看下面分析:
@Test
public void testLogin() throws Exception {
//2. 获取连接:如果连接的是本机mysql并且端口是默认的 3306 可以简化书写
String url = "jdbc:mysql:///db1?useSSL=false";
String username = "root";
String password = "1234";
Connection conn = DriverManager.getConnection(url, username, password);
// 接收用户输入 用户名和密码
String name = "sjdljfld";
String pwd = "' or '1' = '1";
String sql = "select * from tb_user where username = '"+name+"' and password = '"+pwd+"'";
// 获取stmt对象
Statement stmt = conn.createStatement();
// 执行sql
ResultSet rs = stmt.executeQuery(sql);
// 判断登录是否成功
if(rs.next()){
System.out.println("登录成功~");
}else{
System.out.println("登录失败~");
}
//7. 释放资源
rs.close();
stmt.close();
conn.close();
}
看该条语句:“select * from tb_user where username = '”+name+“’ and password = '”+pwd+“'”;
将我们输入的账号密码写入(账号随意,密码会产生sql注入): password = ’ ‘or’1’='1 ’ ==>
password = ’ ‘or’1’=‘1’ ; ‘’ => 假 或 ‘1’=‘1’ 真 所以得到的结果为真,所以就算输入的不是真正的密码,最终也能够实现登录。
现在我们使用?(占位符)来防止sql注入:
// SQL语句中的参数值,使用?占位符替代
String sql = "select * from user where username = ? and password = ?";
// 通过Connection对象获取,并传入对应的sql语句
PreparedStatement pstmt = conn.prepareStatement(sql);
我们通过PrepareStatement对象的setXxx()方法来设置参数?的值,如下:
// 接收用户输入 用户名和密码
String name = "zhangsan";
String pwd = "' or '1' = '1";
// 定义sql
String sql = "select * from tb_user where username = ? and password = ?";
// 获取pstmt对象
PreparedStatement pstmt = conn.prepareStatement(sql);
// 设置?的值
pstmt.setString(1,name);
pstmt.setString(2,pwd);
// 执行sql
ResultSet rs = pstmt.executeQuery();
// 判断登录是否成功
if(rs.next()){
System.out.println("登录成功~");
}else{
System.out.println("登录失败~");
}
我就很好奇为啥这样就不会产生sql注入?PrepareStatement是如何实现的?
PrepareStatement是将特殊字符进行了转义,转义的sql如下:
select * from tb_user where username = 'sjdljfld' and password = '\'or \'1\' = \'1'
PrepareStatement的优点:
预编译SQL,性能更高
防止SQL注入:将敏感字符进行转义
java代码操作数据库流程如图:
开启预编译功能:
在代码中编写url时需要加上以下参数。而我们之前根本就没有开启预编译功能,知识解决了sql注入漏洞
useServerPrepstmts=true
配置MYSQL执行日志(重启mysql服务后生效)
- 在mysql配置文件(my.ini)中添加如下配置
log-output=FILE
general-log=1
general_log_file="D:\mysql.log"
slow-query-log=1
slow_query_log_file="D:\mysql_slow.log"
long_query_time=2
小结
- 在获取PreparedStatement对象时,将sql语句发送给mysql服务器进行检查,编译(这些步骤很耗时)
- 执行时就不用再进行这些步骤了,速度更快
- 如果sql模板一样,则只需要进行一次检查、编译
4,数据库连接池
-
数据库连接池是个容器,负责分配、管理数据库连接(Connection)
-
它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个;
-
释放空闲时间超过最大空闲时间的数据库连接来避免因为没有释放数据库连接而引起的数据库连接遗漏
-
好处
-
资源重用
-
提升系统响应速度
-
避免数据库连接遗漏
数据库连接池实现
-
标准接口:DataSource
官方(SUN) 提供的数据库连接池标准接口,由第三方组织实现此接口。该接口提供了获取连接的功能:
Connection getConnection()
那么以后就不需要通过
DriverManager
对象获取Connection
对象,而是通过连接池(DataSource)获取Connection
对象。 -
常见的数据库连接池
- DBCP
- C3P0
- Druid
我们现在使用更多的是Druid,它的性能比其他两个会好一些。
-
Druid(德鲁伊)
-
Druid连接池是阿里巴巴开源的数据库连接池项目
-
功能强大,性能优秀,是Java语言最好的数据库连接池之一
-