【JDBC】Statement使用步骤详解

一、需求

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

image-20240725120822033
/**
 * TODO:
 *  1.明确jdbc的使用流程 和 详解讲解内部设计api方法
 *  2.发现问题,引出preparedstatement
 *
 * TODO
 *  输入密码账号
 *  进行数据库信息查询
 *  反馈登录成功还是登录失败
 *
 *  TODO:
 *      1.键盘输入事件,收集账号和密码信息
 *      2.注册驱动
 *      3.获取链接
 *      4.创建statement
 *      5.发送查询SQL语句,并获取返回结果
 *      6.结果判断,显示登陆成功还是失败
 *      7.关闭资源
 */

二、注册驱动

方案一:调用静态方法,但是会注册两个

DriverManager.registerDriver(new com.cj.jdbc.Driver())
  注意:8+  ——>  com.mysql.cj.jdbc.Driver
       5+  ——>  com.mysql.jdbc.Driver
问题:在DriverManager.registerDriver方法中,会注册一次驱动: registerDriver(driver, null);
     在Driver类中的静态代码块中,也会注册一次驱动:DriverManager.registerDriver(new Driver());
     这样就造成了一个性能消耗的问题

如下图,registerDriver 方法中进行了一次驱动注册

image-20240725122043637

Driver类 中的静态代码块也会调用注册驱动

image-20240725122215334

也就是说,我们其实会注册两个驱动,这个就属于性能消耗了。

大家思考一个问题,我们一定要用到这个驱动类,那只要用到了这个驱动类,就一定会触发静态代码块,也就是说我们不要去触发 DriverManager.registerDriver() 方法了

解决问题:只想注册一次
         只触发静态代码块即可!Driver
触发静态代码块:
        类加载机制:类加载的时刻,会触发静态代码块!
        加载 [class文件 -> jvm虚拟机的class对象]
        链接 [验证(检查文件类型) -> 准备(静态变量默认值) -> 解析(触发静态代码块)]
        初始化 (给静态属性赋真实值)
触发类加载:
    1.new 关键字
    2.调用静态方法
    3.调用静态属性
    4.接口 1.8以后新特性 加default默认实现
    5.反射
    6.子类触发父类
    7.程序的入口main

方案二:通过反射机制,触发类加载,触发静态代码块的调用

// new Driver();//只会触发一次,但这样写非常不雅,代码就很固定化
// 因为当前导的是mysql新版本的驱动,但如果有一天换成了oracle数据库,这个类就要改成oracle的类,就很不方便
Class.forName("com.mysql.cj.jdbc.Driver"); // 通过反射机制,触发类加载,触发静态代码块的调用
// 由于这里使用的是字符串,以后字符串 -> 提取到外部的配置文件 -> 可以在不改代码的情况下,完成数据库驱动的切换! -> 这样就很灵活

三、获取数据库连接重载方法对比

发现,DriverManager.getConnection() 是一个重载方法,即同名不同参,有三种参数传递形式,允许开发者,用不同的形式传入数据库连接的核心参数!

PS:这三种只是参数传递的形式不同,但最终选择哪种都无所谓。

image-20240725124858732

核心属性:
     1.数据库软件所在的主机的ip地址:127.0.0.1,或者本机的主机名:localhost
     2.数据库软件所在的主机的端口号:3306
     3.连接的具体库:itcast
     4.连接的账号:root
     5.连接的密码:123456
     6.可选的信息:稍后说

三个参数

String url         数据库软件所在的信息,连接的具体库,以及其他可选信息
                   语法:jdbc:数据库管理软件名称[mysql,oracle]://ip地址|主机名:port端口号/数据库名?key=value&key=value	以 key-value形式填入可选信息!
                   必须以jdbc开头,它代表这个是连接JDBC的一种路径协议
                   示例 : jdbc:mysql://127.0.0.1:3306/itcast
                           jdbc:mysql://localhost:3306/itcast
                   本机的省略写法:(强调:必须是本机,并且端口号是3306方可省略 使用///)
                   PS:如果没省略却使用了///则一定会报错。而且既然要省略,ip地址和prot必须都省略,不能只省略一个。
                   如果你的数据库软件安装到本机,可以进行一些省略
                   jdbc:mysql:///itcast
String user       数据库的账号 root
String password   数据库的密码 123456

示例

Connection connection = DriverManager.getConnection("jdbc:mysql:///itcast", "root", "123456");

两个参数(更麻烦一些,推荐三个参数)

String url :次url和三个参数的url的作用一样!
Properties info:存储账号和密码
                Properties 类似于 Map 只不过key = value 都是字符串形式的
                key user:账号信息
                key password:密码信息

我们可以来看一下源码的参数介绍

image-20240725130330552

示例

Properties info = new Properties();
info.put("user", "root");
info.put("password", "123456");
Connection connection2 = DriverManager.getConnection("jdbc:mysql://localhost:3306/itcast", info);

一个参数

String url:数据库ip,端口号,具体的数据库  可选信息(账号密码)
            jdbc:mysql/localhost:3306/itcast?user=root&password=123456;
            携带固定的参数名 user password  传递账号和密码信息![规定!]
 url的路径属性可选信息:
        url?user=账号&password=密码
        8.0.27版本驱动,下面都是一些可选属性!
        8.0.25以后,自动识别时区!serverTimezone=Asia/Shanghai 不用添加!8.0.25之前版本,下面一句话还是要加的!
        8版本以后,默认使用的就是utf-8格式,useUnicode=true&characterEncoding=utf8&useSSL=true 都可以省略了!
        时区:会影响数据库插入时间类型的时间、编码格式是不是UFT-8、忽略SSL格式验证
        
        我们使用的是8.0.27版本,下面这些其实都可以省略了
        serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8&useSSL=true

示例

Connection connection3 = DriverManager.getConnection("jdbc:mysql://localhost:3306/itcast?user=root&password=123456");

四、发送SQL语句的方法

statement发送SQL语句有很多种方法

image-20240725141041893

我们需要根据不同的SQL类型进行原则。

executeUpdate :返回值是一个int类型。

executeQuery:返回值是一个ResultSet。

到底使用哪种方式呢?我们来看一下源码的介绍就明白了。

1)executeUpdate

