学静思语
Published on 2025-02-14 / 5 Visits
0
0

JDBC笔记

JDBC笔记

一、jdbc的下载,网址为[ https://www.mysql.com/]

image-20231123155732701

image-20231123155810495

image-20231123155605210

image-20231123160040104

二、JDBC的使用

1.jdbc的初次使用

  • 代码

    package com.leon.study;
    
    import com.mysql.jdbc.Driver;
    import org.junit.jupiter.api.Test;
    
    import java.sql.Connection;
    import java.sql.SQLException;
    import java.sql.Statement;
    import java.util.Properties;
    
    /**
    
  • ClassName:HelloWord

  • Package:com.leon.study

  • Description:
    *

  • @Author: leon–>ZGJ

  • @Create: 2023/11/23 10:14

  • @Version: 1.0
    */
    public class HelloWord {
    @Test
    public void studyJdbc() throws Exception {
    // 注册驱动驱动

        Driver driver = new Driver();
    

    // 获取连接

        /*
            1.jdbc:mysql这个表示的是协议,通过jdbc的方式连接MYSQL
            2.localhost 指的是ip地址
            3.3306 指的是端口号
            4.studyjdbc 指的是你要连接的数据库名称
        */
        String url = "jdbc:mysql://localhost:3306/studyjdbc";
        Properties properties = new Properties();
    

    // 数据库用户名

        properties.setProperty("user","root");
    

    // 数据库用户密码

        properties.setProperty("password","root");
        Connection connect = driver.connect(url, properties);
    

    // System.out.println(connect);

    // 执行sql语句
    // 创建SQL语句

        String sql = "insert into actor values(null,'李华','女','1991-7-8','985211')";
        Statement statement = connect.createStatement();
    

    // 执行SQL语句‘

        int i = statement.executeUpdate(sql);
        System.out.println(i);
    

    // 关闭资源

        if(statement != null){
            statement.close();
        }
        if(connect != null ){
            connect.close();
        }
    

    }
    }

2.jdbc的获取连接的五种方式

package com.leon.connect;

import com.mysql.jdbc.Driver;
import org.junit.jupiter.api.Test;

import java.io.FileInputStream;
import java.lang.reflect.Constructor;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
import java.util.Properties;


/**
 * ClassName:ConnectTest
 * Package:com.leon.connect
 * Description:
 *
 * @Author: leon-->ZGJ
 * @Create: 2023/11/23 10:42
 * @Version: 1.0
 */
public class ConnectTest {

//    方式一
    @Test
    public void connect01() throws Exception {
//        注册驱动
        Driver driver = new Driver();
//        建立连接
        String url = "jdbc:mysql://localhost:3306/studyjdbc";
        Properties properties = new Properties();

        properties.setProperty("user","root");
        properties.setProperty("password","root");

        Connection connect = driver.connect(url, properties);
//        执行SQL语句
        String sql = "insert into actor values(null,'刘德华','男','1998-12-1','110')";
        Statement statement = connect.createStatement();
        statement.executeUpdate(sql);

//        关闭资源
        if(statement != null){
            statement.close();
        }
        if(connect != null ){
            connect.close();
        }

    }

//    方式二
    @Test
    public void connect02() throws Exception {

//        类加载
        Class clazz = Class.forName("com.mysql.jdbc.Driver");
//        获取构造器
        Constructor declaredConstructor = clazz.getDeclaredConstructor();
//        强制访问
        declaredConstructor.setAccessible(true);
//        创建对象
        Driver driver = (Driver)declaredConstructor.newInstance();

        String url = "jdbc:mysql://localhost:3306/studyjdbc";
        Properties properties = new Properties();
//      user和password是规定好,不能胡乱更改
        properties.setProperty("user","root");
        properties.setProperty("password","root");

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

        //        执行SQL语句
        String sql = "insert into actor values(null,'韩老师','男','1998-12-1','110')";
//        获取Statement对象
        Statement statement = connect.createStatement();
        statement.executeUpdate(sql);


    }


//    方式三
    /*
        1. 使用DriverManager对Driver进行统一管理
        2. 使用 registerDriver()静态方法进行注册

    */
    @Test
    public void connect03() throws Exception {

        Class clazz = Class.forName("com.mysql.jdbc.Driver");
//      获取构造器
        Constructor declaredConstructor = clazz.getDeclaredConstructor();
//        强制访问
        declaredConstructor.setAccessible(true);
//        创建对象
        Driver driver = (Driver) declaredConstructor.newInstance();
//      使用DriverManager统一进行注册管理
        DriverManager.registerDriver(driver);
//        创建url、user、password
        String url = "jdbc:mysql://localhost:3306/studyjdbc";
        String user = "root";
        String password = "root";
//        获取连接
        Connection connection = DriverManager.getConnection(url, user, password);
//      创建SQL语句
        String sql = "delete from actor where id = '3'";
//      获取Statement对象
        Statement statement = connection.createStatement();
//        执行SQL语句
        int i = statement.executeUpdate(sql);
        System.out.println(i > 0 ? "删除成功":"删除失败");

    }

//    方式4
    @Test
    public void connect04() throws Exception {
//        进行类的加载
        Class.forName("com.mysql.jdbc.Driver");
//       因为Driver的静态代码块对Driver进行了注册管理
        /*
          1.代码
            static {
                try {
                    DriverManager.registerDriver(new Driver());
                } catch (SQLException var1) {
                    throw new RuntimeException("Can't register driver!");
                }
            }
         */
//        创建url、user、password
        String url = "jdbc:mysql://localhost:3306/studyjdbc";
        String user = "root";
        String password = "root";
        Connection connection = DriverManager.getConnection(url, user, password);
        System.out.println(connection);



    }

//    方式五
    @Test
    public void connect05() throws Exception {
//        进行类加载
        Class.forName("com.mysql.jdbc.Driver");
//        使用文件来读取连接信息
        Properties properties = new Properties();
//      加载文件
        properties.load(new FileInputStream("src/mysql.properties"));
//      获取数据
        String url = properties.getProperty("url");
        String user = properties.getProperty("user");
        String password = properties.getProperty("password");
//      获取connect连接
        Connection connection = DriverManager.getConnection(url, user, password);

        System.out.println(connection);


    }

}

3.ResultSet接口

  • 基本介绍

  • 表示数据库结果集的数据表,通常通过执行查询数据库的语句生成

  • ResultSet对象维护一个指向其当前数据行的光标。最初,光标位于第一行之前。next方法将光标移到下一行,因为当ResultSet对象中没有更多行时,它会返回false,所以可以在while循环中使用它来迭代结果集。

  • previous()向上移动一行

  • getXxx(列的索引或者列名),这个xxx是你在数据库表设置的数据类型

  • getObject(列的索引值或列名),返回值对应列的值,接收类型为Object

  • 代码

    package com.leon.resultset;
    
    import org.junit.jupiter.api.Test;
    
    import java.io.FileInputStream;
    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.ResultSet;
    import java.sql.Statement;
    import java.util.Properties;
    
    /**
    
  • ClassName:ResultSetTest

  • Package:com.leon.resultset

  • Description:

  •  使用ResultSet类的使用
    
  • @Author: leon–>ZGJ

  • @Create: 2023/11/23 17:27

  • @Version: 1.0
    */
    public class ResultSetTest {

    @Test
    public void resultSet() throws Exception {
    // 创建properties对象

      Properties properties = new Properties();
    

    // 加载文件

      properties.load(new FileInputStream("src/mysql.properties"));
    

    // 获取数据:url,user,password,driver

      String driver = properties.getProperty("driver");
      String url = properties.getProperty("url");
      String user = properties.getProperty("user");
      String password = properties.getProperty("password");
    

    // 加载驱动

      Class.forName(driver);
    

    // 获取数据库链接

      Connection connection = DriverManager.getConnection(url, user, password);
    

    // 创建SQL语句

      String sql = "select id,name,sex,borndate from actor";
    

    // 获取Statement对象

      Statement statement = connection.createStatement();
    

    // 执行SQL语句

      ResultSet resultSet = statement.executeQuery(sql);
    
      /*
      表中的数据
      +----+--------+-----+---------------------+--------+
      | id | name   | sex | borndate            | phone  |
    

    next +—-+——–+—–+———————+——–+
    —-> | 2 | 李华 | 女 | 1991-07-08 00:00:00 | 985211 |

      |  4 | 刘德华 | 男  | 1998-12-01 00:00:00 | 110    |
      |  5 | 刘德华 | 男  | 1998-12-01 00:00:00 | 110    |
      |  6 | 韩老师 | 男  | 1998-12-01 00:00:00 | 110    |
      |  7 | 韩老师 | 男  | 1998-12-01 00:00:00 | 110    |
      +----+--------+-----+---------------------+--------+
      */
    

    // 如果没有更多行时返回false

      while(resultSet.next()){
    

    // 获取第一行第一列的数据

          int id = resultSet.getInt(1);
    

    // 获取第一行第二列的数据

          String name = resultSet.getString(2);
    

    // 获取第一行第三列的数据

          String sex = resultSet.getString(3);
    

    // 获取第一行第四列的数据

          String borndate = resultSet.getString(4);
          System.out.println("id = " + id + " name= " + name + " sex= " + sex + " brondate= " + borndate);
    
      }
    

    // 关闭资源

      if(resultSet != null){
          resultSet.close();
      }
      if(statement != null){
          statement.close();
      }
      if(connection != null){
          connection.close();
      }
    

    }

    }
    
  • 数据示意图

    image-20231123214157080

4.Statement接口

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

  • 在建立连接后,需要对数据库进行访问,执行SQL语句,可以通过

  • Statement[这个存在SQL注入问题]

  • PreparedStatement[预处理]

  • CallableStatement[存储过程]

  • Statement对象执行SQL语句,存在SQL注入风险,所以不建议使用

  • SQL注入是利用某些系统没有对用户输入的数据进行充分的检查,而在用户输入数据中注入非法的SQL语句段或命令,恶意攻击数据库

  • 防范SQL注入,只要使用PreparedStatement(从Statement扩展而来)取代Statement就可以了

  • 类图

    image-20231123215405685

  • Statement 代码

    package com.leon.preparedstatement;
    
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.IOException;
    import java.net.URL;
    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.ResultSet;
    import java.sql.Statement;
    import java.util.Properties;
    import java.util.Scanner;
    
    /**
    
  • ClassName:StatementTest

  • Package:com.leon.preparedstatement

  • Description:
    *

  • @Author: leon–>ZGJ

  • @Create: 2023/11/23 22:13

  • @Version: 1.0
    */
    public class StatementTest {

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

      Scanner scanner = new Scanner(System.in);
      System.out.print("请输入你的账号:");
      String name = scanner.nextLine();
    
      System.out.print("请输入你的密码:");
      String pwd = scanner.nextLine();
    
      //        读取数据
      Properties properties = new Properties();
    

    // 加载文件

      properties.load(new FileInputStream(StatementTest.class.getResource("/").getFile()+"mysql.properties"));
    

    // 读取数据Driver,url ,user,password

      String driver = properties.getProperty("driver");
      String url = properties.getProperty("url");
      String user = properties.getProperty("user");
      String password = properties.getProperty("password");
    

    // 类加载

      Class.forName(driver);
    

    // 获取连接

      Connection connection = DriverManager.getConnection(url, user, password);
    

    // 获取select对象

      Statement statement = connection.createStatement();
    

    // 创建SQL语句

      String sql = "select * from admin where name='"+name+"' and  pwd = '"+pwd+"'";
    

    // 执行SQL

      ResultSet resultSet = statement.executeQuery(sql);
    
      if(resultSet.next()){
          System.out.println("登录成功");
      }else {
          System.out.println("登录失败");
      }
    

    // 关闭资源

      if(resultSet != null){
          resultSet.close();
      }
      if(statement != null){
          statement.close();
      }
      if(connection != null){
          connection.close();
      }
    

    }

    }

