Review: Java SE 05(JDBC、数据库连接池和DBUtils)

Java SE 05

一、JDBC

1. JDBC概述

  • JDBC(Java Data Base Connectivity) 是 Java 访问数据库的标准规范。是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java语言编写的类和接口组成。是Java访问数据库的标准规范
  • JDBC就是由sun公司定义的一套操作所有关系型数据库的规则(接口),而不同的数据库厂商需要实现这套接口,提供数据库驱动jar包,开发者可以使用这套接口编程,真正执行的代码是对应驱动包中的实现类

2. 使用JDBC实现类进行开发的流程

  • 添加MySQL驱动jar包到当前项目下

  • 注册驱动

    作用:将厂商的jar包中的实现类加载到当前类下,比如com.mysql.jdbc.Driver中定义了静态代码块当Driver类加载后执行静态代码块中的注册驱动语句

    从 JDBC3 开始,目前已经普遍使用的版本,可以不用注册驱动而直接使用,Class.forName 这句话可以省略

  • 获得连接

    使用DriverManager类中getConnection方法来获取连接即获取Connection对象

    getConnection方法中需要传入的参数有3个

    URL(包括数据库厂商名称、服务器所在IP、端口号、所选数据库、参数信息(可选)),数据库用户名,密码

  • 获取语句执行平台(获取Statement接口对象)

    通过Connection对象调用createStatement方法来获取Statement对象

    Statement对象:代表一条语句对象,用于发送 SQL 语句给服务器,用于执行静态 SQL 语句并返回它所生成结果的对象

    Statement对象中常用方法:

    int executeUpdate(String sql) 用于执行insert update delete语句,也支持DDL.返回int类型,代表受影响的行数

    ResultSet executeQuery(String sql) 用于执行select语句, 返回ResultSet结果集对象

    注意:sql字符串中写SQL语句,其中字符串使用单引号,语句结尾;可以省略

  • 处理结果集(只在查询时处理)

    只有在进行查询操作executeQuery的时候, 才会处理结果集ResultSet

    ResultSet常用方法:

    boolean next()游标指向下一行,还有下一条记录就返回true

    xxx getXxx( String or int)重载方法,通过列名或列号(索引从1开始)进行获取数据

  • 释放资源

    • 需要释放的对象:ResultSet 结果集(非查询,不用释放),Statement 语句,Connection 连接

    • 释放原则:先开的后关,后开的先关;ResultSet ==> Statement ==> Connection

      释放方法就是调用对应的close方法

    • 一般将释放资源的语句放在异常处理的finally代码块中

3. JDBC实现增删改查

  • JDBC工具类

    • 工具类:如果一个功能经常要用到,建议把这个功能做成一个工具类,可以在不同的地方重用

    • 获取Connection释放资源在增删改查中会重复使用,所以将这两个操作的方法封装为JDBCUtils工具类中的静态方法

      获取Connection需要URL、数据库用户名、密码、驱动全类名的字符串(可省)可以将这些字符串设置为工具类中的常量,

      若使用低版本的JDBC中还需要将Class.forName加载驱动的操作也封装在工具类中

    • 封装JDBCUtils工具类的实例(不含注册驱动的版本)

      public class JDBCUtils {
      	//1. 定义字符串常量, 记录获取连接所需要的信息
          public static final String URL = "jdbc:mysql://localhost:3306/db_jdbc_test";
          public static final String USERNAME = "root";
          public static final String PASSWORD = "xxxx";
      
          //2.获取连接的静态方法
          public static Connection getConnection() {
              try {
                  //获取连接对象
                  Connection conn = DriverManager.getConnection(URL, USERNAME, PASSWORD);
                  //返回连接对象
                  return conn;
              } catch (SQLException e) {
                  e.printStackTrace();
                  return null;
              }
          }
      
          //关闭资源的方法(DML)
          public static void close(Connection conn, Statement stmt) {
              if (conn != null && stmt != null) {
                  try {
                      conn.close();
                      stmt.close();
                  } catch (SQLException e) {
                      e.printStackTrace();
                  }
              }
          }
      
          //关闭资源的方法(重载方法用于DQL后的释放资源)
          public static void close(Connection conn, Statement stmt, ResultSet res) {
              if (res != null) {
                  try {
                      //对ResultSet对象进行关闭
                      res.close();
                  } catch (SQLException e) {
                      e.printStackTrace();
                  }
              }
              //直接复用DML的释放资源方法
              close(conn, stmt);
          }
      
      }
      
  • DML操作

    • 防止插入中文乱码的解决方案

      将工具类中URL字符串中指定字符的编解码格式

      jdbc:mysql://localhost:3306/db4?characterEncoding=UTF-8

    • 使用工具类进行插入、删除、更改

      public void test() throws SQLException { 
          //1.通过工具类获取连接
          Connection connection = JDBCUtils.getConnection();
          //2.获取Statement
          Statement statement = connection.createStatement();
          //2.1 编写Sql
          String sql = "xxx";
          //2.2 执行Sql
          statement.executeUpdate(sql);
          //3.通过工具类关闭流
          JDBCUtils.close(connection,statement);
      }
      
  • DQL操作

    • 使用工具类进行查询操作

      public void test() throws SQLException { 
          //1.通过工具类获取连接
          Connection connection = JDBCUtils.getConnection();
          //2.获取Statement
          Statement statement = connection.createStatement();
          //2.1 编写Sql
          String sql = "xxx";
          //2.2 执行Sql, 获取ResultSet对象
          ResultSet res = statement.executeUpdate(sql);
          //2.3处理结果集
          //3.通过工具类关闭流
          JDBCUtils.close(connection, statement, res);
      }
      

