目录

1、JDBC简介

2、JDBC应用

2.1 建立数据库连接

2.1.1 DriverManager静态方法获取连接

2.1.2 DataSource对象获取

2.2 获取SQL执行对象

2.2.1 SQL注入

2.2.2 Statement(执行静态SQL)

2.2.3 PreparedStatement(预处理的SQL执行对象)

2.3 执行SQL并返回结果

2.4 关闭连接,释放资源

3、示例


1、JDBC简介

JDBC(Java Data Base Connectivity,Java数据库连接)是Java程序和数据库之间的桥梁,包含 了⼀套Java定义的用于执行SQL语句的接口,使开发者能够编写数据库的程序。JDBC 的主要作用是: 与数据库建立连接、发送SQL语句和处理数据库执行结果。

正常来说,访问数据库需要经过以下几个重要步骤:

  1. 确定数据库服务器的地址,端口号(数据源)
  2. 建立连接,用户名、密码(不同的数据库以哪种协议建立连接)
  3. 发生要执行的SQL(以什么样的形式发送——需要考虑编码的格式(协议))
  4. 接收返回的结果(结果集(select)、受影响的行数(insert、...))(需要考虑一哪种协议解析结果)
  5. 关闭连接(释放资源,关闭连接)

JDBC是Java平台提供的接口,其中具体的实现是由不同的数据库厂商来完成的,数据库厂商实现完后将其封装在不同的方法中,Java开发者可以使用这些封装好的方法,操作数据库。

JDBC工作原理简洁地概括为:

  1. 加载驱动
  2. 建立连接
  3. 创建Statement(获取SQL执行对象)
  4. 执行SQL并返回结果
  5. 处理结果,关闭资源

2、JDBC应用

2.1 建立数据库连接

2.1.1 DriverManager静态方法获取连接

获取数据库连接的第一种方式:以驱动管理类DriverManager获取连接。

注意:该方式获取的是物理连接,即每次运行时都会重新打开一个客户端工具(随用随开)。

举个例子:比如公司中有了一个新业务,老板为完成这个业务招了十个员工,业务完成后立刻把他们炒了。过了一段时间,公司又有了一个新业务,老板又重新招人,完成业务又把他们开了。(随用随招)

因此,该方法效率低下,不推荐。

 //1. 加载数据库厂商提供的驱动
 //通过完全限定名记载指定的类到JVM
 Class.forName("com.mysql.cj.jdbc.Driver");
 //2. 获取数据库连接(物理连接)
 connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/test2?characterEncoding=utf8&" +
                    "allowPublicKeyRetrieval=true&useSSL=false", "root", "111111");

2.1.2 DataSource对象获取

通过数据源DataSource对象获取,一个连接可以执行很多SQL,直到关闭数据源。

这种方式是通过一个连接池去管理很多个连接,当需要SQL执行时,就从连接池里拿出一个连接,用完后返还给连接池。

推荐在实际开发中使用这种方式。

        //1. 定义MySQL数据源对象(连接池)
        MysqlDataSource mysqlDataSource = new MysqlDataSource();
        //2. 设置数据库连接串
        mysqlDataSource.setURL("jdbc:mysql://127.0.0.1:3306/test2?characterEncoding=utf8" +
                "&allowPublicKeyRetrieval=true&useSSL=false");
        //用户
        mysqlDataSource.setUser("root");
        //密码
        mysqlDataSource.setPassword("111111");

        //定义JDBC的数据源对象
        DataSource dataSource = mysqlDataSource;

        //1. 通过数据源获得数据库连接对象
        connection = dataSource.getConnection();

2.2 获取SQL执行对象

2.2.1 SQL注入

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

2.2.2 Statement(执行静态SQL)

Statement是用于执行静态SQL语句并返回执行结果的对象

注意:该方式存在SQL注入的安全问题!!!

如下图:该方式是通过字符串拼接的方式组装完成的SQL语句,字符串拼接形式构造SQL语句时,如果不处理参数中的特殊字符就会造成SQL注入,这是⼀个非常严重的安全性问题。

//定义Statement 
Statement statement = null;
//3. 创建Statement对象
statement = connection.createStatement();
//4. 定义SQL并执行SQL语句
Scanner scanner = new Scanner(System.in);
System.out.println("请输入要查询的学生的姓名:");
//接收用户输入
String name = scanner.next();
String sql = "select student_id, sn, name, mail, class_id from student where name = '" + name + "'";
//5. 执行SQL并获取查询结果
resultSet = statement.executeQuery(sql);

2.2.3 PreparedStatement(预处理的SQL执行对象)

预编译SQL语句对象,SQL语句被预编译并存储在PreparedStatement对象中,可以使用该对象多次执行SQL语句,同时可以解决SQL注入问题。

动态参数用占位符 ? 表示。