image-20240725141603640

总结:

SQL分类:DDL(容器创建,修改,删除) DML(增删改) DQL(查询) DCL(权限控制) TPL(事务控制语句)
参数:sql 非DQL
返回结果:int
     情况1:DML 返回影响的行数,例如;删除了三条数据 return 3;插入了两条 return 2;
     情况2:非DML return 0;

2)executeQuery

image-20240725142929212

总结:

参数:sql DQL
返回:resultSet 结果封装对象
ResultSet resultSet = executeQuery(sql);

3)总结

DQL选择 executeQuery,非DQL选择 executeUpdate


五、查询结果集解析 resultSet

我们之前在图形化界面中查询出来的结果如下图,是有行有列的。

image-20240725144013202

但是到了Java代码中,它没有办法使用这种可视化帮我们展示,它只能用Java的面向对象的思维,将查询结果封装成了resultSet对象,我们应该理解,内部一定也是有行和有列的!和可视化工具是一样的!只不过是同样的结果,不同的体现形式而已。


1)获取行

resultSet -> 逐行获取数据,行 -> 行的列的数据

我们可以来看看 resultSet 的源码

image-20240725145457364

最初resultSet的 cursor(光标) 会指向第一行的前一行,next() 方法即将 cursor 移向下一行

若下一行有数据,返回 true,若下一行没数据,则返回 false

总结:

想要进行数据解析,我们需要进行两件事情:1.移动游标指定获取数据行  2.获取指定数据行的列数据即可
游标移动问题
     resultSet内部包含一个游标,指定当前行数据!
     默认游标指定的是第一行数据之前!
     我们可以调用next()方法向后移动一行游标!
     如果我们有很多行数据,我们可以使用while(next){获取每一行数据}
     boolean = next() true:有更多行数据,并且向下移动一行
                      false:没有更多行数据,不移动!

来看一下 next() 的源码

image-20240725151618262

其实还有一个方法叫 previos,可以将光标往前移。

image-20240725151752052
TODO:移动光标的方法有很多,只需要记next即可,配合while循环获取全部数据!

2)获取列

resultSet.get类型(String columnLabel | int columnIndex);

columnLabel:列名,如果有别名,写别名

columnIndex:列的下标获取,从左向右,从1开始

image-20240725154947664

六、代码实现

package com.atguigu.api.statement;

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

public class StatementUserLoginPart {
    public static void main(String[] args) throws SQLException, ClassNotFoundException {
        //1.获取用户输入信息
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入账号");
        String account = scanner.nextLine();
        System.out.println("请输入密码");
        String password = scanner.nextLine();


        // 1.注册驱动
        Class.forName("com.mysql.cj.jdbc.Driver");//通过反射机制,触发类加载,触发静态代码块的调用

        // 2.获取数据库链接
        Connection connection = DriverManager.getConnection("jdbc:mysql:///itcast", "root", "123456");

        //3.创建发送SQL语句的statement对象
        //statement 可以发送SQL语句到数据库,并且可以返回结果!
        Statement statement = connection.createStatement();

        //4.发送SQL语句(1.编写SQL语句 2.发送SQL语句)
        String sql = "select * from employee where account = '" + account + "' and password = '" + password + "';";
        ResultSet resultSet = statement.executeQuery(sql);
        statement.executeUpdate(sql);

        //5.查询结果集解析 resultSet
        /*while(resultSet.next()) {
            int id = resultSet.getInt(1);
            int salary = resultSet.getInt("salary");
            System.out.println(id + "--" + salary);
        }*/

        //但是当前需求下,没有必要使用while循环去遍历结果集,我们只需要移动一次光标,只要有数据,就代表登录成功
        if (resultSet.next()) {
            System.out.println("登陆成功");
        } else {
            System.out.println("登录失败");
        }

        //关闭资源,规则:先开的流最后关闭
        connection.close();
        statement.close();
        resultSet.close();
    }
}
  • 14
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值