4. SQL注入问题

  • 问题:用户输入的密码和 SQL 语句进行字符串拼接。用户输入的内容作为了 SQL 语句语法的一部分,改变了原有SQL 真正的意义

    拼接后WHERE条件永远为真,相当于没有过滤,查询全部数据,造成密码不正确也能进行查询现象

  • 解决:防止用户输入的密码和执行查询的SQL语句进行拼接

5. PreparedStatement接口

  • PreparedStatement接口概述

    • PreparedStatement接口是Statement接口的子接口,继承了Statement中的所有方法

    • PreparedStatement是一个预编译的SQL语句对象

      预编译是指SQL 语句被预编译,并存储在 PreparedStatement对象中,然后可以使用此对象多次高效地执行该语句

  • PreparedStatement特点

    • 预编译可以提高SQL执行的效率
    • 可以有效防止SQL注入的问题
    • 可以减少编译次数提高数据库性能
    • PrepareStatement是预编译的SQL语句对象,语句中可以包含动态参数?,在执行时可以为?动态设置参数值
  • 获取PreparedStatement对象

    通过Connection中的方法PreparedStatement prepareStatement(String sql)

    通过Connection中的方法获取Statement对象的方法Statement createStatement()中是空参的,

    使用Statement对象时才传入SQL参数

    指定预编译的 SQL 语句,SQL 语句中使用占位符 ? 创建一个语句对象

    如:"SELECT * FROM jdbc_user WHERE username=? AND password=?";

  • 使用PreparedStatement步骤

    1. 获取PreparedStatement对象(传入包含动态参数的SQL语句)

    2. 使用setXxx(占位符位置,真实的值)方法设置占位符参数

      占位符的起始索引是1

    3. 执行PreparedStatement中处理SQL的方法

      PreparedStatement接口中的常用方法同Statement接口,不同是Statement的方法中传参是完整的静态SQL字符串:

      int executeUpdate(); 执行insert、update、delete语句

      ResultSet executeQuery(); 执行select语句,返回结果集对象ResuletSet

    4. 释放资源(调用PreparedStatement对象中的close方法)

  • Statement与PreparedStatement的对比

    • 先通过Connection生成对象Statement,Statement对象每调用一次处理SQL的方法,就会将SQL发送给数据库,数据库要先编译再执行;

      假如有一万条数据,就会编译一万次

    • 通过Connection生成PreparedStatement对象的同时会将SQL语句发送给数据库进行预编译,后面执行多次插入操作,每次只需要调用PreparedStatement中的setXxx方法进行占位符的参数设置和调用处理SQL的方法;

      假如有一万条数据,数据库也只是进行一次编译,所以可以减少编译次数,提高效率

