JDBC编程之连接Mysql数据库实现和SQL注入问题讲解(超详细!!!)

一、数据库驱动

应用程序不会直接对数据库进行操作,而是通过数据库生产商提供的数据库驱动程序来间接地对数据库进行操作。
JDBC编程之连接Mysql数据库实现和SQL注入问题讲解(超详细!!!)_第1张图片

二、JDBC

SUN公司为了简化开发人员对数据库的统一操作,提供了一个Java操作数据库的规范,俗称JDBC。这些规范的实现由具体的数据库生产商去做,开发人员只需要掌握JDBC接口的操作即可。
JDBC编程之连接Mysql数据库实现和SQL注入问题讲解(超详细!!!)_第2张图片

1.所需要的包:

  • java.sql
  • javax.sql
  • 需要导入一个数据库驱动包:mysql-connector-java-8.0.20.jar

2.jdbc代码:

package jdbcProject;

//第一步:导入必须的包
import java.sql.*;

public class jdbcDemo01 {
	  //第二步:说明JDBC驱动的名称和数据库的地址
    static final String JDBC_DRIVER = "com.mysql.jdbc.Driver";
    static final String DB_URL = "jdbc:mysql://localhost:3306/school?" +
            "useUnicode=true&characterEncoding=utf-8&useSSL=true";//连接school数据库
  	//Oracle--(jdbc:oracle:thin:@localhost:1521:sid) 
    //第三步:说明数据库的认证账户及密码
    static final String USER = "root";
    static final String PASS = "123456";
    
	public static void main(String[] args) throws ClassNotFoundException, SQLException{
		//第四步:注册JDBC驱动
    Class.forName(JDBC_DRIVER);

    //第五步:获得数据库连接
    Connection connection =  DriverManager.getConnection(DB_URL,USER,PASS);
    //第六步:执行查询语句
    Statement statement = connection.createStatement();
    String sql = "SELECT * FROM student";
    ResultSet rs =statement.executeQuery(sql);
    while (rs.next())
    {
         String studentno = rs.getString("studentno");
         String loginpwd=rs.getString("loginpwd");
         String studentname=rs.getString("studentname");
         String sex=rs.getString("sex");
         String gradeid=rs.getString("gradeid");
         String phone=rs.getString("phone");
         String address=rs.getString("address");
         String borndate=rs.getString("borndate");
         String email=rs.getString("email");
         String identitycard = rs.getString("identitycard");

         System.out.println(studentno+"\t"+loginpwd+"\t"+studentname+"\t"+sex+"\t"
                +gradeid+"\t"+phone+"\t"+address+"\t"+borndate+"\t"+email+"\t"+identitycard);
     }
     //第七步:关闭连接资源
     rs.close();
     statement.close();
     connection.close();
	}
}

3.Statement和PrepareStatement的区别:

  • Statement用于执行静态SQL语句,在执行时,必须指定一个事先准备好的SQL语句。
  • PrepareStatement是预编译的SQL语句对象,sql语句被预编译并保存在对象中。
  • Statement每次执行sql语句,相关数据库都需要执行sql语句的编译。而Preparedstatement是预编译的,并且支持批处理。
  • 使用PrepareStatement对象执行sql时,sql被数据库进行解析和编译,然后被放到命令缓冲区,每当执行同一个PrepareStatement对象时,它就会被解析一次,但不会被再次编译。在缓冲区可以发现预编译的命令,并且可以重用。
  • PrepareStatement可以减少编译次数提高数据库性能。

4.执行SQL的对象:

  • Statement.executeQuery( ):执行查询操作并返回查询结果ResultSet。
  • Statement.execute( ):执行任何SQL语句。
  • Statement.executeUpdate( ):执行更新、插入,删除操作,返回一个受影响的行数。

5.ResultSet查询结果集,封装了所有的查询结果:

  • 获取指定数据类型的结果:
//在不知道列的数据类型情况下使用
ResultSet.getObeject();
//获取指定的数据类型
ResultSet.getInt();
ResultSet.getFloat();
ResultSet.getDate();
  • ResultSet的遍历和指针使用:
ResultSet.beforeFirst();//移动到最前面
ResultSet.afterLast();//移动到最后面
ResultSet.next();//移动到后一行
ResultSet.previous();//移动到前一行
ResultSet.absolute(row);//移动到指定的row行

6.释放资源:

