Skip to content

二、全新JDBC核心API

1、引入mysql-jdbc驱动jar

驱动jar版本选择

mysql版本推荐驱动版本备注
mysql 5.5.x5.0.xcom.mysql.jdbc.Driver
mysql 5.7.x5.1.xcom.mysql.jdbc.Driver
msyql 8.x8.0.x建议: 8.0.25+省略时区设置 com.mysql.cj.jdbc.Driver

2、POM依赖

xml
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.18</version>
</dependency>

3、jdbc基本使用步骤分析

  1. 注册驱动
  2. 获取连接
  3. 创建发送sql语句对象
  4. 发送sql语句,并获取返回结果
  5. 结果集解析
  6. 资源关闭

4、基于statement实现查询

准备数据库数据

mysql
CREATE DATABASE xx_jdbc;

USE xx_jdbc;

CREATE TABLE t_user(
   id INT PRIMARY KEY AUTO_INCREMENT COMMENT '用户主键',
   account VARCHAR(20) NOT NULL UNIQUE COMMENT '账号',
   PASSWORD VARCHAR(64) NOT NULL COMMENT '密码',
   nickname VARCHAR(20) NOT NULL COMMENT '昵称');

INSERT INTO t_user(account,PASSWORD,nickname) VALUES
  ('root','123456','技术总监'),('admin','666666','CTO');
java
package com.xx;


import java.sql.*;

/**
 * @Author: xueqimiao
 * @Date: 2023/1/4 09:14
 */
public class JdbcBasePart {

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

        //1.注册驱动
        /**
         * TODO: 注意
         *   Driver -> com.mysql.cj.jdbc.Driver
         */
        DriverManager.registerDriver(new com.mysql.cj.jdbc.Driver());

        //2.获取连接
        /**
         *   面向接口编程
         *   java.sql 接口 = 实现类
         *   connection 使用java.sql.Connection接口接收
         */
        Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/xx_jdbc",
                "root",
                "mac_root");

        //3.创建小车
        Statement statement = connection.createStatement();

        //4.发送SQL语句
        String sql = "select id,account,password,nickname from t_user ;";
        ResultSet resultSet = statement.executeQuery(sql);

        //5.结果集解析
        while (resultSet.next()) {
            int id = resultSet.getInt("id");
            String account = resultSet.getString("account");
            String password = resultSet.getString("password");
            String nickname = resultSet.getString("nickname");
            System.out.println(id + "\t" + account + "\t" + password + "\t" + nickname);
        }

        //6.关闭资源  【先开后关】
        resultSet.close();
        statement.close();
        connection.close();

    }
}

5、基于statement方式问题

模拟登录,控制台输入账号和密码,判断是否登陆成功成功!

java
package com.xx;

import java.sql.*;
import java.util.Scanner;

/**
 * @Author: xueqimiao
 * @Date: 2023/1/4 09:23
 */
public class JdbcStatementLoginPart {