5. PreparedStatement 类

  • 基本介绍

  • PreparedStatement 执行的SQL语句中不确定的参数用 “?“(又称占位符) 来表示,调用PreparedStatement对象的setXxx(parameterIndex,xxx)方法来设置这些参数,setXxx()方法有两个参数,第一个参数是要设置的SQL语句中的 占位符的索引(从1开始),第二个是设置SQL语句中的占位符的值,值的类型根据你在数据库中的表来确定的

  • 调用executeQuery(),返回的是ResultSet对象,这个是查询语句使用的方法,也可说是执行DQL语句的方法:DQL语句:数据查询语句

  • 调用excuteUpdate(),执行更新,包括增,删,修改,返回的是影响的行数,也可以说是执行DML语句的方法:DML语句:数据库操作语言

  • setObject(占位符索引值,占位符的值)

  • 预处理好处

  • 不再使用字符串拼接SQL语句,减少语法错误

  • 有效的解决了SQL注入问题

  • 大大减少了编译次数,效率较高

  • 代码

    package com.leon.preparedstatement;
    
    import org.junit.jupiter.api.Test;
    
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.sql.*;
    import java.util.Properties;
    import java.util.Scanner;
    
    /**
    
  • ClassName:PreparedStatementTest

  • Package:com.leon.preparedstatement

  • Description:
    *

  • @Author: leon–>ZGJ

  • @Create: 2023/11/23 21:52

  • @Version: 1.0
    */
    public class PreparedStatementTest {

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

      Scanner scanner = new Scanner(System.in);
      System.out.print("请输入你的账号:");
      String name = scanner.nextLine();
    
      System.out.print("请输入你的密码:");
      String pwd = scanner.nextLine();
    
      //        读取数据
      Properties properties = new Properties();
    

    // 加载文件

      properties.load(new FileInputStream(StatementTest.class.getResource("/").getFile()+"mysql.properties"));
    

    // 读取数据Driver,url ,user,password

      String driver = properties.getProperty("driver");
      String url = properties.getProperty("url");
      String user = properties.getProperty("user");
      String password = properties.getProperty("password");
    

    // 类加载

      Class.forName(driver);
    

    // 获取连接

      Connection connection = DriverManager.getConnection(url, user, password);
    

    // 创建SQL

      String sql = "select * from admin where name = ? and pwd = ? ";
      //      获取PreparedStatement对象
        PreparedStatement preparedStatement = connection.prepareStatement(sql);
    

    // 给占位符设置数据

        preparedStatement.setString(1,name);
        preparedStatement.setString(2,pwd);
    

    // 执行语句,这个是不需要在executeQuery()方法中传入SQL语句作为实参,因为有占位符

        ResultSet resultSet = preparedStatement.executeQuery();
             if(resultSet.next()){
        System.out.println("登录成功");
    }else {
        System.out.println("登录失败");
    }
    
    //      关闭资源
    if(resultSet != null){
        resultSet.close();
    }
    if(preparedStatement != null){
        preparedStatement.close();
    }
    if(connection != null){
        connection.close();
    }
    

    }
    }

