第二十五章 JDBC 和数据库连接池

news2024/9/24 15:19:21

一、JDBC 概述(P821)

1. 基本介绍

(1)JDBC 为访问不同的数据库提供了统一的接口,为使用者屏蔽了细节问题。
(2)Java 程序员使用 JDBC,可以连接任何提供了 JDBC 驱动程序的数据库系统,从完成对数据库的各种操作。

2. 模拟 JDBC

public interface JdbcInterface {

    //连接
    public Object getConnection() ;
    //crud
    public void crud();
    //关闭连接
    public void close();
}
public class MysqlJdbcImpl implements JdbcInterface {
    @Override
    public Object getConnection() {
        System.out.println("得到 mysql 的连接");
        return null;
    }

    @Override
    public void crud() {
        System.out.println("完成 mysql 增删改查");
    }

    @Override
    public void close() {
        System.out.println("关闭 mysql 的连接");
    }
}
public class OracleJdbcImpl implements JdbcInterface {
    @Override
    public Object getConnection() {
        System.out.println("得到 oracle 的连接 升级");
        return null;
    }

    @Override
    public void crud() {
        System.out.println("完成 对 oracle 的增删改查");
    }

    @Override
    public void close() {
        System.out.println("关闭 oracle 的连接");
    }
}
public class TestJDBC {
    public static void main(String[] args) throws Exception {
        //完成对 mysql 的操作
        JdbcInterface jdbcInterface = new MysqlJdbcImpl();
        jdbcInterface.getConnection(); //通过接口来调用实现类[动态绑定]
        jdbcInterface.crud();
        jdbcInterface.close();
        //完成对 oracle 的操作
        System.out.println("==============================");
        jdbcInterface = new OracleJdbcImpl();
        jdbcInterface.getConnection(); //通过接口来调用实现类[动态绑定]
        jdbcInterface.crud();
        jdbcInterface.close();
    }
}

说明:JDBC 是 Java 提供一套用于数据库操作的接口 API,Java 程序员只需要面向这套接口编程即可。不同的数据库厂商,需要针对这套接口,提供不同实现。

3. JDBC API

JDBC API 是一系列的接口,它统一和规范了应用程序与数据库的连接、执行 SQL 语句,并到得到返回结果等各类操作,相关类和接口在 【java.sql】与【javax.sql】 包中

二、JDBC 快速入门

1. JDBC程序编写步骤

(1)注册驱动 - 加载 Driver 类
(2)获取连接-得到Connection
(3)执行增删改查 - 发送 SQL 给 mysql 执行
(4)释放资源-关闭相关连接

2. JDBC 第一个程序

import com.mysql.jdbc.Driver;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;

public class Jdbc01 {
    public static void main(String[] args) throws Exception {
        //前置工作: 在项目下创建一个文件夹比如 libs
        // 将 mysql.jar 拷贝到该目录下,点击 add to project ..加入到项目中
        //1. 注册驱动
        Driver driver = new Driver(); //创建 driver 对象
        //2. 得到连接
        //(1) jdbc:mysql:// 规定好表示协议,通过 jdbc 的方式连接 mysql
        //(2) localhost 主机,可以是 ip 地址
        //(3) 3306 表示 mysql 监听的端口
        //(4) hsp_db02 连接到 mysql dbms 的哪个数据库
        //(5) mysql 的连接本质就是前面学过的 socket 连接
        String url = "jdbc:mysql://localhost:3306/hsp_db02";

        //将 用户名和密码放入到 Properties 对象
        Properties properties = new Properties();
        //说明 user 和 password 是规定好,后面的值根据实际情况写
        properties.setProperty("user", "root");// 用户
        properties.setProperty("password", "hsp"); //密码

        Connection connect = driver.connect(url, properties);

        //3. 执行 sql
        //String sql = "insert into actor values(null, '刘德华', '男', '1970-11-11', '110')";
        //String sql = "update actor set name='周星驰' where id = 1";
        String sql = "delete from actor where id = 1";
        //statement 用于执行静态 SQL 语句并返回其生成的结果的对象
        Statement statement = connect.createStatement();

        int rows = statement.executeUpdate(sql); // 如果是 dml 语句,返回的就是影响行数
        System.out.println(rows > 0 ? "成功" : "失败");
        //4. 关闭连接资源
        statement.close();
        connect.close();
    }
}

三、获取数据库连接 5 种方式

1. 方式1 获取 Driver 实现类对象

public class Demo {

