JDBC(一):JDBC的基本使用和Statment的SQL注入问题

JDBC

1. JDBC概述

1.1 什么是JDBC

使用Java这种语言去访问各种关系型数据库,如:MySQL,Oracle。Java DataBase Connectivity Java的数据库连接技术。

1. 2 好处

  1. 使用接口编程,不用考虑实现类,实现类由厂商实现。
  2. 代码不需要修改或者少量修改就能访问另一种数据库。
  3. 代码工作量少,学习一组接口就可以访问所有数据库。

1542941216981

2. JDBC使用

2.1 所用的包
会使用到的包说明
java.sql访问数据库的核心包,今天要学习的所有的接口都在这个包中
javax.sql访问数据库的扩展名,使用数据库的高级特性。如:连接池
数据库的驱动只需要导入即可,不需要对它进行任何的操作。
2.2 核心api
接口或类作用
DriverManager类1) 加载和注册驱动2) 创建连接对象
**Connection接口 **代表一个Java程序与数据库之间创建的一个连接对象
Statement接口代表一条要发送给服务器的SQL语句
ResultSet接口代表从服务器上返回的结果集

导包

在这里插入图片描述

在这里插入图片描述

2.3 使用步骤(以Mysql为例)
  1. 加载和注册驱动(可选)
Class.forName(数据库驱动实现类) 将驱动加载到内存

com.mysql.jdbc.Driver加载驱动的源代码

public class Driver extends NonRegisteringDriver implements java.sql.Driver {
    static { //类加载的时候执行
        try {
            DriverManager.registerDriver(new Driver());  //DriveManager类注册了驱动
        } catch (SQLException var1) {
            throw new RuntimeException("Can't register driver!");  //注册失败,不能注册驱动
        }
    }
}

从JDK1.5以后这个注册驱动就可以省略了

  1. 由DriverManager创建一个连接对象Connection
Connection conn = DriverManager.createConnection();
  1. 由Connection对象创建一个执行的语句对象Statement
Statement conn.createStatement();
  1. 由Statement语句对象发送SQL语句给服务器,由服务器执行SQL语句。
//执行查询语句,返回结果集
ResultSet executeQuery(sql); 
//执行DDL(数据库定义语言),返回布尔值
Boolean execute();
//执行增删改语句,返回影响的函数
int executeUpdate(); 
  1. 由服务器返回数据库的查询结果,封装成ResultSet结果集对象,返回给Java客户端。ResultSet方法如下
//移动到下一行,如果下一行为null则返回false:
Boolean next(); 
//XXX指的是数据类型
XXX rs.getXXX(int column); // 根据行号获取数据
XXX rs.getXXX(String name); // 根据名字获取数据
  1. 关闭资源
//关闭Result
Result的变量名.close();
//关闭Statement
Statement的变量名.close();
//关闭Connection
Connection的变量名.close();

案例:用JDBC操作数据库

package com.zmysna.test;

import com.zmysna.utils.JDBCUtils;

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

public class Test01 {
    private final static String DRIVER_NAME= "com.mysql.jdbc.Driver";
	private final static String URL = "jdbc:mysql://localhost:3306/day18";
    private final static String USER = "root";
    private final static String PASSWORD = "root";

