MySQL基础学习(四)————JDBC

本文详细介绍了JDBC的基本用法,包括连接数据库、SQL操作、工具类优化、数据库注入防范,以及PreparedStatement和批处理的实战应用,展示了不同操作的性能比较。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、JDBC是什么?

在这里插入图片描述
       Java语言可以作为一个客户端去连接一些常见的数据库产品,那么这个时候为了JAVA生态的发展,JAVA就指定了连接数据库的这么一套标准,这套标准就是JDBC。
       JDBC(Java Database Connection),具体来说,JDBC的具体体现是什么呢?其实就是JAVA定义了一套连接管理数据库的这么一套标准接口。
       对于开发者来说,假如我们切换了一下数据库,那么这个时候我们下面的代码就得去做大量的修改,这样对于Java语言的发展其实是很不利的。在这种情况下,Java就推出了一个去连接数据库的标准,这个标准就是JDBC。说白了,JDBC其实就是一套连接数据库的接口。

2、第一个JDBC

数据库访问过程:
客户端与Mysql服务器之间建立连接

客户端向Mysql服务器发送数据库请求

Mysql服务器处理客户端请求,并返回结果给客户端

客户端接受Mysql服务器的响应,并按照自己的业务逻辑做响应处理。

释放相关资源。
Java去连接数据库也是严格遵循这个数据库的访问过程的。

2.1 第一步:导包

我们需要导入MySQL的驱动包,我们导入了这个MySQL的驱动包以后,就能使用这个驱动包里面代码。具体的原理是我们自己写的Java程序在运行的时候,会去把MySQL驱动包里面的代码进行类加载,加载到我们的JVM内存里面去,然后我们就可以使用导包里面的代码了。

我们需要去maven仓库管理网站 去下载对应的Jar包。
在这里插入图片描述
下载完了以后,我们会得到一个.jar文件,我们可以把这个文件添加到我们项目的依赖里面去,如何添加呢?
在这里插入图片描述
右键对应的文件夹或者是文件,然后点击下面的add as library 即可。
在这里插入图片描述

2.2 第二步:编写代码

2.2.1 修改

// 这个方法其实就是去连接数据库,操作数据库

// 1. 加载驱动
DriverManager.registerDriver(new Driver());

// 2. 获取连接
Connection connection = DriverManager.getConnection(url, username, password);

// 3. 执行sql语句 connection只是一个连接对象,不能够直接执行sql语句,需要根据connection对象去
//    创建statement对象才能够去执行sql语句
// statement对象其实就是用来去自动封装JDBC请求的,并且把sql语句传给我们的MySQL服务器
Statement statement = connection.createStatement();

Integer affectedRows =  statement.executeUpdate("update clazz  set name = '小鲁班'");

// 4. 获取执行sql语句的结果
System.out.println("affectedRows:" + affectedRows);

// 5. 解析结果

// 6. 释放资源
statement.close();

connection.close();

2.2.2 查询

// 加载驱动
DriverManager.registerDriver(new Driver());

// 获取连接
Connection connection = DriverManager.getConnection(url, username, password);

// 执行sql语句
Statement statement = connection.createStatement();


// ResultSet对象其实就是获取到的结果集
ResultSet resultSet = statement.executeQuery("select * from student");
// 获取执行结果

// 解析结果集
resultSet.next();

String name = resultSet.getString("name");
int age = resultSet.getInt("age");

System.out.println("name:" + name + "\n age:" + age) ;


// 释放资源
resultSet.close();

statement.close();

connection.close();

2.2.3 解析结果集优化

在这里插入图片描述

 // 加载驱动
 DriverManager.registerDriver(new Driver());

 // 获取连接
 Connection connection = DriverManager.getConnection(url, username, password);

 // 执行sql语句
 Statement statement = connection.createStatement();


 // ResultSet对象其实就是获取到的结果集
 ResultSet resultSet = statement.executeQuery("select * from student");
 // 获取执行结果

 // 解析结果集