    public static void main(String[] args) throws Exception {
        Driver driver = new Driver();
        String url = "jdbc:mysql://localhost:3306/hsp_db02";

        Properties properties = new Properties();
        properties.setProperty("user", "root");// 用户
        properties.setProperty("password", "hsp"); //密码
        Connection connect = driver.connect(url, properties);       
    }
}

2. 方式2 反射加载 Driver 类

public class JdbcConn {

    @Test
    public void connect02() throws Exception {
        //使用反射加载 Driver 类 , 动态加载,更加的灵活,减少依赖性
        Class<?> aClass = Class.forName("com.mysql.jdbc.Driver");
        Driver driver = (Driver) aClass.newInstance();
        String url = "jdbc:mysql://localhost:3306/hsp_db02";
        //将 用户名和密码放入到 Properties 对象
        Properties properties = new Properties();
        //说明 user 和 password 是规定好,后面的值根据实际情况写
        properties.setProperty("user", "root");// 用户
        properties.setProperty("password", "hsp"); //密码
        Connection connect = driver.connect(url, properties);
        System.out.println("方式 2=" + connect);
    }
}

3. 方式3 使用 DriverManager 替代 driver

public class JdbcConn {
    
    //方式 3 使用 DriverManager 替代 driver 进行统一管理
    @Test
    public void connect03() throws Exception {
        //使用反射加载 Driver
        Class<?> aClass = Class.forName("com.mysql.jdbc.Driver");
        Driver driver = (Driver) aClass.newInstance();
        //创建 url 和 user 和 password
        String url = "jdbc:mysql://localhost:3306/hsp_db02";
        String user = "root";

        String password = "hsp";
        DriverManager.registerDriver(driver);//注册 Driver 驱动
        Connection connection = DriverManager.getConnection(url, user, password);
        System.out.println("第三种方式=" + connection);
    }
}

4. 方式4 使用 Class.forName 自动完成注册驱动(推荐使用)

public class JdbcConn {

    //方式 4: 使用 Class.forName 自动完成注册驱动,简化代码
    //这种方式获取连接是使用的最多,推荐使用
    @Test
    public void connect04() throws Exception {
        //使用反射加载了 Driver 类
        //在加载 Driver 类时,完成注册
        /*
        源码:
            1. 静态代码块,在类加载时,会执行一次.
            2. DriverManager.registerDriver(new Driver());
            3. 因此注册 driver 的工作已经完成
        static {
            try {
                DriverManager.registerDriver(new Driver());
            } catch (SQLException var1) {
                throw new RuntimeException("Can't register driver!");
            }
        }
        */
        Class.forName("com.mysql.jdbc.Driver");
        //创建 url 和 user 和 password
        String url = "jdbc:mysql://localhost:3306/hsp_db02";
        String user = "root";
        String password = "hsp";
        Connection connection = DriverManager.getConnection(url, user, password);
        System.out.println("第 4 种方式~ " + connection);
    }
}

5. 方式5 增加配置文件

public class JdbcConn {

    //方式 5 , 在方式 4 的基础上改进,增加配置文件,让连接 mysql 更加灵活
    @Test
    public void connect05() throws Exception {
        //通过 Properties 对象获取配置文件的信息
        Properties properties = new Properties();
        properties.load(new FileInputStream("src\\mysql.properties"));
        //获取相关的值
        String user = properties.getProperty("user");
        String password = properties.getProperty("password");
        String driver = properties.getProperty("driver");
        String url = properties.getProperty("url");
        Class.forName(driver);//建议写上
        Connection connection = DriverManager.getConnection(url, user, password);
        System.out.println("方式 5 " + connection);
    }
}

四、ResultSet(结果集)

1. 基本介绍

(1)表示数据库结果集的数据表,通常通过执行查询数据库的语句生成。
(2)ResultSet 对象保持一个光标指向其当前的数据行。最初,光标位于第一行之前。
(3)next 方法将光标移动到下一行,并且由于在 ResultSet 对象中没有更多行时返回 false,因此可以在 while 循环中使用循环来遍历结果集。

2. 应用实例

演示 select 语句返回 ResultSet ,并取出结果。

