• jdbc的API详解


    1、DriverManager

    • 注册驱动
      // 这个可以不用写,mysql驱动里面配置了
      // 会自动加载jar包中META-INF/services/java.sql.Driver文件中的驱动类
      Class.forName("com.mysql.cj.jdbc.Driver");
      
      • 1
      • 2
      • 3

    com.mysql.cj.jdbc.Driver这个类中,有个静态代码块,是用来注册驱动的,源码如下:

    package com.mysql.cj.jdbc;
    
    public class Driver extends NonRegisteringDriver implements java.sql.Driver {
        public Driver() throws SQLException {
        }
    
        static {
            try {
                DriverManager.registerDriver(new Driver());
            } catch (SQLException var1) {
                throw new RuntimeException("Can't register driver!");
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 获取数据库连接
      //String url = "jdbc:mysql://127.0.0.1:3306/db1";
      // 如果是本机的mysql并且端口是默认的3306,可以简化书写
      String url = "jdbc:mysql:///db1";
      String url = "jdbc:mysql:///db1";
      String username = "root";
      String password = "root1234";
      // 2. 获取连接
      Connection conn = DriverManager.getConnection(url, username, password);
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8

    2、Connection

    数据库连接对象

    • 获取执行的sql对象
      • 获取普通执行sql对象
        Statement statement = conn.createStatement();
        
        • 1
      • 获取预编译sql执行的sql对象:防止sql注入
        PreparedStatement prepareStatement = conn.prepareStatement(sql);
        
        • 1
    • 管理事务
      • 开启事务
        // true:设置成自动提交事务
        // false:设置成手动提交事务
        // 开启事务
        setAutoCommit(false)
        
        • 1
        • 2
        • 3
        • 4
      • 提交事务
        commit()
      • 回滚事务
        rollback()

    例子

    1. 模拟数据
      drop table if exists account;
      create table if not exists account
      (
          id    int primary key auto_increment,
          name  varchar(10),
          money double(10, 2)
      );
      insert into account(name, money)
      values ('张三', 1000),
             ('李四', 1000);
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
    2. java代码
      // 如果是本机的mysql并且端口是默认的3306,可以简化书写
      String url = "jdbc:mysql:///db1";
      String username = "root";
      String password = "root1234";
      
      // 1. 注册驱动
      // 这个可以不用写,mysql驱动里面配置了
      // 会自动加载jar包中META-INF/services/java.sql.Driver文件中的驱动类
      //            Class.forName(className);
      // 2. 获取连接
      Connection conn = DriverManager.getConnection(url, username, password);
      // 3. 定义sql语句
      String sql1 = "update account set money = 111 where id = 1";
      String sql2 = "update account set money = 111 where id = 2";
      // 4. 获取执行sql的对象 statement
      Statement statement = conn.createStatement();
      /**
       * ========事务管理=================
       */
      try {
          // 开启事务
          conn.setAutoCommit(false);
          // 5. 执行sql语句
          int count1 = statement.executeUpdate(sql1);
          System.out.println("count: " + count1);
          // 模拟失败
          int i = 1 / 0;
          int count2 = statement.executeUpdate(sql2);
          System.out.println("count: " + count2);
          // 提交事务
          conn.commit();
      } catch (Exception e) {
          // 回滚事务
          conn.rollback();
          e.printStackTrace();
      }
      
      // 6. 处理结果
      // 7. 释放资源
      statement.close();
      conn.close();
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40
      • 41

    3、Statement

    作用就是执行sql语句

    • int executeUpdate(String sql):执行DML、DDL语句
      • 返回值:DML语句返回的是影响的行数,DDL语句返回的是0
    • ResultSet executeQuery(String sql):执行DQL语句
      • 返回值:查询的结果集

    例子

    • executeUpdate 执行DML语句

      @Test
      public void testDML() throws Exception {
          //String url = "jdbc:mysql://127.0.0.1:3306/db1";
          // 如果是本机的mysql并且端口是默认的3306,可以简化书写
          String url = "jdbc:mysql:///db1";
          String username = "root";
          String password = "root1234";
          String className = "com.mysql.cj.jdbc.Driver";
          // 1. 注册驱动
          // 这个可以不用写,mysql驱动里面配置了
          // 会自动加载jar包中META-INF/services/java.sql.Driver文件中的驱动类
          // Class.forName(className);
          // 2. 获取连接
          Connection conn = DriverManager.getConnection(url, username, password);
          // 3. 定义sql语句
          String sql = "insert into account(name, money) values ('张三丰', '2000');";
          // 4. 获取执行sql的对象 statement
          Statement statement = conn.createStatement();
          // 5. 执行sql语句
          int count = statement.executeUpdate(sql);
          // 6. 处理结果 count 为 1
          System.out.println("count: " + count);
          // 7. 释放资源
          statement.close();
          conn.close();
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
    • executeUpdate 执行DDL语句

      @Test
      public void testDDL() throws Exception {
          //String url = "jdbc:mysql://127.0.0.1:3306/db1";
          // 如果是本机的mysql并且端口是默认的3306,可以简化书写
          String url = "jdbc:mysql:///db1";
          String username = "root";
          String password = "root1234";
          String className = "com.mysql.cj.jdbc.Driver";
          // 1. 注册驱动
          // 这个可以不用写,mysql驱动里面配置了
          // 会自动加载jar包中META-INF/services/java.sql.Driver文件中的驱动类
          // Class.forName(className);
          // 2. 获取连接
          Connection conn = DriverManager.getConnection(url, username, password);
          // 3. 定义sql语句
          String sql = "create table if not exists tb_test_ddl\n" +
                  "(\n" +
                  "    id       int primary key auto_increment,\n" +
                  "    username varchar(20) not null unique,\n" +
                  "    password varchar(20) not null default 123456\n" +
                  ");";
          // 4. 获取执行sql的对象 statement
          Statement statement = conn.createStatement();
          // 5. 执行sql语句
          int count = statement.executeUpdate(sql);
          // 6. 处理结果 count 为 0
          System.out.println("count: " + count);
          // 7. 释放资源
          statement.close();
          conn.close();
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
    • executeQuery 执行DQL语句

    这里使用的是sql注入的例子

    模拟数据

    create table if not exists tb_user
    (
        id       int primary key auto_increment,
        username varchar(20),
        password varchar(20)
    );
    
    insert into tb_user(username, password)
    VALUES ('zhangsan', '123'),
           ('lisi', '123');
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    java 代码

    @Test
    public void testSqlInject() throws Exception {
        String url = "jdbc:mysql:///db1";
        String username = "root";
        String password = "root1234";
    
        Connection conn = DriverManager.getConnection(url, username, password);
    
        String name = "asdafa";
        String pwd = "' or '1' = '1";
    
        // 3. 定义sql语句
        String sql = "select * from tb_user where username='" + name + "' and password='" + pwd + "'";
        // select * from tb_user where username='asdafa' and password='' or '1' = '1'
        // 上面的语句相当于 select * from tb_user
        System.out.println(sql);
    
        Statement statement = conn.createStatement();
        // 通过执行上面的sql语句,是查询所有的user数据
        ResultSet rs = statement.executeQuery(sql);
        if (rs.next()) {
            System.out.println("登陆成功");
        } else {
            System.out.println("登陆失败");
        }
        // 释放资源
        rs.close();
        statement.close();
        conn.close();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    4、ResultSet

    ResultSet 里面是封装了DQL查询语句的结果

    • boolean next()
      • 将光标向下移动一位,判断当前行是否有效
      • 返回值:
        • true:有效行,当前行有数据
        • false:无效行,当前行没有数据
    • xxx getXxx(param) 获取数据
      • xxx:数据类型
        • 例如 int getInt(param)String getString(param)
      • param:参数,有两种
        • columnIndex:列的序号,是从1开始
        • columnLabel:列的名称

    例子

    @Test
    public void testResultSet() throws Exception {
        String url = "jdbc:mysql:///db1";
        String username = "root";
        String password = "root1234";
    
        Connection conn = DriverManager.getConnection(url, username, password);
        // 3. 定义sql语句
        String sql = "select * from account";
    
        Statement statement = conn.createStatement();
    
        ResultSet rs = statement.executeQuery(sql);
    
        while (rs.next()) {
    //            根据列的序号获取
    //            int id = rs.getInt(1);
    //            String name = rs.getString(2);
    //            double money = rs.getDouble(3);
    //            根据列的名称获取
            int id = rs.getInt("id");
            String name = rs.getString("name");
            double money = rs.getDouble("money");
            System.out.println(id + " , " + name + " , " + money);
        }
        // 释放资源
        rs.close();
        statement.close();
        conn.close();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    5、PreparedStatement

    预编译sql并执行sql语句

    好处

    • 预编译sql,性能更高
    • 防止sql注入:将敏感字符进行了转义

    原理

    • 在获取PreparedStatement对象时,将sql语句发送给了mysql服务器进行检查,编译(这些步骤比较耗时)
    • 执行时就不用再进行这些步骤了,速度更快
    • 如果sql模板一样,则只需要进行一次检查、编译
    1. 获取PreparedStatement对象

      // sql语句里面的参数值使用?占位符替代
      String sql = "select * from tb_user where username= ? and password = ?";
      // 通过Connection对象传入对应的sql语句获取
      PreparedStatement prepareStatement = conn.prepareStatement(sql);
      
      • 1
      • 2
      • 3
      • 4
    2. 设置参数值 setXxx(p1,p2):给sql语句中?赋值

      • Xxx数据类型,如setInt(p1,p2)、setString(p1,p2)
      • 参数
        • p1: ? 占位符的位置序号,从1开始
        • p2: ?的值
    3. 执行sql

      • executeQuery() / executeUpdate() 在这里就不需要传递sql语句了

    例子

    @Test
    public void testPreparedStatement() throws Exception {
        //  useServerPrepStmts=true 开启预编译功能   
        String url = "jdbc:mysql:///db1?useServerPrepStmts=true";
        String username = "root";
        String password = "root1234";
    
        Connection conn = DriverManager.getConnection(url, username, password);
    
        String name = "zhangsan";
    //        String pwd = "' or '1' = '1";
        String pwd = "123";
    
        // 定义sql语句
        String sql = "select * from tb_user where username= ? and password = ?";
        // 获取 PreparedStatement 对象
        PreparedStatement prepareStatement = conn.prepareStatement(sql);
        // 给 ?设置值
        prepareStatement.setString(1, name);
        prepareStatement.setString(2, pwd);
        // 执行sql
        ResultSet rs = prepareStatement.executeQuery();
        if (rs.next()) {
            System.out.println("登陆成功");
        } else {
            System.out.println("登陆失败");
        }
        // 再次设置数据,并执行,在这里,就不需要进行检查编译了,
        prepareStatement.setString(1, "aaa");
        prepareStatement.setString(2, "pwd");
        rs = prepareStatement.executeQuery();
        if (rs.next()) {
            System.out.println("登陆成功");
        } else {
            System.out.println("登陆失败");
        }
    
        rs.close();
        prepareStatement.close();
        conn.close();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    这里用到了junit单元测试,需要在pom.xml中导入junit

    <dependencies>
        
        <dependency>
            <groupId>com.mysqlgroupId>
            <artifactId>mysql-connector-jartifactId>
            <version>8.0.33version>
        dependency>
    
        <dependency>
            <groupId>junitgroupId>
            <artifactId>junitartifactId>
            <version>RELEASEversion>
            <scope>compilescope>
        dependency>
    
    dependencies>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    参考文献

    1. 黑马程序员JavaWeb基础教程

  • 相关阅读:
    Linux防火墙之iptables(上)
    〖全域运营实战白宝书 - 运营角色认知篇③〗- 运营的底层逻辑是什么?
    树莓派4B_OpenCv学习笔记21:OpenCV_haar人脸识别
    Vue常用但记不住的操作
    简单线性回归(Simple Linear Regression)
    【TCP/IP】组播
    s28.CentOS、Ubuntu、Rocky Linux系统初始化脚本v6版本
    《LeetCode力扣练习》代码随想录——链表(设计链表---Java)
    Magic Bracelet-【群论】【Burnside引理】【矩阵快速幂】
    Js获取指定字符串指定字符位置&指定字符位置区间的子串【简单详细】
  • 原文地址:https://blog.csdn.net/ljp345775/article/details/133896306