JDBC链接数据库

JDBC连接数据库的七步走:

jdbc链接数据库

* 1.加载驱动

* 2.获取链接(url 用户名 密码)

* 3.编写sql

* 4.获取执行sql的statement对象

        * 两个 stmt(sql注入(字符串拼接)) pstmt(预编译 防止sql注入 占位符)

* 5.执行 stmt并获取结果

* 6.遍历结果集

* 7.关闭资源(先开启的后关闭)

一、JDBC1.0版本

初版本只使用JDBC工具类完成数据库操作,即为单纯的java代码,不涉及非.java文件的内容。

1、示例场景

user表:

CREATE TABLE users (
    id INT(11) NOT NULL ,
    name VARCHAR(255),
    email VARCHAR(255),
    PRIMARY KEY (id)
);

演示数据:

INSERT INTO user (id, name, email) VALUES
(1, 'Alice', '[email protected]'),
(2, 'Bob', '[email protected]'),
(3, 'Charlie', '[email protected]'),
(4, 'David', '[email protected]'),
(5, 'Eva', '[email protected]'),
(6, 'Frank', '[email protected]'),
(7, 'Grace', '[email protected]'),
(8, 'Hannah', '[email protected]'),
(9, 'Irene', '[email protected]'),
(10, 'Jack', '[email protected]'),
(11, 'Katherine', '[email protected]'),
(12, 'Leo', '[email protected]'),
(13, 'Mona', '[email protected]'),
(14, 'Nina', '[email protected]'),
(15, 'Oscar', '[email protected]'),
(16, 'Paul', '[email protected]'),
(17, 'Quincy', '[email protected]'),
(18, 'Rita', '[email protected]'),
(19, 'Sam', '[email protected]'),
(20, 'Tina', '[email protected]'),
(21, 'Uma', '[email protected]'),
(22, 'Vera', '[email protected]'),
(23, 'Wendy', '[email protected]'),
(24, 'Xander', '[email protected]'),
(25, 'Yvonne', '[email protected]'),
(26, 'Zach', '[email protected]'),
(27, 'Alex', '[email protected]'),
(28, 'Bella', '[email protected]'),
(29, 'Carl', '[email protected]'),
(30, 'Diana', '[email protected]'),
(31, 'Eve', '[email protected]'),
(32, 'Fred', '[email protected]'),
(33, 'George', '[email protected]'),
(34, 'Holly', '[email protected]'),
(35, 'Ivy', '[email protected]'),
(36, 'Jackie', '[email protected]'),
(37, 'Kevin', '[email protected]'),
(38, 'Laura', '[email protected]'),
(39, 'Mike', '[email protected]'),
(40, 'Nate', '[email protected]'),
(41, 'Olivia', '[email protected]'),
(42, 'Peter', '[email protected]'),
(43, 'Quinn', '[email protected]'),
(44, 'Rachel', '[email protected]'),
(45, 'Sophie', '[email protected]'),
(46, 'Tom', '[email protected]'),
(47, 'Ursula', '[email protected]'),
(48, 'Victor', '[email protected]'),
(49, 'Walter', '[email protected]'),
(50, 'Xena', '[email protected]');

2、加载驱动

两种方式

//1.直接调用方法
DriverManager.registerDriver(new Driver());
//2. 反射加载
//Class.forName("com.mysql.jdbc.Driver");

3、获取链接

Connection conn = DriverManager.getConnection(数据库url,用户名,密码);

4、编写sql

String sql = "select * from t_user";

5、获取执行SQL的Statement对象

// 有能执行SQL语句的对象 Statement对象,能执行SQL语句,不能解决sql注入问题  
Statement stmt = conn.createStatement();
//Statement stmt = conn.prepareStatement()

6、执行Statement对象

// 执行SQL语句,数据封装到结果集中
ResultSet rs = stmt.executeQuery(sql);

7、遍历结果集

while(rs.next()){
    // 获取到数据就OK
    int id = rs.getInt("id");
    String username = rs.getString("name");
    String email = rs.getString("email");
    // 做打印
    System.out.println(id+"-"+username+"-"+password+"-"+email);
}

8、关闭资源

先开启的后关闭

rs.close();
stmt.close();
conn.close();

9、完整示例

package jdbcDemo.demo1;

import com.mysql.jdbc.Driver;

import java.sql.*;