public class ResultSet_ {
    public static void main(String[] args) throws Exception {
        //通过 Properties 对象获取配置文件的信息
        Properties properties = new Properties();
        properties.load(new FileInputStream("src\\mysql.properties"));
        //获取相关的值
        String user = properties.getProperty("user");
        String password = properties.getProperty("password");
        String driver = properties.getProperty("driver");
        String url = properties.getProperty("url");
        //1. 注册驱动
        Class.forName(driver);//建议写上
        //2. 得到连接
        Connection connection = DriverManager.getConnection(url, user, password);

        //3. 得到 Statement
        Statement statement = connection.createStatement();
        //4. 组织 SqL
        String sql = "select id, name , sex, borndate from actor";
        //执行给定的 SQL 语句,该语句返回单个 ResultSet 对象
        /*
        +----+-----------+-----+---------------------+
        | id | name | sex | borndate |
        +----+-----------+-----+---------------------+
        | 4 | 刘德华 | 男 | 1970-12-12 00:00:00 |
        | 5 | jack | 男 | 1990-11-11 00:00:00 |
        +----+-----------+-----+---------------------+
        */
        /*
        老韩阅读 debug 代码 resultSet 对象的结构
        */
        ResultSet resultSet = statement.executeQuery(sql);
        //5. 使用 while 取出数据
        while (resultSet.next()) { // 让光标向后移动,如果没有更多行,则返回 false
            int id = resultSet.getInt(1); //获取该行的第 1 列
            //int id1 = resultSet.getInt("id"); 通过列名来获取值, 推荐
            String name = resultSet.getString(2);//获取该行的第 2 列
            String sex = resultSet.getString(3);
            Date date = resultSet.getDate(4);
            System.out.println(id + "\t" + name + "\t" + sex + "\t" + date);
        }
        //6. 关闭连接
        resultSet.close();
        statement.close();
        connection.close();
    }

}

五、Statement

1. 基本介绍

(1)Statement 对象,用于执行静态 SQL 语句并返回其生成的结果的对象。
(2)在连接建立后,需要对数据库进行访问,执行命名或是 SQL 语句,可以通过
1️⃣Statement【存在 SQL 注入】
2️⃣PreparedStatement【预处理】
3️⃣CallableStatement【存储过程】
(3)Statement 对象执行 SQL 语句,存在 SQL 注入风险。
(4)SQL注入 是利用某些系统没有对用户输入的数据进行充分的检查,而在用户输入数据中注入非法的SQL 语句段或命令,恶意攻击数据库。
(5)要防范 SQL 注入,只要用 PreparedStatement(从 Statement 扩展而来)取
代 Statement 就可以了。

2. 应用实例

public class ResultSet_ {
    public static void main(String[] args) throws Exception {
        //让用户输入管理员名和密码(万能用户名和密码)
        System.out.print("请输入管理员的名字: ");
        String admin_name = "1\' or";
        System.out.print("请输入管理员的密码: ");
        String admin_pwd = "\'1\'=\'1 ";

        //通过 Properties 对象获取配置文件的信息
        Properties properties = new Properties();
        properties.load(new FileInputStream("src\\mysql.properties"));
//获取相关的值
        String user = properties.getProperty("user");
        String password = properties.getProperty("password");
        String driver = properties.getProperty("driver");
        String url = properties.getProperty("url");

        //1. 注册驱动
        Class.forName(driver);
        //2. 得到连接
        Connection connection = DriverManager.getConnection(url, user, password);
        //3. 得到 Statement
        Statement statement = connection.createStatement();
        //4. 组织 SqL
        String sql = "select name , pwd from admin where "
                + "name ='" + admin_name
                + "' and pwd = '" + admin_pwd + "'";
        ResultSet resultSet = statement.executeQuery(sql);
        if (resultSet.next()) { //如果查询到一条记录,则说明该管理存在
            System.out.println("恭喜, 登录成功");
        } else {
            System.out.println("对不起,登录失败");
        }
        //关闭连接
        resultSet.close();
        statement.close();
        connection.close();
    }
}

六、PreparedStatement

1. 基本介绍

(1)PreparedStatement 执行的 SQL 语句中的参数用问号(?)来表示,调用
Preparedstatement 对象的 setXxx()方法来设置这些参数。setXxx()方法有
两个参数,第一个参数是要设置的 SQL 语句中的参数的索引(从1开始),第二
个是设置的 SQL 语句中的参数的值。
(2)调用 executeQuery(),返回 ResultSet 对象。
(3)调用 executeUpdate(),执行更新,包括增、删、修改。

2. 预处理好处

(1)不再使用 + 拼接 sql 语句,减少语法错误。
(2)有效的解决了 sql 注入问题!
(3)大大减少了编译次数,效率较高。

3. 应用实例

