【MySQL】MySQL基础教程(14)
前言:
本文内容:Statement对象详解、SQL注入问题、PreparedStatement对象
推荐免费MySQL基础讲解视频:【狂神说Java】MySQL最新教程通俗易懂哔哩哔哩bilibili
Statement对象详解
JDBC中的Statement对象用于向数据库发送SQL语句,想完成对数据库的增删改查,只需要通过这个对象向数据库发送增删改查语句即可。
CRUD操作
create
使用executeUpdate(String sql)方法完成数据添加操作,示例操作:
1 | Statement st = conn.createStatement(); |
read
使用executeQuery(String sql)方法完成数据库查询操作:
1 | Statement st = conn.createStatement(); |
update
使用executeUpdate(String sql)方法完成数据修改操作:
1 | Statement st = conn.createStatement(); |
delete
使用executeUpdate(String sql)方法完成数据删除操作:
1 | Statement st = conn.createStatement(); |
代码实例
-
提取工具类
db.properties
1
2
3
4
5# db.properties
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/jdbcstudy?useSSL=false&serverTimezone=UTC
username=root
password=123456JDBCUtils.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60package com.jokerdig.utils;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
/**
* @author Joker大雄
* @data 2022/3/21 - 13:17
**/
public class JDBCUtils {
private static String driver = null;
private static String url = null;
private static String username = null;
private static String password = null;
static{
try {
InputStream in = JDBCUtils.class.getClassLoader().getResourceAsStream("db.properties");
Properties properties = new Properties();
properties.load(in);
driver = properties.getProperty("driver");
url = properties.getProperty("url");
username = properties.getProperty("username");
password = properties.getProperty("password");
// 加载一次驱动
Class.forName(driver);
} catch (Exception e) {
e.printStackTrace();
}
}
// 获取连接
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(url,username,password);
}
// 释放资源
public static void release(Connection connection, Statement statement, ResultSet resultSet){
try {
if(resultSet!=null){
resultSet.close();
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}
try {
if(statement!=null){
statement.close();
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}
try {
if(connection!=null){
connection.close();
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
} -
增删改方法
executeUpdate
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36package com.jokerdig.lesson02;
import com.jokerdig.utils.JDBCUtils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
/**
* @author Joker大雄
* @data 2022/3/21 - 13:44
**/
public class TestInsert {
public static void main(String[] args) {
Connection conn = null;
Statement st = null;
ResultSet rs = null;
try {
conn = JDBCUtils.getConnection();
st = conn.createStatement();
String sql = "insert into users(`id`,`name`,`password`,email,birthday) " +
"values(4,'夏明','123456','xm@qq.com','1999-01-22')";
int back = st.executeUpdate(sql);
if(back==1){
System.out.println("添加成功");
}else{
System.out.println("添加失败");
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally{
JDBCUtils.release(conn,st,rs);
}
}
} -
查询方法
executeQuery
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33package com.jokerdig.lesson02;
import com.jokerdig.utils.JDBCUtils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
/**
* @author Joker大雄
* @data 2022/3/21 - 13:29
**/
public class TestQuery {
public static void main(String[] args) {
Connection conn = null;
Statement st = null;
ResultSet rs = null;
try {
conn = JDBCUtils.getConnection();
st = conn.createStatement();
String sql = "select * from users";
rs = st.executeQuery(sql);
while(rs.next()){
System.out.println("id:"+rs.getInt("id")+" name:"+rs.getString("name")+" password:"+rs.getString("password")+"\n");
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally{
JDBCUtils.release(conn,st,rs);
}
}
}
SQL注入问题
SQL存在漏洞,会被攻击导致数据泄露;
恶意拼接查询
SQL 语句可以查询、插入、更新和删除数据,且使用分号来分隔不同的命令。例如:
1 | SELECT * FROM users WHERE user_id = $user_id |
其中,user_id 是传入的参数,如果传入的参数值为“1234; DELETE FROM users”,那么最终的查询语句会变为:
1 | SELECT * FROM users WHERE user_id = 1234; DELETE FROM users |
如果以上语句执行,则会删除 users 表中的所有数据。
利用注释执行非法命令
SQL 语句中可以插入注释。例如:
1 | SELECT COUNT(*) AS 'num' FROM game_score WHERE game_id=24411 AND version=$version |
如果 version 包含了恶意的字符串'-1' OR 3 AND SLEEP(500)--
,那么最终查询语句会变为:
1 | SELECT COUNT(*) AS 'num' FROM game_score WHERE game_id=24411 AND version='-1' OR 3 AND SLEEP(500)-- |
以上恶意查询只是想耗尽系统资源,SLEEP(500) 将导致 SQL 语句一直运行。若在其中添加了修改、删除数据的恶意指令,那么将会造成更大的破坏。
传入非法参数
SQL 语句中传入的字符串参数是用单引号引起来的,如果字符串本身包含单引号而没有被处理,那么可能会篡改原本 SQL 语句的作用。 例如:
1 | SELECT * FROM user_name WHERE user_name = $user_name |
如果 user_name 传入参数值为 G’zhang,那么最终的查询语句会变为:
1 | SELECT * FROM user_name WHERE user_name ='G'zhang' |
一般情况下,以上语句会执行出错,这样的语句风险比较小。虽然没有语法错误,但可能会恶意产生 SQL 语句,并且以一种你不期望的方式运行。
添加额外条件
在 SQL 语句中添加一些额外条件,以此来改变执行行为。条件一般为真值表达式。例如:
1 | UPDATE users SET userpass='$userpass' WHERE user_id=$user_id; |
如果 user_id 被传入恶意的字符串“1234 OR TRUE”,那么最终的 SQL 语句会变为:
1 | UPDATE users SET userpass= '123456' WHERE user_id=1234 OR TRUE; |
这将更改所有用户的密码。
如何避免SQL注入
使用PreparedStatement对象
PreparedStatement对象
PreparedStatement对象防止SQL注入,执行效率更好。
增删改
这里只写添加
1 | package com.jokerdig.lesson03; |
查询
1 | package com.jokerdig.lesson03; |
防止SQL注入
PreparedStatement 防止SQL注入的本质,把传递进来的参数当作字符;如果SQL语句中存在
'
,会被直接转义,从而防止SQL注入。