6. 事务

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

7. 批处理

  • 基本介绍
  • 当需要成批插入或者更新记录时,可以采用java的批量更新机制,这一机制允许多条语句一次提交给数据库批量处理,通常情况下比单独提交处理更有效率
  • JDBC的批量处理语句包括下面方法:
    • addBatch():添加需要批量处理的SQL语句或参数
    • executeBatch():执行批量处理语句
    • clearBatch():清空批处理语句
  • JDBC连接MYSQL时,如果要使用批处理功能,请在url中添加参数{?rewriteBatchedStatements=true}
  • 批处理往往和PreparedStatement一起搭配使用,可以减少编译次数,又减少运行次数,效率大大提高

8.数据库连接池

  • 数据库连接池基本介绍
  • 预先在缓冲池中放入一定数量的连接,当需要建立数据库连接时,只需要从“缓冲池”中取出一个,使用完毕之后再放回去
  • 数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是重新建立一个
  • 当应用程序向连接池请求的连接超过最大连接数量时,这些请求将被加入到等待队列中
  • 数据库连接池种类
  • JDBC的数据库连接池使用 javax.sql.DataSource来表示,DataSource只是一个接口,该接口通常由第三方提供实现
  • C3P0数据库连接池,速度相对较慢,稳定性不错(hibernate,spring底层使用的都是C3P0)
  • DBCP数据库连接池,速度相对c3p0较快,但是不稳定
  • Proxool数据库连接池,有监控连接池状态的功能,稳定性较c3p0差一点
  • BoneCP数据库连接池,速度快
  • Druid(德鲁伊)是阿里提供的数据库连接池,集DBCP、C3P0、Proxool优点于一身的数据库连接池

9.Apache-DBUtils

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

  • DBUtils类

  • QueryRunner类:该类封装了SQL的执行,是线程安全的,可以实现增、删、改、查、批处理

  • ResultSetHandler接口:该接口用于处理java.sql.ResultSet,将数据按要求转换为另一个形式

  • 对象

    ArrayHandler:把结果集中的第一行数据转成对象数组
    ArrayListHandler:把结果集中的每一行都转成一个数组,再存放到List中
    BeanHandler:将结果集中的第一行数据封装到一个对应的javaBean实例中
    BeanListHandler:将结果集中的每一行数据都封装到一个对应的javaBean实例中,存放到List里
    ColumnListHandler:将结果集中的某一列的数据存放到List中
    KeyedHandler(name):将结果集中的每一行都封装到Map里,再把这些map存放到一个map里,其key为指定的key
    MapHandler:将结果集中的第一行数据存放到一个Map里,key是列名,values就是对应的值
    MapListHandler:将结果集中的每一行数据都封装到一个map里,然后再存放到List
    ScalarHandler:将某一行的某一列数据封装到Object对象中    
    

Comment