public class PreparedStatement_ {
    public static void main(String[] args) throws Exception {

        Scanner scanner = new Scanner(System.in);
        //让用户输入管理员名和密码
        System.out.print("请输入管理员的名字: "); //next(): 当接收到 空格或者 '就是表示结束
        String admin_name = scanner.nextLine(); // 老师说明,如果希望看到 SQL 注入,这里需要用 nextLine
        System.out.print("请输入管理员的密码: ");
        String admin_pwd = scanner.nextLine();

        //通过 Properties 对象获取配置文件的信息
        Properties properties = new Properties();
        properties.load(new FileInputStream("src\\mysql.properties"));
        //获取相关的值
        String user = properties.getProperty("user");
        String password = properties.getProperty("password");
        String driver = properties.getProperty("driver");
        String url = properties.getProperty("url");
        //1. 注册驱动
        Class.forName(driver);//建议写上
        //2. 得到连接
        Connection connection = DriverManager.getConnection(url, user, password);

        //3. 得到 PreparedStatement
        //3.1 组织 SqL , Sql 语句的 ? 就相当于占位符
        String sql = "select name , pwd from admin where name =? and pwd = ?";
        //3.2 preparedStatement 对象实现了 PreparedStatement 接口的实现类的对象
        PreparedStatement preparedStatement = connection.prepareStatement(sql);
        //3.3 给 ? 赋值
        preparedStatement.setString(1, admin_name);
        preparedStatement.setString(2, admin_pwd);
        //4. 执行 select 语句使用 executeQuery
        // 如果执行的是 dml(update, insert ,delete) executeUpdate()
        // 这里执行 executeQuery ,不要在写 sql
        ResultSet resultSet = preparedStatement.executeQuery(sql);
        if (resultSet.next()) { //如果查询到一条记录,则说明该管理存在
            System.out.println("恭喜, 登录成功");
        } else {
            System.out.println("对不起,登录失败");
        }
        //关闭连接
        resultSet.close();
        preparedStatement.close();
        connection.close();
    }
}

七、封装 JDBCUtils

1. 说明

在 jdbc 操作中,获取连接和释放资源是经常使用到,可以将其封装 JDBC 连接的工具类 JDBCUtils。

2. 代码实现

public class JDBCUtils {

    //定义相关的属性(4 个), 因为只需要一份,因此,我们做出 static
    private static String user; //用户名
    private static String password; //密码
    private static String url; //url
    private static String driver; //驱动名

    //在 static 代码块去初始化
    static {
        try {
            Properties properties = new Properties();
            properties.load(new FileInputStream("src\\mysql.properties"));
            //读取相关的属性值
            user = properties.getProperty("user");
            password = properties.getProperty("password");
            url = properties.getProperty("url");
            driver = properties.getProperty("driver");
        } catch (IOException e) {
            //在实际开发中,我们可以这样处理
            //1. 将编译异常转成 运行异常
            //2. 调用者,可以选择捕获该异常,也可以选择默认处理该异常,比较方便. 
            throw new RuntimeException(e);
        }
    }

    //连接数据库, 返回 Connection
    public static Connection getConnection() {
        try {
            return DriverManager.getConnection(url, user, password);
        } catch (SQLException e) {
            //1. 将编译异常转成 运行异常
            //2. 调用者,可以选择捕获该异常,也可以选择默认处理该异常,比较方便. 
            throw new RuntimeException(e);
        }
    }

    //关闭相关资源
    /*
    1. ResultSet 结果集
    2. Statement 或者 PreparedStatement
    3. Connection
    4. 如果需要关闭资源,就传入对象,否则传入 null
    */
    public static void close(ResultSet set, Statement statement, Connection connection) {
        //判断是否为 null
        try {
            if (set != null) {
                set.close();
            }
            if (statement != null) {
                statement.close();
            }
            if (connection != null) {
                connection.close();
            }
        } catch (SQLException e) {
            //将编译异常转成运行异常抛出
            throw new RuntimeException(e);
        }
    }
}

八、事务

1. 基本介绍

(1)JDBC 程序中当一个 Connection 对象创建时,默认情况下是自动提交事务:每次执行一个 SQL 语句时,如果执行成功,就会向数据库自动提交,而不能回滚。
(2)JDBC 程序中为了让多个 SQL 语句作为一个整体执行,需要 使用事务
(3)调用 Connection 的 setAutoCommit(false)可以取消自动提交事务。
(4)在所有的 SQL 语句都成功执行后,调用 Connection 的 commit()方法提交事务。
(5)在其中某个操作失败或出现异常时,调用 Connection 的 rollback()方法回滚事务。

2. 代码实现

public class Transaction_ {

