Skip to content

JDBC(Java Data Base Connectivity,java数据库连接),是一种用于执行SQL语句的Java API

JDBC是接口,而JDBC驱动才是接口的实现,没有驱动无法完成数据库连接!每个数据库厂商都有自己的驱动,用来连接自己公司的数据库

使用JDBC

可以直接jar包导入,也可以使用XML快速导入(Maven)

xml
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.37</version>
</dependency>

核心类

DriverManger(驱动管理器)

java
// 通过这个获取Connection连接
public static Connection getConnection() {
    // 注册驱动
    Class.forName("com.mysql.jdbc.Driver");
    // 三大属性
    String url = "jdbc:mysql://localhost:3306/数据库名";
    String name = "SQL用户名";
    String pass = "SQL密码";
    // 获取链接对象
    return DriverManager.getConnection(url, name, pass);
}

四大参数:数据库驱动 、数据库连接地址、用户名、密码

注册驱动原理

注册驱动:Class.forName("com.mysql.jdbc.Driver")

Class.forName("")这段代码是反射,会初始化里面的类,而 com.mysql.jdbc.Driver 类里面有以下内容

java
public class Driver extends NonRegisteringDriver implements java.sql.Driver {
	
    public Driver() throws SQLException {
		// Required for Class.forName().newInstance()
	}
    
	static {
		try {
			java.sql.DriverManager.registerDriver(new Driver());
		} catch (SQLException E) {
			throw new RuntimeException("Can't register driver!");
		}
	}
    
}

使用反射会初始化这个类里面的代码,这里面只有一个无参构造和一个静态代码块

所以使用 Class.forName("") 真正的目的就是初始化这个里面的静态代码块

也就是初始化 java.sql.DriverManager.registerDriver(new Driver()) 内容

Connection(连接对象)

java
// 通过 Connection 里面的 Statement 对数据库进行连接然后进行操作
Statement stmt = con.createStatement();

Statement / PreparedStatement(执行对象)

java
public void toStatement() {
    // 获取链接
    Connection con = ...;
    Statement statement = con.createStatement();
    // sql语句
    String sql = "SQL语句";
    // 执行sql语句并输出结果
    System.out.println("受影响的行数:" + statement.executeUpdate(sql));
    // 关闭连接
    statement.close();
    con.close();
}

上面这种方法不是很安全,容易被SQL注入,所以有了一个新的 Statement 方法:PreparedStatement

PreparedStatement有三个好处

  1. prepareStatement使用预编译sql,减少SQL编译次数,提高效率。
  2. 安全性更高,没有SQL注入的隐患。
  3. 提高了程序的可读性
java
public void toPreparedStatement(){
    // 获取链接
    Connection con = ...;
    //添加预编译
    PreparedStatement preparedStatement = con.prepareStatement("insert into user values (?,?)");
    // 添加预编译数据
    preparedStatement.setString(1, "李四");
    preparedStatement.setInt(2, 123456);
    // 执行sql
    System.out.println("受影响的行" + preparedStatement.executeUpdate());
    // 关闭连接
    preparedStatement.close();
    con.close();
}

可以在里面先进行SQL预编译,需要进行填写的数据可以使用 ? 来代替,下面则可以使用 .set··· 方法进行数据的填入,格式为 (int,object)int 是第几个问号(从1开始),后面则是要填入的数据

ResultSet(查询结果集对象)

查询结果集对象是在使用SQL进行查询数据的时候,数据返回时用于接收使用,有两个非常长用的方法

一个是 next() 方法,使“行光标”移动到下一行,并返回移动后的行是否存在

一个是 getString("字段名") 方法,获取相对应的结果的列

两个配合循环输出返回的值

java
// 接受到结果集
ResultSet resultSet = statement.executeQuery(sql);
// 解析并输出查询结果
while (resultSet.next()) {
    String name1 = resultSet.getString("name");
    String pass1 = resultSet.getString("pass");
    System.out.println(name1 + " - " + pass1);
}

四大参数

如果把四大参数都写在代码里面如果需要修改参数还要从新编译,解决办法就是书写一个配置文件(xml、properties...)

使用 properties 创建一个配置文件,创建一个名为 dbconfig.properties 的配置文件,然后里面写入以下内容

properties
# 数据库驱动
driverClassName=com.mysql.jdbc.Driver
# 数据库连接地址
url=jdbc:mysql://localhost:3306/数据库名
# 数据库账号
username=xxxx
# 数据库密码
password=xxxx

一般来说名称最好是上面的,一些连接池的默认名称就是上面的,所以可以免去一些更改操作

工具类(JdbcUtils)

上述操作的代码复用性很差,每次数据操作都需要重新走一遍流程,尤其是连接非常耗费时间,所以要提高数据的复用性

分析

  1. 该工具类作用,就是将通用代码封装,提升代码复用性
  2. 通用代码包含:读取配置文件、注册驱动、获取连接对象和释放资源
  3. 读取配置文件、注册驱动仅需要执行一次即可,所以可以放在 JdbcUtils 工具类静态代码块完成
  4. 将获取连接对象和释放资源定义成静态方法,方便调用

实操

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

public class JdbcUtils {
    private static String driverClassName;
    private static String url;
    private static String userName;
    private static String password;

    // 加载JDBC配置文件
    static {
        try {
            InputStream resourceAsStream = JdbcUtils.class.getResourceAsStream("dbconfig.properties");
            Properties properties = new Properties();
            properties.load(resourceAsStream);
            driverClassName = properties.getProperty("driverClassName");
            url = properties.getProperty("url");
            userName = properties.getProperty("userName");
            password = properties.getProperty("password");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    // 注册驱动
    static {
        try {
            Class.forName("driverClassName");
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        }
    }

    // 获取连接资源
    public static Connection getConnection() throws SQLException {
        return DriverManager.getConnection(url, userName, password);
    }

    // 释放资源
    public static void close(ResultSet resultSet, PreparedStatement preparedStatement, Connection connection) {
        if (resultSet != null)
            try {
                resultSet.close();
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        if (preparedStatement != null)
            try {
                preparedStatement.close();
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        if (connection != null)
            try {
                connection.close();
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
    }
	// 释放资源
    public static void close(ResultSet resultSet, Connection connection) {
        close(resultSet, null, connection);
    }
}