简单以上文SQL注入的输入为例,该方式直接将用户输入的内容全部当做name的值(利用占位符),直接在数据表中通过输入值来查找相应记录。

注意:使用真实值替换占位符时,使用setString/setLong/....方法,编号从1开始,有多少个参数就设置多少个值。

            //定义要执行的SQL
            String sql = "select student_id, sn, name, mail, class_id from student where name = ?";
            Scanner scanner = new Scanner(System.in);
            //2. 获取预处理SQL执行对象
            statement = connection.prepareStatement(sql);
            //接收用户输入
            System.out.println("请输入要查询的学生的姓名:");
            String name = scanner.next();
            //3. 用真实值替换占位符
            statement.setString(1, name);

2.3 执行SQL并返回结果

执行select语句,返回结果集(ResultSet结果集接收):

//定义结果集对象
ResultSet resultSet = null; 
//4. 执行SQL,获取结果集对象
resultSet = statement.executeQuery();
//迭代打印结果集
//最初游标位于第⼀⾏之前,调⽤next⽅法将游标移动到下⼀⾏,
//当ResultSet中没有更多的数据⾏时返回false
while (resultSet.next()) {
    long stuId = resultSet.getLong(1);
    String stuSn = resultSet.getString(2);
    String stuName = resultSet.getString(3);
    String stuMail = resultSet.getString(4);
    long stuClassId = resultSet.getLong(5);
    System.out.println(MessageFormat.format("学生编号={0}, 学号={1}, 姓名={2}, 邮箱={3}, 班级编号={4}",
            stuId, stuSn, stuName, stuMail, stuClassId));
}

执行update、delete、insert操作,返回所影响的行数:

int row = statement.executeUpdate();

2.4 关闭连接,释放资源

自下而上,依次关闭。

// 依次释放资源,关闭连接
            if (resultSet != null) {
                try {
                    resultSet.close();
                } catch (SQLException e) {
                    throw new RuntimeException(e);
                }
            }
            if (statement != null) {
                try {
                    statement.close();
                } catch (SQLException e) {
                    throw new RuntimeException(e);
                }
            }
            if (connection != null) {
                try {
                    connection.close();
                } catch (SQLException e) {
                    throw new RuntimeException(e);
                }
            }

3、示例

封装数据库连接、资源关闭方法:

package org.example.utils;

import com.mysql.cj.jdbc.MysqlDataSource;

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

/**
 * Created with IntelliJ IDEA.
 * Description:封装方法
 * User: dings
 * Date: 2024-09-21
 * Time: 14:53
 */
public class DBUtils {
    private static DataSource dataSource = null;
    private static MysqlDataSource mysqlDataSource = new MysqlDataSource();
    private static String URL = "jdbc:mysql://127.0.0.1:3306/test2?characterEncoding=utf8&allowPublicKeyRetrieval=true&useSSL=false";
    private static String USER = "root";
    private static String PASSWORD = "111111";


    private DBUtils() {}//构造方法私有化

    static {
        mysqlDataSource.setURL(URL);
        mysqlDataSource.setUser(USER);
        mysqlDataSource.setPassword(PASSWORD);
        dataSource = mysqlDataSource;
    }
    public static Connection getConnection() throws SQLException {
        return dataSource.getConnection();
    }
    public static void close(ResultSet resultSet, Statement statement, Connection connection) {
        if (resultSet != null) {
            try {
                resultSet.close();
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }
        if (statement != null) {
            try {
                statement.close();
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }
        if (connection != null) {
            try {
                connection.close();
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

实现记录的插入:

package org.example;

import org.example.utils.DBUtils;

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

/**
 * Created with IntelliJ IDEA.
 * Description:向表中插入记录
 * User: dings
 * Date: 2024-09-21
 * Time: 15:06
 */
public class Demo03_insert {
    public static void main(String[] args) {
        Connection connection = null;
        PreparedStatement statement = null;
        try {
            connection = DBUtils.getConnection();
            String sql = "insert into student (sn, name, mail, class_id) values (?,?,?,?)";
            statement = connection.prepareStatement(sql);
            Scanner scanner = new Scanner(System.in);

            System.out.println("请输入学号:");
            String sn = scanner.next();

            System.out.println("请输入姓名:");
            String name = scanner.next();

            System.out.println("请输入邮箱:");
            String mail = scanner.next();

            System.out.println("请输入班级编号:");
            Long classId = Long.valueOf(scanner.next());

            //编号从1开始
            statement.setString(1, sn);
            statement.setString(2, name);
            statement.setString(3, mail);
            statement.setLong(4, classId);

            int row = statement.executeUpdate();
            if(row == 1) {
                System.out.println("插入成功!");
            }else {
                System.out.println("插入失败!");
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            // 释放资源,关闭连接
            DBUtils.close(null, statement, connection);
        }
    }
}

END

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