    //事务来解决
    @Test
    public void useTransaction() {
        //操作转账的业务
        //1. 得到连接
        Connection connection = null;
        //2. 组织一个 sql
        String sql = "update account set balance = balance - 100 where id = 1";
        String sql2 = "update account set balance = balance + 100 where id = 2";
        PreparedStatement preparedStatement = null;
        //3. 创建 PreparedStatement 对象
        try {
            connection = JDBCUtils.getConnection(); // 在默认情况下,connection 是默认自动提交
            
            //将 connection 设置为不自动提交
            connection.setAutoCommit(false); //开启了事务
            
            preparedStatement = connection.prepareStatement(sql);
            preparedStatement.executeUpdate(); // 执行第 1 条 sql
            int i = 1 / 0; //抛出异常
            preparedStatement = connection.prepareStatement(sql2);
            preparedStatement.executeUpdate(); // 执行第 3 条 sql
            //这里提交事务
            connection.commit();
        } catch (SQLException e) {
            //这里我们可以进行回滚,即撤销执行的 SQL
            //默认回滚到事务开始的状态. System.out.println("执行发生了异常,撤销执行的 sql");
            try {
                connection.rollback();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
            e.printStackTrace();
        } finally {
            //关闭资源
            JDBCUtils.close(null, preparedStatement, connection);
        }
    }
}

九、批处理

1. 基本介绍

(1)当需要感批插入或者更新记录时。可以采用 Java 的批量更新机制,这一机制允许多条语句一次性提交给数据库批量处理。通常情况下比单独提交处理更有效率。
(2)JDBC 的批量处理语句包括下面方法:
1️⃣addBatch():添加需要批量处理的 SQL 语句或参数
2️⃣executeBatch():执行批量处理语句
3️⃣clearBatch():清空批处理包的语句
(3)JDBC 连接 MySQL 时,如果要使用批处理功能,请再 url 中加参数【rewriteBatcherStatements=true】
(4)批处理往往和 PreparedStatement 一起搭配使用,可以既减少编译次数,又减少运行次数,效率大大提高。

2. 应用实例

public class Batch_ {

    //使用批量方式添加数据
    @Test
    public void batch() throws Exception {
        Connection connection = JDBCUtils.getConnection();
        String sql = "insert into admin2 values(null, ?, ?)";
        PreparedStatement preparedStatement = connection.prepareStatement(sql);
        System.out.println("开始执行");
        long start = System.currentTimeMillis();//开始时间
        for (int i = 0; i < 5000; i++) {//5000 执行
            preparedStatement.setString(1, "jack" + i);
            preparedStatement.setString(2, "666");
            //将 sql 语句加入到批处理包中
            preparedStatement.addBatch();
            //当有 1000 条记录时,在批量执行
            if ((i + 1) % 1000 == 0) {//满 1000 条 sql
                preparedStatement.executeBatch();
                //清空一把
                preparedStatement.clearBatch();
            }
        }
        long end = System.currentTimeMillis();
        System.out.println("批量方式 耗时=" + (end - start));//批量方式 耗时=108
        //关闭连接
        JDBCUtils.close(null, preparedStatement, connection);
    }
}

十、数据库连接池

1. 传统获取 Connection 问题分析

(1)传统的JDBC数据库连接使用 DriverManager 来获取,每次向数据库建立连接的时候都要将 Connection 加载到内存中,再验证IP地址、用户名和密码。需要数据库连接的时候,就向数据库要求一个,频繁的进行数据库连接操作将占用很多的系统资源,容易造成服务器前溃。
(2)每一次数据库连接,使用完后都得断开,如果程序出现异常而未能关闭,将导致数据库 内存泄露,最终将导致重启数据库。
(3)传统获取连接的方式,不能控制创建的连接数量,如连接过多,也可能导致内存泄漏,MySQL 崩溃。
(4)解决传统开发中的数据库连接问题,可以采用数据库 连接池 技术(connection pool)。

2. 数据库连接池基本介绍

(1)预先在缓冲池中放入一定数量的连接,当需要建立数据库连接时,只需从“缓冲池”取出一个,使用完毕之后再放回去。
(2)数据库连接池负责分配、管理和释放数据库连接,它允许应用程序 重复使用 一个现有的数据库连接,而不是重新建立一个。
(3)当应用程序向连接池请求的连接数超过最大连接数量时,这些请求将被加入到等待队列中。

3. 数据库连接池种类

(1) JDBC 的数据库连接池使用 javax.sgl.DataSource 来表示,DataSource 只是一个接口,该接口通常由第三方提供实现。
1️⃣ C3P0 数据库连接池,速度相对较慢,稳定性不错(hibernate,spring)
2️⃣DBCP 数据库连接池,速度相对 C3P0 较快,但不稳定
3️⃣Proxool 数据库连接池,有监控连接池状态的功能,稳定性较 C3P0 差一点
4️⃣BoneCP数据库连接池,速度快
5️⃣ Druid(德鲁伊)是阿里提供的数据库连接池,集DBCP、C3PO、Proxool 优点于一身的数据库连接池。

4. C3P0 应用实例

public class C3P0_ {