public class JDBCTest1_1 {
    public static void main(String[] args) {
        try {
            //  1.加载驱动
            DriverManager.registerDriver(new Driver());
            // 2.创建链接
            Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbcdemo", "root", "00000");
            // 3.编写SQL语句
            String sql = "select * from user limit 10";
            // 4. 获取执行SQL的Statement对象
            Statement stmt = conn.createStatement();
            // 5. 执行sql并获得结果集
            ResultSet rs = stmt.executeQuery(sql);
            // 6.遍历结果集
            while (rs.next()) {
                // 获取到数据就OK
                int id = rs.getInt("id");
                String username = rs.getString("name");
                String email = rs.getString("email");
                // 做打印
                System.out.println(id + "-" + username +"-" + email);
            }
            rs.close();
            stmt.close();
            conn.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

为了避免资源泄露,一般使用try-catch-finally结构,在finally中关闭资源。

try{
    ...
}catch(SQLException e){
    e.printStackTrace();
}finally{
    rs.close();
    stmt.close();
    conn.close();
}

此时不能再在try块内创建资源对象

// 数据库连接
Connection conn = null;
// 能执行SQL语句的对象
Statement stmt = null;
// 查询数据,把数据封装到该结果集中,表格
ResultSet rs = null;
try{
    ...
}catch(SQLException e){
    e.printStackTrace();
}finally{
    rs.close();
    stmt.close();
    conn.close();
}

Java 7 后可以用 try-with-resources 简化资源释放。该方式自动关闭资源,不需要 finally 手动关闭

public static void main(String[] args) {
        // 加载驱动类(新版JDBC不需要这一步,如果使用的是mysql-connector-java 6.0+ 可以省略)
        try {
            DriverManager.registerDriver(new com.mysql.cj.jdbc.Driver());
        } catch (SQLException e) {
            e.printStackTrace();
            return; // 驱动加载失败直接退出
        }

        // try-with-resources 自动关闭资源
        try (
            Connection conn = DriverManager.getConnection("jdbc:mysql:///jdbcdemo", "root", "root");
            Statement stmt = conn.createStatement();
            ResultSet rs = stmt.executeQuery("SELECT * FROM t_user")
        ) {
            while (rs.next()) {
                int id = rs.getInt("id");
                String username = rs.getString("username");
                String password = rs.getString("password");
                String email = rs.getString("email");

                System.out.println(id + " - " + username + " - " + password + " - " + email);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

10、使用工具类

每操作一次数据库,都需要重复上述步骤。

如果操作的数据库不变,那么有这么几个步骤的编写是重复的

  1. 加载驱动
  2. 获取链接(url 用户名 密码)
  3. 关闭资源(先开启的后关闭)

重复的代码可以将其封装成不同的方法,使用的时候进行调用即可。

1.加载驱动

/**
 * 加载驱动
 */
public static void loadDriver(){
    try {
        // 加载驱动类
        DriverManager.registerDriver(new Driver());
        // Class.forName("com.mysql.jdbc.Driver");
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }
}

2.获取链接

/**
 * 加载完驱动,获取到连接,返回连接对象
 * @return
 */
public static Connection getConnection(){
    // 加载驱动
    loadDriver();
    // 获取到连接对象,返回
    Connection conn = null;
    try {
        // 获取到连接
        conn = DriverManager.getConnection(url,username,password);
    } catch (SQLException e) {
        e.printStackTrace();
    }
    return conn;
}

3.关闭资源

/**
 * 关闭资源
 * @param conn
 * @param stmt
 * @param rs
 */
public static void close(Connection conn, Statement stmt, ResultSet rs){
    if(rs != null){
        try {
            rs.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
    if(stmt != null){
        try {
            stmt.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
    if(conn != null){
        try {
            conn.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

/**
 * 关闭资源
 * @param conn
 * @param stmt
 */
public static void close(Connection conn, Statement stmt){
    if(stmt != null){
        try {
            stmt.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
    if(conn != null){
        try {
            conn.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

这里关闭资源需要重写两个

有ResultSet类型参数针对查询操作进行

没有ResultSet类型参数针对增删改操作进行

二、JDBC2.0版本

JDBC2.0版本使用properties文件对MySQL数据库表进行约束,每一个数据库可以对应一个properties文件进行IO操作来读取数据库的链接信息。

2.0版本和1.0版本的区别只发生在加载驱动类和创建链接的参数使用上。1.0版本中,驱动类的加载和链接数据库都是固定写死的,在2.0版本中,只需要读取对应数据库的配置信息即可。

2.0版本工具类

package jdbccc.utils;

import com.mysql.jdbc.Driver;

import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Properties;

public class JDBCUtils {
    private static final String driverManager;
    private static final String url;
    private static final String username;
    private static final String password;
    // 静态代码块  类一加载(调用这个类的时候)的时候就会执行
    static {
        /*
        * 加载db.properties 文件读取链接数据库的所有参数
        *
        * */
        // 加载属性文件
        Properties properties = new Properties();
        // 将文件的内容获取到流中
        InputStream resourceAsStream = JDBCUtils.class.getResourceAsStream("/db.properties");
        try {
            properties.load(resourceAsStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
        // 获取文件中的key-value值

        // 给常量赋值
        driverManager = properties.getProperty("driverclass");
        url = properties.getProperty("url");
        username=properties.getProperty("username");
        password=properties.getProperty("password");
    }
    /*
    * 加载驱动
    * Driver函数也可以直接写进static代码块中
    * */
    public static void Driver(){
        try {
            // 1.直接调用方法
            // DriverManager.registerDriver(new Driver());
            // 2. 反射加载
            // Class.forName("com.mysql.jdbc.Driver");
             Class.forName(driverManager);
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    /*
    * 获取链接
    * */
    public static Connection getConnection(){
        Connection connection = null;
        try{
            Driver();
            connection = DriverManager.getConnection(url,username,password);
        }catch (Exception e ){
            e.printStackTrace();
        }
        return connection;
    }
    /*
    * 关闭资源
    * 有结果集的情况——查
    * */
    public static void close(Connection connection, ResultSet resultSet, Statement statement){
        try{
            statement.close();
            resultSet.close();
            connection.close();
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    /*
    * 关闭资源
    * 有结果集的情况——增删改
    * */
    public static void close(Connection connection, Statement statement){
        try{
            statement.close();
            connection.close();
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

配置文件格式

driverclass=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/jdbcdemo
username=root
password=00000

测试用例:

package com.goose;

import com.goose.utils.JDBCUtils;

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

/**
 * @Author: Insight
 * @Description: TODO
 * @Date: 2025/5/10 17:13
 * @Version: 1.0
 */

public class JDBCTest2_2 {
    public static void main(String[] args) {
        Connection conn = JDBCUtils.getConnection();
        String sql = "select * from user limit 10";
        try {
            Statement statement = conn.createStatement();
            ResultSet rs = statement.executeQuery(sql);
            while (rs.next()) {
                int id = rs.getInt("id");
                String name = rs.getString("name");
                String email = rs.getString("email");
                System.out.println(id + "-" + name + "-" + email);
            }
            JDBCUtils.close(conn,rs,statement);
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

如果不使用工具类,每次需要执行SQL时,都需要读取一遍db.properties文件。使用工具类的话,只需要加载一次即可。

不使用工具类的示例:

package com.goose;

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

/**
 * @Author: Insight
 * @Description: TODO
 * @Date: 2025/5/10 17:01
 * @Version: 1.0
 */

public class JDBCTest2_1 {
    public static void main(String[] args) {
        Properties properties = new Properties();
        InputStream inputStream = JDBCTest2_1.class.getResourceAsStream("/db.properties");
        try {
            properties.load(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
        String url = properties.getProperty("url");
        String driverclass = properties.getProperty("driverclass");
        String username = properties.getProperty("username");
        String password = properties.getProperty("password");
        Connection conn = null;
        Statement stmt = null;
        ResultSet rs = null;
        try {
            // 1.加载驱动
            Class.forName(driverclass);
            conn = DriverManager.getConnection(url, username, password);
            stmt = conn.createStatement();
            String sql = "select * from user limit 10";
            rs = stmt.executeQuery(sql);
            while (rs.next()) {
                int id = rs.getInt("id");
                String name = rs.getString("name");
                String email = rs.getString("email");
                System.out.println(id + "-" + name + "-" + email);
            }
            rs.close();
            stmt.close();
            conn.close();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

三、JDBC3.0

再次升级的JDBC使用了数据库连接池。

数据库连接池是一个用于管理数据库连接的容器,主要作用为:复用数据库连接,提高性能,避免频繁创建和销毁连接带来的开销。

可以简单理解为:一个连接的缓存池,事先创建好一些连接放到池子里面,程序需要时就“借”,用完后“还”,而且不是每次都重新创建数据库连接。

举个例子理解一下:

在公司门口最开始投放了 50 辆共享单车,供公司里面 50 个人上下班使用。大家下班从门口骑车回家,第二天上班再把车停回公司门口。这样大家就不需要每个人都花钱买一辆车了,既省钱又环保。

这就好比我们程序一开始设置了一个数据库连接池,里面准备好了 50 个数据库连接,程序中每个请求来了,就去借一个连接,用完还回去,不用每次都“买”一个新连接(即新建连接对象),这样大大提高了效率。

时间久了,公司里的一些员工发现骑车太累,或者住得近,干脆选择走路上下班,于是 50 辆车每天并不会都用完,会有几辆闲着。这也就相当于连接池中,并不是每次都需要用到所有连接,有些连接会空闲着等待下一次请求。

后来公司发展迅速,新来了不少员工,这时候原来的 50 辆车开始不够用了。于是,公司决定增加车的上限,最多可以投放到 80 辆(对应连接池的 maxActive=80)。但公司不是一口气就扔出 80 辆车,而是按需增加,只有在不够用的时候,才会临时增加几辆备用车。

但公司也不是傻,车太多没人骑也是浪费资源,占地方还要维护。于是他们设置了一个策略:如果闲置的车超过 30 辆(maxIdle=30),就会主动把一部分拉走回收;如果发现空闲车太少了,比如只剩 5 辆了(低于 minIdle=10),就再提前安排几辆送过来。

而员工们使用单车也很讲规矩,用完要停回原位(就像我们使用完连接后要 close(),实际是归还给连接池,而不是真正销毁)。不守规矩的员工,用完不归还,或者直接骑回家放几天,那就是连接泄漏了 —— 连接被借走后没还回来,连接池迟早就会被“借空”,后来的同事一个连接也借不到,只能干瞪眼。

为了避免这种事,公司还装上了智能监控系统(比如 Druid 的 web 管控台),可以随时查看有多少人在用车、多少车闲着、有没有车丢了、使用情况是不是正常。

直接使用连接池

package com.goose;

import com.alibaba.druid.pool.DruidDataSource;

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

/**
 * @Author: Goose
 * @Description: TODO
 * @Date: 2025/5/10 16:42
 * @Version: 1.0
 */

public class JDBCTest3_1 {
    /*
     * 直接使用连接池
     * */
    public static void main(String[] args) {
        DruidDataSource dataSource = new DruidDataSource();
        // 设置加载类
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        // 设置url
        dataSource.setUrl("jdbc:mysql://localhost:3306/jdbcdemo");
        // 设置用户
        dataSource.setUsername("root");
        // 设置密码
        dataSource.setPassword("00000");
        // 设置最大连接数
        dataSource.setMaxActive(10);
        // 设置初始链接数
        dataSource.setInitialSize(5);
        // 设置最大等待时间
        dataSource.setMaxWait(3000);
        // 设置最大空闲连接数
        dataSource.setMinIdle(6);
        // 设置最小最小空闲连接数
        dataSource.setMinIdle(3);

        Connection conn = null;
        Statement stmt = null;
        ResultSet rs = null;
        try {
            // 创建链接
            conn = dataSource.getConnection();
            // 定义SQL
            String sql = "select * from user limit 10";
            // 创建Statement对象
            stmt = conn.createStatement();
            // 执行SQL,并保存结果
            rs = stmt.executeQuery(sql);
            while (rs.next()) {
                // 获取到数据就OK
                int id = rs.getInt("id");
                String username = rs.getString("name");
                String email = rs.getString("email");
                // 做打印
                System.out.println(id + "-" + username + "-" + email);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 释放资源,可以使用try-catch 块,也可以直接throws异常交给上一级处理,这里最好使用try-catch
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

使用工具类完成

工具类:

package com.goose.utils;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidDataSourceFactory;

import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.sql.*;
import java.util.Properties;
import java.util.logging.Logger;

/**
 * @Author: Goose
 * @Description: TODO
 * @Date: 2025/5/10 16:17
 * @Version: 1.0
 */
/*
* 连接池工具类
* */
public class JDBCUtils3 {
    private static DataSource dataSource ;

    static{
        Properties properties = new Properties();
        InputStream inputStream = JDBCUtils3.class.getResourceAsStream("/druid.properties");
        try {
            properties.load(inputStream);
            dataSource= DruidDataSourceFactory.createDataSource(properties);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /*
    * 创建链接
    * */
    public static Connection getConnection(){
        Connection conn = null;
        try {
            conn = dataSource.getConnection();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return conn;
    }

    /*
    * 关闭连接——查询
    * */
    public static void closeConnection(ResultSet rs, Statement stmt,Connection conn){
        try {
            rs.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        try {
            stmt.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        try {
            conn.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
    /*
    * 关闭连接——增删改
    * */
    public static void closeConnection(Statement stmt,Connection conn){
        try {
            stmt.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        try {
            conn.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

配置文件:

driverclass=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/jdbcdemo
username=root
password=00000
initialSize=5
maxActive=10
maxWait=3000
maxIdle=6
minIdle=3

测试示例:

package com.goose;

import com.goose.utils.JDBCUtils;
import com.goose.utils.JDBCUtils3;

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

/**
 * @Author: Goose
 * @Description: TODO
 * @Date: 2025/5/10 17:37
 * @Version: 1.0
 */

public class JDBCTest3_2 {
    public static void main(String[] args) {

        try {
            // 创建链接
            Connection conn = JDBCUtils3.getConnection();
            // 创建执行sql 的Statement对象
            Statement stmt = conn.createStatement();
            // 执行sql并获取数据
            String sql = "INSERT INTO user (id, name, email) VALUES\n" +
                    "(55, 'Alice', '[email protected]')";
            int i = stmt.executeUpdate(sql);
            System.out.println(i);
            JDBCUtils3.closeConnection(stmt,conn);
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

你可能感兴趣的:(数据库,oracle,java)