while (resultSet.next()) {

    int id = resultSet.getInt("id");
    String name = resultSet.getString("name");
    int age = resultSet.getInt("age");
    int clazzId = resultSet.getInt("clazz_id");

    System.out.println("id:" + id );
    System.out.println("name:" + name );
    System.out.println("age:" + age );
    System.out.println("clazzId:" + clazzId );

    System.out.println("-----------------------------");
}

 // 释放资源
 resultSet.close();

 statement.close();

 connection.close();

3、使用工具类优化代码

3.1 第一个简单版本

public class JDBCUtils {


    private static final String url = "jdbc:mysql://localhost:3306/31th_sql4?characterEncoding=utf8&useSSL=false";
    private static final String username = "root";
    private static final String password = "123456";

    // 获取连接
    public static Connection getConnection(){

        Connection connection = null;

        try {
            // 加载驱动
            DriverManager.registerDriver(new Driver());

            // 获取连接对象
            connection = DriverManager.getConnection(url, username, password);

        } catch (SQLException e) {
            e.printStackTrace();
        }

        return connection;
    }


    // 关闭资源
    public static void releaseSources(Connection connection, Statement statement, ResultSet resultSet){

        // 关闭ResultSet
        if (resultSet != null) {
            try {
                resultSet.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

        // 关闭statement
        if (statement != null) {
            try {
                statement.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        // 关闭connection
        if (connection != null) {
            try {
                connection.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }


    }
}

3.2 第二个版本

这个版本主要是把一些配置写到配置文件里面去,并且优化我们的驱动加载的代码。

public class JDBCUtils {


    private static  String url = null;
    private static  String username = null;
    private static  String password = null;
    private static  String driverClassName = null;

    static {

        try {
            // 获取文件输入流
            FileInputStream fileInputStream = new FileInputStream("jdbc.properties");

            Properties properties = new Properties();
            // 装载
            properties.load(fileInputStream);

            url = properties.getProperty("url");
            username = properties.getProperty("username");
            password = properties.getProperty("password");
            driverClassName = properties.getProperty("driverClassName");

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }


    }

    // 获取连接
    public static Connection getConnection(){



        Connection connection = null;

        try {
            // 加载驱动 com.mysql.cj.jdbc.Driver
            Class.forName(driverClassName);

            // 获取连接对象
            connection = DriverManager.getConnection(url, username, password);

        } catch (SQLException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

        return connection;
    }


    // 关闭资源
    public static void releaseSources(Connection connection, Statement statement, ResultSet resultSet){

        // 关闭ResultSet
        if (resultSet != null) {
            try {
                resultSet.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

        // 关闭statement
        if (statement != null) {
            try {
                statement.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        // 关闭connection
        if (connection != null) {
            try {
                connection.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

4、使用JDBC进行增删改查

public static void main(String[] args) throws SQLException {

        JDBCDemo jdbcDemo = new JDBCDemo();
        // insert
//        jdbcDemo.insert();

        // update
//        jdbcDemo.update();

        // delete
//        jdbcDemo.delete();

        // query
        jdbcDemo.query();

    }

    private void query() throws SQLException {

        Connection connection = JDBCUtils.getConnection();
        Statement statement = connection.createStatement();
        ResultSet resultSet = statement.executeQuery("select * from clazz");
        while (resultSet.next()) {
            int id = resultSet.getInt("id");
            String name = resultSet.getString("name");
            System.out.println("id:" + id + ", name :" + name);
        }
        JDBCUtils.releaseSources(connection,statement,resultSet);

    }

    private void delete() throws SQLException {
        Connection connection = JDBCUtils.getConnection();
        Statement statement = connection.createStatement();
        int affectedRows = statement.executeUpdate("delete from clazz where id = 3");
        System.out.println("affectedRows:" +affectedRows);

        JDBCUtils.releaseSources(connection,statement,null);

    }

    private void update() throws SQLException {
        Connection connection = JDBCUtils.getConnection();
        Statement statement = connection.createStatement();
        int affectedRows = statement.executeUpdate("update clazz set name = '王菲' where id = 3");
        System.out.println("affectedRows:" +affectedRows);

        JDBCUtils.releaseSources(connection,statement,null);

    }

    private  void insert() throws SQLException {

        // 获取连接
        Connection connection = JDBCUtils.getConnection();
        // 获取statement对象
        Statement statement = connection.createStatement();
        // 执行sql语句
        int affectedRows = statement.executeUpdate("insert into clazz values (3,'张飞')");
        // 输出
        System.out.println("affectedRows:" +affectedRows);
        // 关闭资源
        JDBCUtils.releaseSources(connection,statement,null);

    }

5、数据库注入问题

5.1 登录案例

public static void main(String[] args) throws SQLException {

    LoginDemo loginDemo = new LoginDemo();

    loginDemo.login("tom","bbb' or '1=1");
}


// 登录的方法
public Boolean login(String username, String password) throws SQLException {

    // 获取连接
    Connection connection = JDBCUtils.getConnection();

    // 获取statement对象
    Statement statement = connection.createStatement();

    // 执行sql语句
    String sql = "select * from user where username = '"+username+"' and password = '"+password+"'";
    System.out.println("sql:" + sql);
    ResultSet resultSet = statement.executeQuery(sql);

    if (resultSet.next()) {
        System.out.println("登录成功!");
        return true;
    }
    System.out.println("登录失败!");
    return false;
}

我们通过以上的案例可以知道,用户在登录的时候,输入了一些sql里面的关键字 ,导致了sql的结构发生了变化,从而使得用户登录的时候不需要正确的密码也可以登录,只要用户输入的内容会符合 bbb' or '1=1 这种格式,不管前面的bbb是什么内容,都可以登录成功,为了避免这种问题,我们就有了一个预编译的statement,就是prepareStatement

5.2 PrepareStatement

这个其实就是一个预编译的statement,是一个statement的子接口。

public static void main(String[] args) throws SQLException {

    Connection connection = JDBCUtils.getConnection();

    // 这一步其实就是预先对sql语句进行编译
    // ? 表示占位
    PreparedStatement preparedStatement = connection.prepareStatement("select * from user where username = ? and password = ?");

    // 设置参数
    preparedStatement.setString(1,"tom");
    preparedStatement.setString(2,"tom1234");
	
    // 执行sql
    ResultSet resultSet = preparedStatement.executeQuery();

    while (resultSet.next()) {

        int id = resultSet.getInt("id");
        String username = resultSet.getString("username");

        System.out.println("id:" + id + ", username:" + username);
    }

    JDBCUtils.releaseSources(connection,preparedStatement,resultSet);

}

5.3 登录案例改造

// 使用prepareStatement
public Boolean login4PrepareStatement(String username, String password) throws SQLException {

    // 获取连接
    Connection connection = JDBCUtils.getConnection();

    // 获取statement对象
    PreparedStatement preparedStatement = connection.prepareStatement("select * from user where username = ? and password = ?");

    // 设置参数
    preparedStatement.setString(1,username);
    preparedStatement.setString(2,password);

    // 执行sql语句
    ResultSet resultSet = preparedStatement.executeQuery();

    if (resultSet.next()) {
        System.out.println("登录成功!");
        return true;
    }
    System.out.println("登录失败!");
    return false;
}

6、批处理

开启JDBC的批处理需要在MySQL的链接后面添加一个参数:rewriteBatchedStatements=true

6.1 Statement批处理

在这里插入图片描述

public static void main(String[] args) throws SQLException {

    Connection connection = JDBCUtils.getConnection();

    Statement statement = connection.createStatement();


    // 添加sql语句到批处理小推车里面去
    statement.addBatch("insert into user values (null,'lisi','lisi')");
    statement.addBatch("insert into user values (null,'wangwu','wangwu')");
    statement.addBatch("insert into user values (null,'shiye','shiye')");
    statement.addBatch("insert into user values (null,'zhangmazi','zhangmazi')");

    // 执行sql语句
    int[] ints = statement.executeBatch();

    for (int anInt : ints) {
        System.out.println("affectedRows:" + anInt);
    }

    JDBCUtils.releaseSources(connection,statement,null);
}

主要的API:

// 添加sql语句到批处理
statement.addBatch(String sql);

// 执行批处理
statement.executeBatch();

6.2 PrepareStatement批处理

public static void main(String[] args) throws SQLException {


    Connection connection = JDBCUtils.getConnection();

    PreparedStatement preparedStatement = connection.prepareStatement("insert into user values (null,?,?)");

    // 批处理
    preparedStatement.setString(1,"sunwukong");
    preparedStatement.setString(2,"sunwukong");
    preparedStatement.addBatch();

    preparedStatement.setString(1,"bajie");
    preparedStatement.setString(2,"bajie");
    preparedStatement.addBatch();

    preparedStatement.setString(1,"jiabaoyu");
    preparedStatement.setString(2,"jiabaoyu");

    // 执行sql语句
    preparedStatement.addBatch();

    int[] ints = preparedStatement.executeBatch();

    for (int anInt : ints) {
        System.out.println("affectedRows:" + anInt);
    }

    JDBCUtils.releaseSources(connection,preparedStatement,null);
}

主要的API

// 添加参数到批处理
preparedStatement.addBatch();

// 执行批处理
preparedStatement.executeBatch();

6.3 对比

public static void main(String[] args) throws SQLException {

    long startTime = System.currentTimeMillis();


    // 不采用批处理
    normalInsert();
    long endTime1 = System.currentTimeMillis();


    // 使用statement批处理
    statementInsert();
    long endTime2 = System.currentTimeMillis();


    // 使用prepareStatement批处理
    prepareStatementInsert();

    long endTime3 = System.currentTimeMillis();


    System.out.println("普通耗时:"+(endTime1-startTime) + "毫秒");
    System.out.println("statement耗时:"+(endTime2-endTime1) + "毫秒");
    System.out.println("预编译耗时:"+(endTime3-endTime2) + "毫秒");

}

// 采用预编译的方式进行批处理
private static void prepareStatementInsert() throws SQLException {

    Connection connection = JDBCUtils.getConnection();

    PreparedStatement preparedStatement = connection.prepareStatement("insert into user values (null,?,?)");

    for (int i = 0; i < 10000; i++) {

        String username = "王五"+i+"号";
        String password = "wangwu"+i;

        preparedStatement.setString(1,username);
        preparedStatement.setString(2,password);
        preparedStatement.addBatch();
    }

    preparedStatement.executeBatch();

    preparedStatement.close();
    connection.close();

}
// 采用statement.addBatch()进行批处理
private static void statementInsert() throws SQLException {

    Connection connection = JDBCUtils.getConnection();

    Statement statement = connection.createStatement();

    for (int i = 0; i < 10000; i++) {

        String username = "李四"+i+"号";
        String password = "lisi"+i;

        String sql = "insert into user values (null,'"+username+"','"+password+"')";
        statement.addBatch(sql);
    }

    statement.executeBatch();

    statement.close();
    connection.close();

}


// 不采用批处理的方式进行插入
private static void normalInsert() throws SQLException {

    Connection connection = JDBCUtils.getConnection();

    for (int i = 0; i < 10000; i++) {
        Statement statement = connection.createStatement();
        String username = "张三"+i+"号";
        String password = "zhangsan:"+i;

        int affectedRows = statement.executeUpdate("insert into user values (null,'"+username+"','"+password+"')");
        System.out.println("affectedRows:" + affectedRows);

        statement.close();
    }
    connection.close();

}

结果:
没有添加配置:
在这里插入图片描述
添加配置以后:
在这里插入图片描述
总结一下:

​       我们的Statement进行批处理对比普通的循环执行效率上还是有一点提升的,但是提升不够大。prePareStatement的批处理方式对于效率的提升非常明显,是效率最高的一种批处理方式。为什么他的效率最高呢?

       因为PrepareStatement这种批处理方式只对SQL语句进行编译了一次,其他的两种方式都编译了多次,所以效率更高。

       但是也有弊端,也就是他支持的场景没有我们的statement那么灵活,它里面的sql语句的范式是不能更改的。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值