    //方式 1: 相关参数,在程序中指定 user, url , password 等
    @Test
    public void testC3P0_01() throws Exception {
        //1. 创建一个数据源对象
        ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();

        //2. 通过配置文件 mysql.properties 获取相关连接的信息
        Properties properties = new Properties();
        properties.load(new FileInputStream("src\\mysql.properties"));
        //读取相关的属性值
        String user = properties.getProperty("user");
        String password = properties.getProperty("password");
        String url = properties.getProperty("url");
        String driver = properties.getProperty("driver");
        //给数据源 comboPooledDataSource 设置相关的参数
        //注意:连接管理是由 comboPooledDataSource 来管理
        comboPooledDataSource.setDriverClass(driver);
        comboPooledDataSource.setJdbcUrl(url);
        comboPooledDataSource.setUser(user);
        comboPooledDataSource.setPassword(password);

        //设置初始化连接数
        comboPooledDataSource.setInitialPoolSize(10);
        //最大连接数
        comboPooledDataSource.setMaxPoolSize(50);
        //测试连接池的效率, 测试对 mysql 5000 次操作
        long start = System.currentTimeMillis();
        for (int i = 0; i < 5000; i++) {
            //这个方法就是从 DataSource 接口实现的
            Connection connection = comboPooledDataSource.getConnection();
            connection.close();
        }
        long end = System.currentTimeMillis();
        //c3p0 5000 连接 mysql 耗时=391
        System.out.println("c3p0 5000 连接 mysql 耗时=" + (end - start));
    }

    //方式 2: 使用配置文件模板来完成
    @Test
    public void testC3P0_02() throws SQLException {
        ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource("hsp_edu");
        //测试 5000 次连接 mysql
        long start = System.currentTimeMillis();
        System.out.println("开始执行....");
        for (int i = 0; i < 500000; i++) {
            Connection connection = comboPooledDataSource.getConnection();
            connection.close();
        }
        long end = System.currentTimeMillis();
        //c3p0 的第二种方式 耗时=413
        System.out.println("c3p0 的第二种方式(500000) 耗时=" + (end - start));//1917
    }
}

5. Druid(德鲁伊)应用实例

public class Druid_ {

    @Test
    public void testDruid() throws Exception {
        //1. 加入 Druid jar 包
        //2. 加入 配置文件 druid.properties , 将该文件拷贝项目的 src 目录
        //3. 创建 Properties 对象, 读取配置文件
        Properties properties = new Properties();
        properties.load(new FileInputStream("src\\druid.properties"));
        //4. 创建一个指定参数的数据库连接池, Druid 连接池
        DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);
        long start = System.currentTimeMillis();
        for (int i = 0; i < 500000; i++) {
            Connection connection = dataSource.getConnection();
            System.out.println(connection.getClass());
            //System.out.println("连接成功!");
            connection.close();
        }
        long end = System.currentTimeMillis();
        //druid 连接池 操作 5000 耗时=412
        System.out.println("druid 连接池 操作 500000 耗时=" + (end - start));//539
    }
}

十一、Apache—DBUtils

1. 基本介绍

(1)commons-dbutils 是 Apache 组织提供的一个开源 JDBC 工具类库,它是对 JDBC 的封装,使用 dbutils 能极大简化 jdbc 编码的工作量。

DbUtils类
(1)QueryRunner类:该类封装了 SQL 的执行,是线程安全的。可以实现增、删、改、查、批处理。
(2)使用 QueryRunner 类实现查询。
(3)ResultSetHandler接口:该接口用于处理 java.sql.ResultSet,将数据按要求转换为另一种形式。在这里插入图片描述

2. 应用实例

public class DBUtils_USE {