ResultSet.close();
Statement.close();
Connection.close();//Connection非常消耗资源,

三、通过提取工具类来实现Mysql的增删改查

1.使用properties存放Mysql的连接配置

Db.properties配置文件如下:

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/school?useUnicode=true&&characterEncoding=utf-8&useSSL=true
username=root
password=123456

2.编写Mysql数据库连接的提取工具类

提取工具类JdbcUtils代码如下:

package jdbcProject.lesson02.utils;

import java.io.InputStream;
import java.sql.*;
import java.util.Properties;

//提取工具类
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");

            //1.驱动只要加载一次
            Class.forName(driver);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    //2.获取连接
    public static Connection getConnection() throws SQLException {
        return DriverManager.getConnection(url,username,password);
    }

    //3.释放连接资源
    public static void releaseResourse(Connection connection, Statement statement, ResultSet resultSet) throws SQLException {
        if(resultSet!=null){
            resultSet.close();
        }

        if(statement!=null){
            statement.close();
        }

        if(connection!=null){
            connection.close();
        }
    }
}

3.实现查询操作

TestSelect.java文件代码如下:

package jdbcProject.lesson02;

import jdbcProject.lesson02.utils.JdbcUtils;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class TestSelect {

    public static void main(String[] args) throws SQLException {
        Connection connection=null;
        Statement statement=null;
        ResultSet resultSet=null;

        try {
            //执行查询操作
            connection= JdbcUtils.getConnection();//获取数据库连接
            statement=connection.createStatement();//获取SQL的执行对象

            String sql="select * from grade";

            resultSet=statement.executeQuery(sql);
            while (resultSet.next()){
                System.out.println(resultSet.getString("gradeid")+"|"+resultSet.getString("gradename"));
            }
            System.out.println("查询成功!");
        } catch (
                SQLException e) {
            e.printStackTrace();
        }finally {
            //释放资源
            JdbcUtils.releaseResourse(connection,statement,resultSet);
        }
    }
}

4.实现删除操作

TestDelete.java文件代码如下:

package jdbcProject.lesson02;