6. JDBC控制事务

  • 可以使用MySQL的命令来操作事务,也可以使用JDBC实现类来操作事务

  • 一般使用Connection中的方法实现事务管理

    使用步骤:

    1. 获取连接

    2. 开启事务

      void setAutoCommit(boolean autoCommit)

      参数是 true 或 false 如果设置为 false,表示关闭自动提交,相当于开启事务

    3. 获取到 PreparedStatement , 执行更新操作

    4. 正常情况下提交事务

      void commit()

    5. 出现异常回滚事务

      void rollback()

    6. 关闭资源

二、数据库连接池和DBUtils

1. 数据库连接池

  • 连接池概述

    • 作用:实际开发中获得连接释放资源是非常消耗系统资源的两个过程,为了解决性能的问题,通常采用连接池技术,来共享Connection。这样就不需要每次都创建连接、释放连接了,将这些操作都交给连接池了。

      用池来管理Connection,这样可以重复使用Connection。 当使用完Connection后,调用Connection的close()方法也不会真的关闭Connection,而是把Connection“归还”给池。

    • Java为数据库连接池提供了公共的接口:javax.sql.DataSource,各个厂商需要让自己的连接池实现这个接口。这样应用程序可以方便的切换不同厂商的连接池。

  • DBCP连接池

    • 在DBCP包中提供了DataSource接口的实现类,具体是连接池BasicDataSource类

      DataSource接口中的常用方法:

      Connection getConnection()

    • 封装DBCPUtils工具类:

      1. 定义常量保存数据库连接的相关信息(DRIVERNAME、URL、USERNAME、PASSWORD)
      2. 创建连接池对象(使用DBCP提供的实现类BasicDataSource类,将该对象定义为静态成员变量)
      3. 使用静态代码块进行数据库连接的相关信息配置(使用BasicDataSource中的setXxxx方法)
      4. 封装获取连接的静态方法(使用BasicDataSource类创建的静态成员变量调用getConnection方法)
      5. 封装释放资源的静态方法(DML、DQL两种close方法重载)
    • 使用DBCPUtils工具类:

      获得连接释放资源时使用DBCPUtils中的方法来实现对数据库的DML、DQL操作

  • C3P0连接池

    • C3P0提供的核心工具类, ComboPooledDataSource , 如果想使用连接池,就必须创建该类的对象

    • 封装C3P0Utils工具类:

      1. 创建连接池对象通过使用C3P0对DataSource接口的实现类,将这个对象作为C3P0Utils的静态成员变量

        C3P0中的配置信息都存储在配置文件c3p0-config.xml中,可以定义默认配置和指定配置名的配置

        在ComboPooledDataSource构造方法中空参为使用XML的默认配置,带参为使用XML中指定配置名

      2. 封装获取连接的方法(使用ComboPooledDataSource类创建的静态成员变量调用getConnection方法)

      3. 封装释放资源的方法(DML、DQL两种close方法重载)

    • 使用C3P0Utils工具类

      获得连接释放资源时使用C3P0Utils中的方法来实现对数据库的DML、DQL操作

  • Druid连接池

    • Druid(德鲁伊)是阿里巴巴开发的号称为监控而生的数据库连接池,Druid是目前最好的数据库连接池。在功能、性能、扩展性方面,都超过其他数据库连接池,同时加入了日志监控,可以很好的监控DB池连接和SQL的执行情况

    • 必要的jar包

    • 封装DruidUtils工具类:

      1. 通过工厂类DruidDataSourceFactory的createDataSource(Properties p)方法获取连接池DataSource类型对象

        • Druid中的配置信息一般存储在.properties文件中,文件名可自定义

        • 设置一个静态代码块在DruidUtils工具类加载时创建连接池DataSource类型的对象:

          Druid连接池不能够主动加载配置文件 ,需要指定文件,将指定的文件加载到字节输入流对象中传入Properties类型对象的load方法中,传入工厂类createDataSource(Properties p)方法中来创建连接池对象

      2. 封装获取连接的方法(使用DataSource类型的静态成员变量调用getConnection方法)

      3. 封装释放资源的方法(DML、DQL两种close方法重载)

    • 使用DruidUtils工具类

      获得连接释放资源时使用DruidUtils中的方法来实现对数据库的DML、DQL操作