    //使用 apache-DBUtils 工具类 + druid 完成对表的 crud 操作
    @Test
    public void testQueryMany() throws Exception { //返回结果是多行的情况
        //1. 得到 连接 (druid)
        Connection connection = JDBCUtilsByDruid.getConnection();
        //2. 使用 DBUtils 类和接口 , 先引入 DBUtils 相关的 jar , 加入到本 Project
        //3. 创建 QueryRunner
        QueryRunner queryRunner = new QueryRunner();
        //4. 就可以执行相关的方法,返回 ArrayList 结果集
        //String sql = "select * from actor where id >= ?";
        // 注意: sql 语句也可以查询部分列
        String sql = "select id, name from actor where id >= ?";
        // 老韩解读
        //(1) query 方法就是执行 sql 语句,得到 resultset ---封装到 --> ArrayList 集合中
                //(2) 返回集合
        //(3) connection: 连接
        //(4) sql : 执行的 sql 语句
        //(5) new BeanListHandler<>(Actor.class): 在将 resultset -> Actor 对象 -> 封装到 ArrayList
        //(6) 1 就是给 sql 语句中的? 赋值,可以有多个值,因为是可变参数 Object... params
        //(7) 底层得到的 resultset ,会在 query 关闭, 关闭 PreparedStatment
        List<Actor> list =
                queryRunner.query(connection, sql, new BeanListHandler<>(Actor.class), 1);
        System.out.println("输出集合的信息");
        for (Actor actor : list) {
            System.out.print(actor);
        }
        //释放资源
        JDBCUtilsByDruid.close(null, null, connection);
    }
}

十二、DAO

1. 基本说明

(1)DAO:data access object,数据访问对象
(2)这样的通用类,称为 BasicDao,是专门和数据库交互的,即完成对数据库(表)的crud操作。
(3)在 BaiscDao 的基础上,实现一张表对应一个 Dao,更好的完成功能。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1353094.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【网络技术】【Kali Linux】Wireshark嗅探(六)地址解析协议(ARP)

一、实验目的 本次实验使用Wireshark流量分析工具进行网络嗅探&#xff0c;旨在了解地址解析协议&#xff08;ARP&#xff09;的工作原理。 二、ARP协议概述 地址解析协议&#xff08;Address Resolution Protocol, ARP&#xff09;位于网络层&#xff08;IP层&#xff09;&…

金和OA SAP_B1Config.aspx存在未授权访问漏洞

产品简介 金和网络是专业信息化服务商&#xff0c;为城市监管部门提供了互联网监管解决方案&#xff0c;为企事业单位提供组织协同OA系统升开发平台&#xff0c;电子政务一体化平台智慧电商平合等服务 漏洞概述 金和OA SAP_B1Config.aspx存在未授权访问漏洞&#xff0c;攻击…

看完,你还会学鸿蒙吗?

是不是前端程序员的春天&#xff0c;我们可以分析鸿蒙现在的市场和布局。其实不仅仅只是前端&#xff0c;还有Android、Java、Python等等开发人员都可以把鸿蒙当做新的出路。 2024年程序员为什么一定要学鸿蒙&#xff1f; 首先&#xff0c;鸿蒙作为一个新系统的出现。它的结构…

Android studio BottomNavigationView 应用设计

一、新建Bottom Navigation Activity项目&#xff1a; 二、修改bottom_nav_menu.xml: <itemandroid:id"id/navigation_beijing"android:icon"drawable/ic_beijing_24dp"android:title"string/title_beijing" /><itemandroid:id"i…

test ui-04-testcomplete 入门介绍

About TestComplete TestComplete是一款适用于各种应用程序类型和技术的自动化测试环境&#xff0c;包括&#xff08;但不限于&#xff09;Windows、.NET、WPF、Visual C、Visual Basic、Delphi、CBuilder、Java以及Web应用程序和服务。 TestComplete既适用于功能测试&#x…

线程的深入学习(一)

前言 前面文章讲述了线程的部分基本知识&#xff0c;这篇是对线程的深入学习&#xff0c;包含线程池&#xff0c;实现框架等。 1.学习如何使用Executor框架创建线程池。 2.并发工具类如CountDownLatch、CyclicBarrier等。 3.线程安全和并发集合&#xff1a; 4.学习如何使用Jav…

python入门第一讲:认识python

目录 什么是计算机 什么是编程 编程语言有哪些 python是咋来的 python能干啥 python的优缺点 什么是计算机 什么叫计算机&#xff0c;当你把问这个问题问家里的老人的时候&#xff0c;他们很可能指着计算器告诉你说&#xff0c;这个就是计算机&#xff0c;这个很明显&am…

CEEMDAN +组合预测模型(Transformer - BiLSTM+ ARIMA)

目录 往期精彩内容&#xff1a; 前言 1 风速数据CEEMDAN分解与可视化 1.1 导入数据 1.2 CEEMDAN分解 2 数据集制作与预处理 3 基于CEEMADN的 Transformer - BiLSTM 模型预测 3.1 定义CEEMDAN-Transformer - BiLSTM预测模型 3.2 设置参数&#xff0c;训练模型 4 基于A…

HubSpot电子邮件自动化的关键功能和流程!