    public static void main(String[] args) throws ClassNotFoundException, SQLException {

        //1.输入账号和密码
        Scanner scanner = new Scanner(System.in);
        String account = scanner.nextLine();
        String password = scanner.nextLine();
        scanner.close();

        //2.jdbc的查询使用
        /**
         * 类加载: java文件 -> 编译 -> 【 class字节码文件 -->  类加载 --> jvm虚拟中  --> Class对象】
         * 类加载具体步骤:  加载 【class文件转成对象加载到虚拟机中】->
         *                连接 【验证(检查类文件) -> 准备 (静态变量赋默认值) -> 解析 (调用静态代码块) 】 ->
         *                初始化 -> (赋真实值)
         * 以下7种方式会触发类加载:
         *    1. new关键字
         *    2. 调用静态属性
         *    3. 调用静态方法
         *    4. 接口 包含1.8 新特性 default关键字
         *    5. 反射 【Class.forName() 类名.class】
         *    6. 子类调用会触发父类的静态代码块
         *    7. 触发类的入口方法main
         */
        //注册一次驱动
        Class.forName("com.mysql.cj.jdbc.Driver");


        /**
         * 重写: 为了子类扩展父类的方法!父类也间接的规范了子类方法的参数和返回!
         * 重载: 重载一般应用在第三方的工具类上,为了方便用户多种方式传递参数形式!简化形式!
         */
        /**
         * 三个参数:
         *    String URL: 连接数据库地址
         *    String user: 连接数据库用户名
         *    String password: 连接数据库用户对应的密码
         * 数据库URL语法:
         *    JDBC:
         *        ip port
         *        jdbc:mysql | jdbc:oracle :// 127.0.0.1 | localhost : 3306 / 数据库名
         *        jdbc:mysql://localhost:3306/xx_jdbc
         *        192.168.33.45
         *        jdbc:mysql://192.168.33.45/3306/xx_jdbc
         *        当前电脑的省略写法! 注意:本机和端口3306
         *        jdbc:mysql://localhost:3306/xx_jdbc = jdbc:mysql:///xx_jdbc
         *
         * 两个参数:
         *     String URL : 写法还是jdbc的路径写法!
         *     Properties : 就是一个参数封装容器!至少要包含 user / password key!存储连接账号信息!
         *
         * 一个参数:
         *    String URL: URl可以携带目标地址,可以通过?分割,在后面key=value&key=value形式传递参数
         *                jdbc:mysql:///xx_jdbc?user=root&password=123456
         * 扩展路径参数(了解):
         *    serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8&useSSL=true
         *
         */
        //获取连接
        Connection connection = DriverManager.getConnection("jdbc:mysql:///xx_jdbc", "root", "mac_root");

        //固定方法固定剂
        //创建statement
        Statement statement = connection.createStatement();

        //执行SQL语句 [动态SQL语句,需要字符串拼接]
        String sql = "select * from t_user where account = '" + account + "' and password = '" + password + "' ;";


        /**
         *  ResultSet 结果集对象 = executeQuery(DQL语句)
         *  int       响应行数  = executeUpdate(非DQL语句)
         */
        ResultSet resultSet = statement.executeQuery(sql);


        //ResultSet == 你必须有面向对象的思维:Java是面向对象编程的语言 OOP!
        /**
         *
         * TODO:1.需要理解ResultSet的数据结构和在navicat中查询出来的是一样,需要在脑子里构建结果表!
         * TODO:2.有一个光标指向的操作数据行,默认指向第一行的上边!我们需要移动光标,指向行,在获取列即可!
         *        boolean = next()
         *              false: 没有数据,也不移动了!
         *              true:  有更多行,并且移动到下一行!
         *       推荐:推荐使用if 或者 while循环,嵌套next方法,循环和判断体内获取数据!
         *       if(next()){获取列的数据!} ||  while(next()){获取列的数据!}
         *
         *TODO:3.获取当前行列的数据!
         *         get类型(int columnIndex | String columnLabel)
         *        列名获取  //lable 如果没有别名,等于列名, 有别名label就是别名,他就是查询结果的标识!
         *        列的角标  //从左到右 从1开始! 数据库全是从1开始!
         */

        //进行结果集对象解析
        if (resultSet.next()) {
            //只要向下移动,就是有数据 就是登录成功!
            System.out.println("登录成功!");
        } else {
            System.out.println("登录失败!");
        }

        //关闭资源
        resultSet.close();
        statement.close();
        connection.close();
    }
}
java
admin
666666
登录成功!

admin
123456 'or 1='1
登录成功!

1、存在问题

  1. SQL语句需要字符串拼接,比较麻烦

  2. 只能拼接字符串类型,其他的数据库类型无法处理

  3. 可能发生注入攻击

    动态值充当了SQL语句结构,影响了原有的查询结果!

6、基于preparedStatement方式优化

利用preparedStatement解决上述案例注入攻击和SQL语句拼接问题!

java
package com.xx;

import java.sql.*;
import java.util.Scanner;

/**
 * @Author: xueqimiao
 * @Date: 2023/1/4 09:30
 */
public class JdbcPreparedStatementLoginPart {

    public static void main(String[] args) throws ClassNotFoundException, SQLException {

        //1.输入账号和密码
        Scanner scanner = new Scanner(System.in);
        String account = scanner.nextLine();
        String password = scanner.nextLine();
        scanner.close();

        //2.jdbc的查询使用
        //注册驱动
        Class.forName("com.mysql.cj.jdbc.Driver");

        //获取连接
        Connection connection = DriverManager.getConnection("jdbc:mysql:///xx_jdbc", "root", "mac_root");

        //创建preparedStatement
        //connection.createStatement();
        //TODO 需要传入SQL语句结构
        //TODO 要的是SQL语句结构,动态值的部分使用 ? ,  占位符!
        //TODO ?  不能加 '?'  ? 只能替代值,不能替代关键字和容器名
        String sql = "select * from t_user where account = ? and password = ? ;";
        PreparedStatement preparedStatement = connection.prepareStatement(sql);

        //占位符赋值
        //给占位符赋值! 从左到右,从1开始!
        /**
         *  int 占位符的下角标
         *  object 占位符的值
         */
        preparedStatement.setObject(2, password);
        preparedStatement.setObject(1, account);

        //这哥们内部完成SQL语句拼接!
        //执行SQL语句即可
        ResultSet resultSet = preparedStatement.executeQuery();
        //preparedStatement.executeUpdate()

        //进行结果集对象解析
        if (resultSet.next()) {
            //只要向下移动,就是有数据 就是登录成功!
            System.out.println("登录成功!");
        } else {
            System.out.println("登录失败!");
        }

        //关闭资源
        resultSet.close();
        preparedStatement.close();
        connection.close();
    }
}

