目录
JDBC的简单使用
向JDBC注入攻击
防止注入攻击
自建JDBC工具类
自建工具类优化--使用配置文件
使用数据库连接池优化工具类
JDBC的简单使用
1 package Test;
2
3 import java.sql.Connection;
4 import java.sql.Driver;
5 import java.sql.DriverManager;
6 import java.sql.DriverPropertyInfo;
7 import java.sql.ResultSet;
8 import java.sql.SQLException;
9 import java.sql.Statement;
10
11
12 /*JDBCsun公司提供的一套标准数据库操作规范
13 * JDBC使用步骤
14 * 1 注册驱动--告诉JVM使用的是哪一个数据库
15 * 2 获得连接--使用JDBC中的类完成对MySQL数据库的连接
16 * 3 获得语句执行平台--通过连接对象获取SQL语句1的执行者对象
17 * 4 执行sql语句--使用执行者对象向数据库执行SQL语句,并获取执行后的结果
18 * 5 处理结果
19 * 6 释放资源
20 * ----------在使用之前一定要先导入jar包
21 */
22
23 public class Main{
24 public static void main(String[] args) throws ClassNotFoundException, SQLException {
25 //1 注册驱动,但查看源码发现这样会注册两次
26 //DriverManager.registerDriver(new Driver());
27 //使用反射技术注册,在这里类名可能找不到因此抛出类名查不到的异常
28 Class.forName("com.mysql.jdbc.Driver");
29
30 //2连接数据库 url:数据库 jdbc:jdbc:mysql://连接主机IP:端口号//数据库名
31 String url ="jdbc:mysql://localhost:3306/mybase";
32 String username="root";//用户名
33 String password="123";//密码
34 //连接,可能连接不到抛出SQL异常
35 Connection con =DriverManager.getConnection(url, username,password);
36
37 //3 获得语句执行平台,通过数据库连接对象获得SQL语句的执行者对象,注意导包为sql的包
38 Statement stat=con.createStatement();
39 //查询语句
40 String sql ="Select * from titles";
41
42 //4 调用执行者对象方法,执行SQL语句获取结果集
43 ResultSet rs=stat.executeQuery(sql);
44 //5 处理结果集
45 while(rs.next()){
46 System.out.println(rs.getString("emp_no")+" "+rs.getString("title"));
47 }
48
49 //6 释放资源
50 rs.close();
51 stat.close();
52 con.close();
53 }
54 }
向JDBC注入攻击
创建数据表
1 CREATE TABLE users(
2 username VARCHAR(20),
3 PASSWORD VARCHAR(10)
4 );
5
6 INSERT INTO users VALUES('a','1'),('b','2');
![](https://i-blog.csdnimg.cn/blog_migrate/6a6b308b23f0185033a1fdee37202d50.png)
待注入攻击的代码:
1 package Test;
2
3 import java.sql.Connection;
4 import java.sql.Driver;
5 import java.sql.DriverManager;
6 import java.sql.DriverPropertyInfo;
7 import java.sql.ResultSet;
8 import java.sql.SQLException;
9 import java.sql.Statement;
10 import java.util.Scanner;
11
12
13 /*MySQL注入攻击
14 * 用户登录案例
15 */
16
17 public class Main{
18 public static void main(String[] args) throws ClassNotFoundException, SQLException {
19 Class.forName("com.mysql.jdbc.Driver");
20
21 //2连接数据库 url:数据库 jdbc:jdbc:mysql://连接主机IP:端口号//数据库名
22 String url ="jdbc:mysql://localhost:3306/mybase";
23 String username="root";//用户名
24 String password="123";//密码
25 Connection con =DriverManager.getConnection(url, username,password);
26 Statement stat=con.createStatement();
27 //查询语句
28 Scanner sc=new Scanner(System.in);
29 String user=sc.next();
30 String pass=sc.next();
31 String sql ="Select * from users where username= '"+user+"' and password= '"+pass+"'";
32
33 //4 调用执行者对象方法,执行SQL语句获取结果集
34 ResultSet rs=stat.executeQuery(sql);
35 System.out.println(sql);
36 //5 处理结果集
37 while(rs.next()){
38 System.out.println(rs.getString("username")+" "+rs.getString("password"));
39 }
40
41 //6 释放资源
42 rs.close();
43 stat.close();
44 con.close();
45 }
46 }
代码运行结果:
![](https://i-blog.csdnimg.cn/blog_migrate/447b2463d80d5447db6e15713ab65bd3.png)
攻击的原理:
利用SQL语句:Select * from users where username= 'a' and password= '1'or'1=1',这样由于最后一个是或运算那么就会显示出来所有的数据,因此在输入时只要想办法凑成这样的形式就可以了。
输入:aa 12'or'1=1 这样便可以完成攻击,即使输入的用户名不对也可以正常登陆。
防止注入攻击
1 package Test;
2
3 import java.sql.Connection;
4 import java.sql.Driver;
5 import java.sql.DriverManager;
6 import java.sql.DriverPropertyInfo;
7 import java.sql.PreparedStatement;
8 import java.sql.ResultSet;
9 import java.sql.SQLException;
10 import java.sql.Statement;
11 import java.util.Scanner;
12
13 /*MySQL防止注入攻击--采用statement的子类preparedstatement
14 * 还可以用占位符实现增删改查等操作
15 */
16
17 public class Main{
18 public static void main(String[] args) throws ClassNotFoundException, SQLException {
19 Class.forName("com.mysql.jdbc.Driver");
20
21 //2连接数据库 url:数据库 jdbc:jdbc:mysql://连接主机IP:端口号//数据库名
22 String url ="jdbc:mysql://localhost:3306/mybase";
23 String username="root";//用户名
24 String password="123";//密码
25 Connection con =DriverManager.getConnection(url, username,password);
26
27 //查询语句
28 Scanner sc=new Scanner(System.in);
29 String user=sc.next();
30 String pass=sc.next();
31 //用?占位符代替参数
32 String sql ="Select * from users where username=? and password= ?";
33 PreparedStatement pds=con.prepareStatement(sql);
34 pds.setObject(1, user);
35 pds.setObject(2, pass);
36 //4 调用执行者对象方法,执行SQL语句获取结果集
37 ResultSet rs=pds.executeQuery();
38 System.out.println(sql);
39 //5 处理结果集
40 while(rs.next()){
41 System.out.println(rs.getString("username")+" "+rs.getString("password"));
42 }
43
44 //6 释放资源
45 rs.close();
46 pds.close();
47 con.close();
48 }
49 }
自建JDBC工具类
JDBCUtils.class文件
1 package Test;
2
3 import java.sql.Connection;
4 import java.sql.DriverManager;
5 import java.sql.ResultSet;
6 import java.sql.SQLException;
7 import java.sql.Statement;
8
9 public class JDBCUtils {
10 private JDBCUtils(){}
11 private static Connection con;
12
13 static{
14 try {
15 Class.forName("com.mysql.jdbc.Driver");
16 //2连接数据库 url:数据库 jdbc:jdbc:mysql://连接主机IP:端口号//数据库名
17 String url ="jdbc:mysql://localhost:3306/mybase";
18 String username="root";//用户名
19 String password="123";//密码
20 con =DriverManager.getConnection(url, username,password);
21 } catch (Exception e) {
22 throw new RuntimeException(e+"数据库连接失败!");
23 }
24 }
25 //定义静态方法,返回数据库的连接对象
26 public static Connection getConnection(){
27 return con;
28 }
29
30 //释放资源
31 public static void close(Connection con,Statement stat){
32 if(stat!=null){
33 try {
34 stat.close();
35 } catch (SQLException e) {
36 // TODO Auto-generated catch block
37 e.printStackTrace();
38 }
39 }
40
41 if(con!=null){
42 try {
43 con.close();
44 } catch (SQLException e) {
45 // TODO Auto-generated catch block
46 e.printStackTrace();
47 }
48 }
49 }
50 //重载,关闭结果集
51 public static void close(Connection con,Statement stat,ResultSet rs){
52 //注意释放的顺序
53 if(rs!=null){
54 try {
55 rs.close();
56 } catch (SQLException e) {
57 // TODO Auto-generated catch block
58 e.printStackTrace();
59 }
60 }
61
62 if(stat!=null){
63 try {
64 stat.close();
65 } catch (SQLException e) {
66 // TODO Auto-generated catch block
67 e.printStackTrace();
68 }
69 }
70
71 if(con!=null){
72 try {
73 con.close();
74 } catch (SQLException e) {
75 // TODO Auto-generated catch block
76 e.printStackTrace();
77 }
78 }
79 }
80 }
测试代码:
1 package Test;
2
3 import java.sql.Connection;
4 import java.sql.PreparedStatement;
5 import java.sql.ResultSet;
6 import java.sql.SQLException;
7 import Test.JDBCUtils;
8
9 public class JDBCTset {
10 public static void main(String[] args) throws SQLException {
11 Connection con =JDBCUtils.getConnection();
12 PreparedStatement pst=con.prepareStatement("SELECT * FROM titles");
13 ResultSet rs =pst.executeQuery();
14 while(rs.next()){
15 System.out.println(rs.getString("title"));
16 }
17 //释放资源
18 JDBCUtils.close(con, pst);
19 }
20 }
自建工具类优化--使用配置文件
优化代码
1 package Test;
2
3 import java.io.IOException;
4 import java.io.InputStream;
5
6 /*在前面的代码中由于数据库用户名,密码直接在静态代码块中,相当于写死了代码,不容易修改
7 * 因此采用properties配置文件,方便后期维护。配置文件建议放在src下,方便自动拷贝bin目录下
8 *
9 */
10
11 import java.sql.Connection;
12 import java.sql.DriverManager;
13 import java.sql.ResultSet;
14 import java.sql.SQLException;
15 import java.sql.Statement;
16 import java.util.Properties;
17
18 public class JDBCUtils {
19 private JDBCUtils(){}
20 private static Connection con;
21 private static String driverClass;
22 private static String url;
23 private static String username;
24 private static String password;
25 //放到静态代码块中保证读取配置文件,获取连接只执行一次
26 static{
27 try{
28 readConfig();
29 //反射
30 Class.forName(driverClass);
31 con=DriverManager.getConnection(url,username,password);
32 }catch(Exception e){
33 throw new RuntimeException("数据库连接失败!");
34 }
35
36 }
37
38 private static void readConfig() throws IOException{
39 //通过字节流,使用类加载器读取配置文件的内容
40 InputStream in = JDBCUtils.class.getClassLoader().getResourceAsStream("database.properties");
41 Properties pro = new Properties();
42 pro.load(in);
43 driverClass=pro.getProperty("driverClass");
44 url = pro.getProperty("url");
45 username=pro.getProperty("username");
46 password=pro.getProperty("password");
47 }
48
49 //定义静态方法,返回数据库的连接对象
50 public static Connection getConnection(){
51 return con;
52 }
53
54 //释放资源
55 public static void close(Connection con,Statement stat){
56 if(stat!=null){
57 try {
58 stat.close();
59 } catch (SQLException e) {
60 // TODO Auto-generated catch block
61 e.printStackTrace();
62 }
63 }
64
65 if(con!=null){
66 try {
67 con.close();
68 } catch (SQLException e) {
69 // TODO Auto-generated catch block
70 e.printStackTrace();
71 }
72 }
73 }
74 //重载,关闭结果集
75 public static void close(Connection con,Statement stat,ResultSet rs){
76 //注意释放的顺序
77 if(rs!=null){
78 try {
79 rs.close();
80 } catch (SQLException e) {
81 // TODO Auto-generated catch block
82 e.printStackTrace();
83 }
84 }
85
86 if(stat!=null){
87 try {
88 stat.close();
89 } catch (SQLException e) {
90 // TODO Auto-generated catch block
91 e.printStackTrace();
92 }
93 }
94
95 if(con!=null){
96 try {
97 con.close();
98 } catch (SQLException e) {
99 // TODO Auto-generated catch block
100 e.printStackTrace();
101 }
102 }
103 }
104 }
测试代码
1 package Test;
2
3 import java.sql.Connection;
4 import java.sql.PreparedStatement;
5 import java.sql.ResultSet;
6 import java.sql.SQLException;
7 import Test.JDBCUtils;
8
9 public class JDBCTset {
10 public static void main(String[] args) throws SQLException {
11 Connection con =JDBCUtils.getConnection();
12 //当能输出数据库连接时边说用工具类正常了
13 System.out.println(con);
14 //由于是简单的测试,因此不用释放资源
15 //JDBCUtils.close(con, pst);
16 }
17 }
使用数据库连接池优化工具类
优化代码:
1 package Test;
2 import java.io.IOException;
3 import java.io.InputStream;
4 import java.util.Properties;
5
6 import javax.sql.DataSource;
7
8 /*
9 * JDBC连接池工具类,使用连接池专门负责数据库的连接
10 * JDBC连接池简化了sql语句中的增删改查操作,方便代码编写
11 */
12 import org.apache.commons.dbcp.BasicDataSource;
13
14
15 public class JDBCUtils {
16 private JDBCUtils(){}
17 private static String driverClass;
18 private static String url;
19 private static String username;
20 private static String password;
21 private static BasicDataSource datasource =new BasicDataSource();
22 //放到静态代码块中保证读取配置文件,获取连接只执行一次
23 static{
24 try {
25 readConfig();
26 //数据库连接配置
27 datasource.setDriverClassName(driverClass);
28 datasource.setUrl(url);
29 datasource.setUsername(username);
30 datasource.setPassword(password);
31 //对象连接池中的数量配置,这些配置可以不用配置的
32 datasource.setInitialSize(10);//初始化的连接数
33 datasource.setMaxActive(8);//最大连接数
34 datasource.setMaxIdle(5);//最大空闲数
35 datasource.setMinIdle(1);//最小空闲数
36 } catch (IOException e) {
37 // TODO Auto-generated catch block
38 e.printStackTrace();
39 }
40 }
41
42 private static void readConfig() throws IOException{
43 //通过字节流,使用类加载器读取配置文件的内容
44 InputStream in = JDBCUtils.class.getClassLoader().getResourceAsStream("database.properties");
45 Properties pro = new Properties();
46 pro.load(in);
47 driverClass=pro.getProperty("driverClass");
48 url = pro.getProperty("url");
49 username=pro.getProperty("username");
50 password=pro.getProperty("password");
51 }
52
53 //定义静态方法,返回数据库的连接对象
54 public static DataSource getDataSource(){
55 return datasource;
56 }
57 }
测试代码:
1 package Test;
2
3 import java.sql.SQLException;
4 import java.util.List;
5
6 import org.apache.commons.dbutils.QueryRunner;
7 import org.apache.commons.dbutils.handlers.ArrayHandler;
8 import org.apache.commons.dbutils.handlers.ArrayListHandler;
9
10 public class JDBCTset {
11 private static QueryRunner qr=new QueryRunner(JDBCUtils.getDataSource());
12
13 public static void main(String[] args) throws SQLException {
14 String sql="select * from titles";
15 //ArrayListHandler:把结果集中的每一行数据都转成一个对象数组,再存放到List中。这是dbutils所特有的
16 List<Object[]> list =qr.query(sql, new ArrayListHandler());
17 for(Object[] objs:list){
18 for(Object obj:objs)
19 System.out.print(obj+"\t\t");
20 System.out.println();
21 }
22 }
23
24 }
0