import jdbcProject.lesson02.utils.JdbcUtils;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class TestDelete {
    public static void main(String[] args) throws SQLException {
        Connection connection=null;
        Statement statement=null;
        ResultSet resultSet=null;

        try {
            //执行删除操作
            connection= JdbcUtils.getConnection();//获取数据库连接
            statement=connection.createStatement();//获取SQL的执行对象

            String sql="delete from grade where gradeid=6";

            int i=statement.executeUpdate(sql);
            if(i>0){
                System.out.println("删除成功!");
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            //释放资源
            JdbcUtils.releaseResourse(connection,statement,resultSet);
        }
    }
}

5.实现插入操作

package jdbcProject.lesson02;

import jdbcProject.lesson02.utils.JdbcUtils;

import java.sql.*;

public class TestInsert {
    public static void main(String[] args) throws SQLException {
        Connection connection=null;
        Statement statement=null;
        ResultSet resultSet=null;

        try {
            //执行插入操作
            connection= JdbcUtils.getConnection();//获取数据库连接
            statement=connection.createStatement();//获取SQL的执行对象

            String sql="insert into grade(gradeid, gradename)\n" +
                    "values(6,'研一')";

            int i=statement.executeUpdate(sql);
            if(i>0){
                System.out.println("插入成功!");
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            //释放资源
            JdbcUtils.releaseResourse(connection,statement,resultSet);
        }
    }    
}

6.实现更新操作

package jdbcProject.lesson02;

import jdbcProject.lesson02.utils.JdbcUtils;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class TestUpdate {
    public static void main(String[] args) throws SQLException {
        Connection connection=null;
        Statement statement=null;
        ResultSet resultSet=null;

        try {
            //执行更新操作
            connection= JdbcUtils.getConnection();//获取数据库连接
            statement=connection.createStatement();//获取SQL的执行对象

            String sql="update grade set gradename='研二' where gradeid=6";

            int i=statement.executeUpdate(sql);
            if(i>0){
                System.out.println("更新成功!");
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            //释放资源
            JdbcUtils.releaseResourse(connection,statement,resultSet);
        }
    }
}

四、SQL注入

1.什么是SQL注入

SQL注入即是指web应用程序对用户输入数据的合法性没有判断或过滤不严,攻击者可以在web应用程序中事先定义好的查询语句的结尾上添加额外的SQL语句,在管理员不知情的情况下实现非法操作,以此来实现欺骗数据库服务器执行非授权的任意查询,从而进一步得到相应的数据信息。

2.SQL注入攻击的总体思路

  • 寻找到SQL注入的位置

  • 判断服务器类型和后台数据库类型

  • 针对不同的服务器和数据库特点进行SQL注入攻击

3.如何防御SQL注入

  • 检查变量数据类型和格式
  • 过滤特殊符号
  • 绑定变量,使用预编译语句
  • 输入“1 and version()>0”

4.PrepareStatement可以防止sql注入

  • 为什么Statement会被sql注入

    因为Statement之所以会被sql注入是因为SQL语句结构发生了变化。比如:

    "select * from tablename where username='"+uesrname+  
    "'and password='"+password+"'"
    

    在用户输入’or true or’之后sql语句结构改变。

    select * from tablename where username=''or true or'' and password=''
    

    这样本来是判断用户名和密码都匹配时才会计数,但是经过改变后变成了或的逻辑关系,不管用户名和密码是否匹配该式的返回值永远为true。

  • 为什么Preparement可以防止SQL注入

    因为Preparement样式为

    select * from tablename where username=? and password=?
    

    该SQL语句会在得到用户的输入之前先用数据库进行预编译,这样的话不管用户输入什么用户名和密码的判断始终都是并的逻辑关系,防止了SQL注入。

  • 总结:参数化能防注入的原因在于,语句是语句,参数是参数,参数的值并不是语句的一部分,数据库只按语句的语义跑,至于跑的时候是带一个普通背包还是一个怪物,不会影响行进路线,无非跑的快点与慢点的区别。

5.SQL注入的实现

SQLInjection.java代码如下:

package jdbcProject.lesson02;

import jdbcProject.lesson02.utils.JdbcUtils;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class SQLInjection {
    public static void main(String[] args) throws SQLException {
        //login("张伟","123456");//正常登录方式![截屏2020-06-15 下午6.13.44](/Users/shaomingmin/Library/Application Support/typora-user-images/截屏2020-06-15 下午6.13.44.png)
        login("'or' 1=1","'or' 1=1");//SQL会被拼接 or
    }

    //登录业务
    public static void login(String username, String password) throws SQLException {
        Connection connection=null;
        Statement statement=null;
        ResultSet resultSet=null;

        try {
            //执行查询操作
            connection= JdbcUtils.getConnection();//获取数据库连接
            statement=connection.createStatement();//获取SQL的执行对象

            String sql="select * from student where studentname='"+username+"' and loginpwd='"+password+"'";

            resultSet=statement.executeQuery(sql);
            while (resultSet.next()){
                System.out.println(resultSet.getString("studentname")+"\t "+resultSet.getString("loginpwd"));
            }
            System.out.println("查询成功!");
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            //释放资源
            JdbcUtils.releaseResourse(connection,statement,resultSet);
        }
    }
}

运行结果如下,读取了表中所有的用户名和密码:

JDBC编程之连接Mysql数据库实现和SQL注入问题讲解(超详细!!!)_第3张图片

6.使用PreparedStatement和“?”占位符进行更新操作

TestInsert.java代码如下:

package jdbcProject.lesson03;

import jdbcProject.lesson02.utils.JdbcUtils;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class TestInsert {
    public static void main(String[] args) throws SQLException {
        Connection connection=null;
        PreparedStatement preparedStatement=null;
        ResultSet resultSet=null;

        try{
            connection=JdbcUtils.getConnection();
            //区别
            //使用?占位符代替参数
            String sql="insert into grade(gradeid, gradename) values(?,?)";
            preparedStatement=connection.prepareStatement(sql);//预编译SQL,不立马执行
            preparedStatement.setInt(1,7);//gradeid
            preparedStatement.setString(2,"研三");
            int i=preparedStatement.executeUpdate();
            if(i>0){
                System.out.println("插入成功!");
            }

        }catch (SQLException e){
            e.printStackTrace();
        }finally {
            JdbcUtils.releaseResourse(connection,preparedStatement,resultSet);
        }
    }
}

运行结果如下:

JDBC编程之连接Mysql数据库实现和SQL注入问题讲解(超详细!!!)_第4张图片

你可能感兴趣的:(Java,数据库系统原理,MySQL)