img

7、基于preparedStatement增删改查

1、新增

java
/**
     * 插入一条用户数据!
     * 账号: test
     * 密码: test
     * 昵称: 测试
     */
@Test
public void testInsert() throws Exception {

    //注册驱动
    Class.forName("com.mysql.cj.jdbc.Driver");

    //获取连接
    Connection connection = DriverManager.getConnection("jdbc:mysql:///xx_jdbc", "root", "mac_root");

    //TODO: 切记, ? 只能代替 值!!!!!  不能代替关键字 特殊符号 容器名
    String sql = "insert into t_user(account,password,nickname) values (?,?,?);";
    PreparedStatement preparedStatement = connection.prepareStatement(sql);

    //占位符赋值
    preparedStatement.setString(1, "test");
    preparedStatement.setString(2, "test");
    preparedStatement.setString(3, "测试");

    //发送SQL语句
    int rows = preparedStatement.executeUpdate();

    //输出结果
    System.out.println(rows);

    //关闭资源close
    preparedStatement.close();
    connection.close();
}

2、修改

java
/**
     * 修改一条用户数据!
     * 修改账号: test的用户,将nickname改为tomcat
     */
@Test
public void testUpdate() throws Exception {

    //注册驱动
    Class.forName("com.mysql.cj.jdbc.Driver");

    //获取连接
    Connection connection = DriverManager.getConnection("jdbc:mysql:///xx_jdbc", "root", "mac_root");

    //TODO: 切记, ? 只能代替 值!!!!!  不能代替关键字 特殊符号 容器名
    String sql = "update t_user set nickname = ? where account = ? ;";
    PreparedStatement preparedStatement = connection.prepareStatement(sql);

    //占位符赋值
    preparedStatement.setString(1, "tomcat");
    preparedStatement.setString(2, "test");

    //发送SQL语句
    int rows = preparedStatement.executeUpdate();

    //输出结果
    System.out.println(rows);

    //关闭资源close
    preparedStatement.close();
    connection.close();
}

3、删除

java
/**
     * 删除一条用户数据!
     * 根据账号: test
     */
@Test
public void testDelete() throws Exception {

    //注册驱动
    Class.forName("com.mysql.cj.jdbc.Driver");

    //获取连接
    Connection connection = DriverManager.getConnection("jdbc:mysql:///xx_jdbc", "root", "mac_root");

    //TODO: 切记, ? 只能代替 值!!!!!  不能代替关键字 特殊符号 容器名
    String sql = "delete from t_user where account = ? ;";
    PreparedStatement preparedStatement = connection.prepareStatement(sql);

    //占位符赋值
    preparedStatement.setString(1, "test");

    //发送SQL语句
    int rows = preparedStatement.executeUpdate();

    //输出结果
    System.out.println(rows);

    //关闭资源close
    preparedStatement.close();
    connection.close();
}

4、查询

java
/**
     * 查询全部数据!
     * 将数据存到List<Map>中
     * map -> 对应一行数据
     * map key -> 数据库列名或者别名
     * map value -> 数据库列的值
     *    1.先创建一个List<Map>集合
     *    2.遍历resultSet对象的行数据
     *    3.将每一行数据存储到一个map对象中!
     *    4.将对象存到List<Map>中
     *    5.最终返回
     * <p>
     *    学习获取结果表头信息(列名和数量等信息)
     */
@Test
public void testQueryMap() throws Exception {

    //注册驱动
    Class.forName("com.mysql.cj.jdbc.Driver");

    //获取连接
    Connection connection = DriverManager.getConnection("jdbc:mysql:///xx_jdbc", "root", "mac_root");

    //TODO: 切记, ? 只能代替 值!!!!!  不能代替关键字 特殊符号 容器名
    String sql = "select id,account,password,nickname from t_user ;";
    PreparedStatement preparedStatement = connection.prepareStatement(sql);

    //占位符赋值 本次没有占位符,省略

    //发送查询语句
    ResultSet resultSet = preparedStatement.executeQuery();

    //创建一个集合
    List<Map> mapList = new ArrayList<>();

    //获取列信息对象
    ResultSetMetaData metaData = resultSet.getMetaData();
    int columnCount = metaData.getColumnCount();
    while (resultSet.next()) {
        Map map = new HashMap();
        for (int i = 1; i <= columnCount; i++) {
            map.put(metaData.getColumnLabel(i), resultSet.getObject(i));
        }
        mapList.add(map);
    }

    System.out.println(mapList);

    //关闭资源close
    preparedStatement.close();
    connection.close();
    resultSet.close();
}