HubSpot提供了强大的电子邮件自动化工具&#xff0c;使用户能够创建、执行和跟踪复杂的电子邮件市场营销活动。以下是HubSpot电子邮件自动化的一些关键功能和流程&#xff1a; 1.电子邮件工作流程&#xff08;Email Workflows&#xff09;&#xff1a; 用户可以使用HubSpot的工…

Lumerical Script------for语句

Lumerical------for语句 正文正文 关于 Lumerical 中 for 语句的用法这里不做过多说明了,仅仅做一个记录,具体用法如下: 通常我们用的比较多的形式是第一种步长值为 1 的情况。对于其他步长值的情况,我们可以使用第二种用法。对于 while 的类似使用方法可以使用第三种。 …

2_并发编程同步锁(synchronized)

并发编程带来的安全性同步锁(synchronized) 1.他的背景 当多个线程同时访问&#xff0c;公共共享资源的时候&#xff0c;这时候就会出现线程安全&#xff0c;代码如&#xff1a; public class AtomicDemo {int i0;//排他锁、互斥锁public void incr(){ //synchronizedi; …

Allins 官网正式上线,铭文赛道进入 AMM 交易时代

“Allins 正在通过全新的 AMM 方案为BRC20及多链铭文资产拓展 DeFi 场景&#xff0c;官网的全新上线意味着铭文资产的交易正式进入 AMM 时代。” 在 2023 年 1 月开始&#xff0c; Ordinals 协议的推出成为了铭文赛道发展的开端&#xff0c;并为比特币这类非图灵完备的生态&…

虾皮马来站点选品:在虾皮(Shopee)5个热门品类和市场特点

在虾皮&#xff08;Shopee&#xff09;马来西亚站点选择商品时&#xff0c;卖家应该考虑一些热门品类和市场特点&#xff0c;以确保他们的产品能够满足当地消费者的需求并取得良好的销售业绩。以下是在虾皮&#xff08;Shopee&#xff09;马来西亚站点销售商品时需要考虑的五个…

大模型实战营第二期——1. 书生·浦语大模型全链路开源开放体系

文章目录 1. 实战营介绍2. 书生浦语大模型介绍2.1 数据2.2 预训练2.3 微调2.4 评测2.5 部署2.6 智能体(应用) 1. 实战营介绍 github链接&#xff1a;https://github.com/internLM/tutorialInternLM&#xff1a;https://github.com/InternLM书生浦语官网&#xff1a;https://in…

c 编码(进行中)

编码出来的jpeg图片只有红&#xff0c;绿色。排查中 ​​​​​​​ #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdlib.h> #include <unistd.h> #include <sys/ioctl.h> #in…

nestjs入门教程系列(三):动态路由到底该怎么用

如何获取前端请求中的参数 引子 我们在处理前端发送过来的请求时&#xff0c;需要访问客户端的request信息&#xff0c;那么我们该怎么操作呢?由于nestjs提供对底层平台的访问即express&#xff0c;所以我们可以通过注入的方式来方位请求对象 TIPS:需要从nestjs/common包里…

【C程序设计】C判断

判断结构要求程序员指定一个或多个要评估或测试的条件&#xff0c;以及条件为真时要执行的语句&#xff08;必需的&#xff09;和条件为假时要执行的语句&#xff08;可选的&#xff09;。 C 语言把任何非零和非空的值假定为 true&#xff0c;把零或 null 假定为 false。 下面…

自动化测试框架 —— pytest框架入门到入职篇

01、pytest框架介绍 pytest 是 python 的第三方单元测试框架&#xff0c;比自带 unittest 更简洁和高效&#xff0c;支持非常丰富的插件&#xff0c;同时兼容 unittest 框架。这就使得我们在 unittest 框架迁移到 pytest 框架的时候不需要重写代码。 pytest框架优点 1、简单…

网络故障排查和流量分析利器-Tcpdump命令

Tcpdump是一个在Unix/Linux系统上广泛使用的命令行网络抓包工具。它能够捕获经过网络接口的数据包&#xff0c;并将其以可读的格式输出到终端或文件中。Tcpdump是一个强大的命令行工具&#xff0c;能够捕获和分析网络数据包&#xff0c;为网络管理员和安全专业人员提供了深入了…

javascript中location对象的属性与方法

前言 本章介绍js中的location中的属性和方法。 文章目录 前言什么是location为什么要用locationlocation对象属性location对象方法总结 什么是location 在JavaScript中&#xff0c;location 是一个包含当前页面的URL信息的对象。它允许你获取和操作当前页面的URL&#xff0c;比…