    public static void main(String[] args){
        Connection connection = null;
        Statement statement = null;
        ResultSet rs = null;
        try {
            //注册驱动,JDK1.5之后可以省略
            //Class.forName(DRIVER_NAME);
            //连接数据库
            connection = DriverManager.getConnection(URL, USER, PASSWORD);
            statement = connection.createStatement();
            //执行DDL语句
           	String ddl = "create table student (id int primary key auto_increment, name varchar(20) not null unique, gender char(1))";
            statement.execute(ddl);
            //执行DML语句(增删改)
            String dml = "insert into student(name,gender) values('张三',‘男’)";
            statement.executeUpdate(dml)
       		//执行DQL查询语句
            String dql = "select * from student";
            rs = statement.executeQuery(dql);
            //遍历结果集
            while(rs.next()){
                String name = rs.getString("name");//获取名字
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {//关闭资源
            if(rs != null){
                try {
                    rs.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if(statement != null){
                try {
                    statement.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if(connection != null) {
                try {
                    connection.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

3. JDBC工具类

为了减少写代码的工作量,创建一个工具类用于创建数据库连接和关闭资源。

  1. 方法:

Connection getConntection(); //获得一个数据库连接

void close(Connection conn,Statement st, Result rs)//关闭资源

void close(Connection conn,Statement st) //关闭资源

  1. 代码如下
package com.zmysna.utils;

import java.sql.*;

public class JDBCUtils {
    private final static String DRIVER_NAME= "com.mysql.jdbc.Driver";
    private final static String URL = "jdbc:mysql://localhost:3306/day18";
    private final static String USER = "root";
    private final static String PASSWORD = "awsed2zx";

    static {
        try {
            Class.forName(DRIVER_NAME);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    /**
     * 获得连接
     * @return
     * @throws SQLException
     */
    public static Connection getConnection() throws SQLException {
        return DriverManager.getConnection(URL, USER, PASSWORD);
    }

    /**
     * 关闭Connection和Statement
     * @param connection
     * @param statement
     */
    public static void close(Connection connection, Statement statement) {
        close(connection, statement, null);
    }

    /**
     * 关闭Connection、Statement以及ResultSet
     * @param connection
     * @param statement
     * @param rs
     */
    public static void close(Connection connection, Statement statement, ResultSet rs){
        if(connection != null) {
            try {
                connection.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if(statement != null){
            try {
                statement.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if(rs != null){
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

4. SQL注入问题以及解决办法

4.1 登录案例
package com.zmysna.test;

import com.zmysna.utils.JDBCUtils;

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

public class Test02 {
    private static Connection connection = null;
    private static Statement statement = null;
    private static ResultSet rs = null;

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String name = scanner.nextLine();
        String pwd = scanner.nextLine();
        try {
            connection = JDBCUtils.getConnection();
            statement = connection.createStatement();
            prepareData(); //准备数据
            login(name,pwd); //登录
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.close(connection, statement, rs);

        }
        scanner.close();
    }

    /**
     * 用户登录功能(不能防止SQL注入)
     * @param name
     * @param pwd
     * @throws SQLException
     */
    private static void login(String name, String pwd) throws SQLException {
        String sql = "SELECT * FROM user WHERE `name` = '" + name + "' AND password = '" + pwd + "'";
        rs = statement.executeQuery(sql);
        if (rs.next()) {
            System.out.println("登录成功,"+name);
        }else{
            System.out.println("登录失败");
        }
    }

    /**
     * 准备数据
     * @throws SQLException
     */
    private static void prepareData() throws SQLException {
//       statement.execute("create table user(id int auto_increment primary key, name varchar(50), password varchar(50))");
//       System.out.println("成功创建用户表");
        int i = statement.executeUpdate("insert into user values(1,'admin',123)");
        System.out.println("成功插入" + i + "条记录");
    }
}

由于字符串的拼接问题,输入a'or'1'='1也能登录成功

4.2 Prep在这里插入图片描述aredStatement解决SQL注入

PreparedStatement是一个语句对象,它是Statement接口的子接口。功能比Statement语句对象功能更加强大。

a. PreparedStatement原理

在这里插入图片描述

b. 好处
  1. 有预编译的功能,在创建这个对象的时候就提供了SQL语句,预先编译好了。执行效率更高一些。

  2. 使用Statement有SQL注入的安全隐患,而使用子接口没有这个问题。安全性更高。

  3. 代码的可读性更好。

c. 主要方法
PreparedStatement中的方法方法说明
PreparedStatement prepareStatement(String sql)通过指定SQL语句创建预编译的语句对象,SQL语句中可能有占位符?
int executeUpdate()执行DML语句,返回影响的行数
ResultSet executeQuery()执行查询语句,返回一个结果集
void set 数据类型(int 参数1,参数2)用真实值替换占位符?
参数1:占位符的索引,从1开始
参数2:用于替换占位符的真实值

练习

package com.zmysna.jdbc;

import org.junit.Test;

import java.sql.*;

/**
 * 使用PreparedStatement
 */
public class Demo1Prepared {

    @Test
    public void testInsert() throws SQLException {
        //得到连接对象
        Connection connection = DriverManager.getConnection("jdbc:mysql:///day19", "root", "root");
        //编写SQL语句,未知内容使用占位符
        String sql = "insert into student values(null,?,?,?)";
        //获得PreparedStatement对象
        PreparedStatement ps = connection.prepareStatement(sql);
        //设置实际参数,替换占位符
        ps.setString(1,"孙悟空");
        ps.setBoolean(2,true);
        ps.setDate(3, Date.valueOf("2000-11-11"));  //将字符串转成日期类型
        //执行参数化SQL语句
        int i = ps.executeUpdate();
        System.out.println(i);
        //关闭资源
        ps.close();
        connection.close();
    }


    //将id为2的用户,姓名更新为"嫦娥",性别换成女
    @Test
    public void testUpdate() throws SQLException {
        //得到连接对象
        Connection connection = DriverManager.getConnection("jdbc:mysql:///day19", "root", "root");
        //编写SQL语句,未知内容使用占位符
        String sql = "update student set name=?, gender=? where id=?";
        //获得PreparedStatement对象
        PreparedStatement ps = connection.prepareStatement(sql);
        //设置实际参数,替换占位符
        ps.setString(1,"嫦娥");
        ps.setBoolean(2,false);
        ps.setInt(3,2);
        //执行参数化SQL语句
        int i = ps.executeUpdate();
        System.out.println(i);
        //关闭资源
        ps.close();
        connection.close();
    }

    //将id为4的学员删除
    @Test
    public void testDelete() throws SQLException {
        //得到连接对象
        Connection connection = DriverManager.getConnection("jdbc:mysql:///day19", "root", "root");
        //编写SQL语句,未知内容使用占位符
        String sql = "delete from student where id=?";
        //获得PreparedStatement对象
        PreparedStatement ps = connection.prepareStatement(sql);
        //设置实际参数,替换占位符
        ps.setInt(1,4);
        //执行参数化SQL语句
        int i = ps.executeUpdate();
        System.out.println(i);
        //关闭资源
        ps.close();
        connection.close();
    }
}
d. 改写登录案例
package com.zmysna.jdbc;

import com.itheima.utils.JdbcUtils;

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

/**
 * 改写登录程序
 */
public class Demo2Login {

    public static void main(String[] args) throws SQLException {
        //得到用户名和密码
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入用户名:");
        String name = scanner.nextLine();
        System.out.println("请输入密码:");
        String pwd = scanner.nextLine();
        //创建连接对象
        Connection conn = JdbcUtils.getConnection();

        //创建预编译语句对象,用户名和密码使用占位符
        PreparedStatement ps = conn.prepareStatement("select * from user where name=? and password=?");

        //替换占位符
        ps.setString(1,name);
        ps.setString(2,pwd);

        //执行查询操作
        ResultSet rs = ps.executeQuery();

        //如果结果集有记录表示登录成功
        if (rs.next()) {
            System.out.println("欢迎您,登录成功" + name);
        }
        else {
            //否则登录失败
            System.out.println("登录失败");
        }

        //关闭连接
        JdbcUtils.close(conn,ps,rs);
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值