2. DBUtils工具类

  • DBUtils中的核心功能

    DbUtils类,是一个工具类,定义了关闭资源与事务处理相关方法

  • JavaBean组件的概念

    • JavaBean就是一个类,开发中通常用于封装数据
      1. 需要实现序列化接口Serializable
      2. 提供私有字段
      3. 提供getter和setter
      4. 提供空参构造
  • 使用DBUtils中的QueryRunner完成增删改

    • 创建QueryRunner

      自动方式创建需要向QueryRunner构造中传入DataSource类型的数据库连接池对象

      手动方式创建需要使用QueryRunner空参构造

    • QueryRunner实现增删改操作主要方法

      update(Connection conn, String sql, Object... params)

      update(String sql, Object... params)

      • update方法是有重载的方法,当QueryRunner是自动方式创建的不用传Connection对象,

        手动方式创建QueryRunner要传入Connection对象,使用连接池工具类调用其中的getConnection方法获取

      • 动态SQL中使用?作为占位符

      • params是可变长度Object类型的变量(一般传入Object[]类型数组),用来设置占位符上的参数

      • 当动态SQL中使用?作为占位符的参数只有一个时,不需要创建数组传参,直接在params位置传入这一个参数即可

    • QueryRunner实现增删改操作主要流程

      1. 创建QueryRunner对象(自动或手动)
      2. 调用QueryRunner对象中的update方法
  • 使用DBUtils中的QueryRunner完成查询操作

    • 创建QueryRunner

    • QueryRunner实现查询操作主要方法

      query(Connection con,String sql,handler,Object[] param)

      query(String sql, handler ,Object[] param)

      query方法的返回值都是泛型,具体的返回值类型,会根据结果集的处理方式,发生变化

      其中handler需要的对象类型是ResultSetHandler接口的实现类,ResultSetHandler可以对查询出来的ResultSet结果集进行处理,达到一些业务上的需求,每一种实现类都代表了对查询结果集的一种处理方式

      常用的ResultSetHandler实现类:

      ArrayHandler 将结果集的第一条数据封装到数组中

      ArrayListHandler可以将每条数据先封装到数组中, 再将数组封装到集合中

      BeanHandler 将结果集的第一条数据封装到 JavaBean中

      BeanListHandler 将结果集的每一条和数据封装到 JavaBean中 再将JavaBean 放到list集合中

      MapHandler 将结果集的第一条记录封装到 Map<String,Object>中 key对应的是 列名 value对应的是 列的值

      ScalarHandler 用于封装单个的数据

    • QueryRunner实现查询操作主要流程

      1. 创建QueryRunner对象(自动或手动)
      2. 调用QueryRunner对象中的query方法

3. 数据库批处理

  • 数据库批处理概述

    • 批处理指的是一次操作中执行多条SQL语句,批处理相比于一次一次执行效率会提高很多
    • 批处理操作主要使用了Statement或PreparedStatement中的批处理方法
  • 实现数据库批处理

    • mysql 批处理是默认关闭的,所以需要加一个参数才打开mysql 数据库批处理,在url中添加

      rewriteBatchedStatements=true

    • 批处理主要方法

      void addBatch()

      将给定的 SQL 命令添加到此 Statement 对象的当前命令列表中,

      通过调用方法 executeBatch 可以批量执行此列表中的命令

      int[] executeBatch()

      每次提交一批命令到数据库中执行,如果所有的命令都成功执行了,

      那么返回一个数组,这个数组是说明每条命令所影响的行数

    • 实现数据库批处理的主要流程

      1. 获取Connection对象
      2. 获取PreparedStatement或Statement对象
      3. 将SQL添加到批处理列表
      4. 统一进行批量处理

4. MySQL元数据

  • MySQL元数据概述

    • 除了表之外的数据都是元数据,包括查询结果信息、数据库和数据表的信息、MySQL服务器信息
    • 查看MySQL元数据的常用命令
  • JDBC获取数据库元数据信息

    connection 连接对象, 调用 getMetaData() 方法,获取的是DatabaseMetaData 数据库元数据对象

    调用DatabaseMetaData中的方法获取数据库元数据信息

  • JDBC获取结果集元数据信息

    PreparedStatement 预处理对象调用 getMetaData() , 获取的是ResultSetMetaData , 结果集元数据对象

    调用ResultSetMetaData中的方法获取结果集元数据信息

posted @   Ramentherapy  阅读(305)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示