【JDBC系列 jdbc的概念以及与数据库的交互流程

2023年 7月 16日 107.1k 0

jdbc的概念以及与数据库的交互流程

😄生命不息,写作不止

🔥 继续踏上学习之路,学之分享笔记

👊 总有一天我也能像各位大佬一样

🏆 博客首页   @怒放吧德德  To记录领地

🌝分享学习心得,欢迎指正,大家一起学习成长!

jdbc1.jpg

引言

人总是向前走的,目标是更上一层楼。原本笔者奔着一颗炙热的心去学习mybatis底层原理,无奈看了一章感觉我还是太菜了,没有对jdbc有个基础的了解,看起来就比较吃力,因此这次就来学习一下jdbc。本次所学习的大致内容是jdbc的概念与理解,以及如何去使用jdbc来实现Java程序和数据库进行打交道。

JDBC的概念

JDBC(Java Database Connectivity),它是Java编程语言中用于连接和操作数据库的API。JDBC提供了一组类和接口,允许Java应用程序与各种关系型数据库进行通信。它提供了一种标准化的方式来与数据库交互。

1、jdbc与数据的交互

Java程序通过jdbc这个规范(接口)来与第三方数据库厂商进行交互,根据jdbc规范根据具体的实现驱动代码,不同厂商数据库的驱动代码不同,但是方法是相同的。jdbc是一组接口,最终实现是由各个数据库厂商(jar)来实现的,是一种面向接口编程。无论是MySQL、Oracle、SQL Server还是其他关系型数据库系统,只需要切换对应的数据库驱动jar包。

image-20230715220756994.png

2、jdbc的一些概念

接下来就了解一些主要的概念,包括驱动、连接、语句、结果集等。

  • 数据库驱动程序(Database Driver):数据库驱动程序是实现JDBC接口的软件组件,它允许Java应用程序与特定类型的数据库进行通信。不同的数据库供应商提供不同的驱动程序实现。
  • 连接(Connection):连接是通过JDBC与数据库建立的会话。它表示Java应用程序与数据库之间的通信通道。使用连接,应用程序可以执行SQL语句并获取结果。
  • 语句(Statement):语句是在数据库上执行的SQL命令。JDBC提供了多种语句类型,包括普通语句(Statement)、预编译语句(PreparedStatement)和可调用语句(CallableStatement)等。应用程序可以使用这些语句来执行查询、更新、插入和删除等操作。
  • 结果集(ResultSet):结果集是从数据库检索到的数据集合。它是通过执行查询语句获得的,并且提供了一种迭代的方式来遍历和访问结果。
  • 批处理(Batch Processing):JDBC支持批处理操作,它允许一次执行多个SQL语句。这对于批量插入、更新或删除数据非常有用,可以提高性能和效率。
  • 事务(Transaction):事务是一组数据库操作,它们要么全部成功执行,要么全部回滚(撤销)。JDBC支持事务管理,可以通过开始事务、提交事务或回滚事务来确保数据的一致性和完整性。
  • 使用核心API - statement

    在JDBC中,statement(语句)是用于执行SQL命令的接口之一。它用于执行静态SQL语句1,即在编译时已经确定的SQL语句,不允许参数化。

    1、jdbc是如何进行与数据库通信的呢?

    jdbc是Java程序与数据库交互的一个桥梁,完成通信需要通过六个步骤:
    ①、加载驱动程序,需要加载适用于特定数据库的驱动程序,本次是使用mysql8.0,所以需要加载mysql-connector-java-8.0.27.jar包。
    ②、建立连接,通过驱动去建立连接,可以理解为这样就会有一条与数据库服务器交互的管道。实际上就是使用数据库连接URL指定数据库的地址、端口和其他连接参数,通过TCP/IP协议建立与数据库服务器的连接。
    ③、创建Statement或PreparedStatement对象,这个对象是存储sql语句,可以理解为是一个搭载sql语句的盒子,需要被送到数据库服务器中执行。
    ④、执行SQL语句,需要将statement对象通过连接通道送到数据库服务器执行sql语句并且返回结果集。
    ⑤、处理结果,将返回的结果集resultSet进行解析处理。
    ⑥、关闭资源,使用完Statement、PreparedStatement、ResultSet和连接等资源后,需要调用它们的close()方法来关闭资源。关闭资源可以释放数据库连接和相关的系统资源。

    image-20230715225147420.png

    以上这张图简单的画出了jdbc与数据库通信的流程步骤。

    2、用代码实现jdbc与数据库通信步骤

    接下来就简单使用一个demo来实现以上jdbc与数据的通信步骤,主要是通过驱动管理器DriverManager来注册驱动和建立连接,在建立连接的时候需要传入数据库服务器url和用户名、密码、数据库信息,与navicat的连接是差不多的,只是使用java代码来实现,然后创建statement对象去执行sql语句,并且能获得一个ResultSet对象的结果集,里面有next()方法用来移动游标输出数据,当开始是指向第一行数据之前,next()将游标往下移动一行,接着通过getString(columnLabel)等方法获取每行的列数据。

    准备数据

    需要准备数据库,这里用一张tb_user的表来做测试,里面就只有id、name、address三个字段。

    image-20230716131453492.png

    代码如下

    package cn.lyd.jdbc;
    import com.mysql.cj.jdbc.Driver;
    import java.sql.*;
    /**
     * @Author: lyd
     * @Description: Jdbc - statement使用
     * @Date: 2023/7/15
     */
    public class JdbcDemo {
        /**
         * DriverManager
         * Connection
         * Statement
         * ResultSet
         * @param args
         */
        public static void main(String[] args) throws SQLException {
            // 1、注册驱动
            /**
             * 注册驱动,如果是8.0+就使用com.mysql.cj.jdbc.Driver
             */
            DriverManager.registerDriver(new Driver());
            // 2、获取连接
            /**
             * 连接数据库需要填入数据库ip地址,端口号,用户名,密码,连接的数据库名称
             */
            Connection connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/cloud_user", "root", "12356");
    
            // 3、创建statement
            Statement statement = connection.createStatement();
    
            // 4、发送sql语句并执行
            String sql = "select * from tb_user;";
            ResultSet resultSet = statement.executeQuery(sql);
            // 5、解析结果集
            /**
             * 有没有下行数据
             */
            while (resultSet.next()) { // 最开始指定的是数据的上一行即起始位置,并无数据,.next方法会将游标往下移动一行。
                long id = resultSet.getLong("id");
                String username = resultSet.getString("username");
                String address = resultSet.getString("address");
                System.out.println(id + " - " + username + " - " + address);
            }
    
            // 6、关闭资源
            resultSet.close();
            statement.close();
            connection.close();
        }
    }
    
    

    执行结果

    通过控制台输出获取得到的数据

    image-20230716131544439.png

    详细介绍使用核心API - statement

    接下来详细介绍以下流程步骤中的一些小问题与小细节。

    1、注册驱动

    注册驱动,可以通过驱动管理(DriverManager)的 DriverManager.registerDriver(new Driver());方法来实现。这样的注册驱动就会出现驱动被注册了两次,我们看一下DriverManager.registerDriver()方法内容

    public static synchronized void registerDriver(java.sql.Driver driver)
        throws SQLException {
    
        registerDriver(driver, null);
    }
    

    再看一下new Driver()的时候,在Driver.class里面的静态代码块也是会注册一次驱动。

    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!");
            }
        }
    }
    

    对于这个问题,我们只要让Driver的静态代码块执行就行了。这里我们就要先了解以下静态代码块是何时触发的呢?

    静态代码块的执行时期:

    类的加载机制:在类的加载的时候会执行静态代码块。简单的介绍一下步骤:

    ​ 1、加载(Loading):将类的字节码文件加载到内存中。

    ​ 2、链接(Linking):链接又分了三个阶段,验证(Verification):对加载的字节码进行验证,确保其符合Java虚拟机规范,不会造成安全或运行时错误;准备(Preparation):为类的静态变量分配内存空间,并设置默认初始值;解析(Resolution):将符号引用(Symbolic References)解析为直接引用(Direct References),即将类、方法、字段等符号引用解析为内存中的实际数据。

    ​ 3、初始化(Initialization):对类进行初始化,包括静态变量的赋值和静态代码块的执行。

    触发类加载:

    ​ 1、通过new关键字;2、调用了静态方法;3、调用了静态属性;4、jdk1.8的接口加上了default关键字;5、反射;6、子类触发父类;7、程序的入口main。

    驱动重复注册的解决

    显然我们就不能直接使用DriverManager.registerDriver(new Driver()); 来直接注册驱动,我们如果想不使它重复注册,可以让他只是执行一次静态代码块直接new Driver() ,当然这样做的也有弊端,如果我们使用的不是mysql我们就要导入对应的包,就显得不太灵活。

    image-20230716144510821.png

    换种方式,我们可以使用反射的机制来实现。当使用不同的数据库,就只要更换一下驱动的全类名,这个字符串是可以提出来作为一种可配置的参数,这样就比较灵活了。

    Class.forName("com.mysql.cj.jdbc.Driver");
    

    2、获取连接

    我们可以看到DriverManager.getconnection()重载了三个方法。三个方法的效果是一样的,只是携带的参数写法并不相同。

    image-20230716145004432.png

    1)、getConnection(String url, String user, String password)

    我们需要将数据库服务器的地址,用户名,密码传入就能建立连接。用户名和密码没什么可说的,就是登录凭证。就是这个url地址,这个地址的组成是:

    jdbc:数据库管理软件名称://ip地址|主机名:port端口号/数据库?key=value&key=value,后面是可选参数。
    如果是localhost:3306可以替换成  jdbc:数据库管理软件名称:///数据库
    

    这个方法实现,传进来的用户名密码,最后也是放到了java.util.Properties这个对象之中。

    @CallerSensitive
    public static Connection getConnection(String url,
        String user, String password) throws SQLException {
        java.util.Properties info = new java.util.Properties();
    
        if (user != null) {
            info.put("user", user);
        }
        if (password != null) {
            info.put("password", password);
        }
    
        return (getConnection(url, info, Reflection.getCallerClass()));
    }
    

    2)、getConnection(String url, java.util.Properties info)

    这个方法与上一个不一样的是,将用户和密码在调用的时候直接放入java.util.Properties这个对象之中,

    Properties properties = new Properties();
    properties.put("user", "root");
    properties.put("password", "root");
    DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/cloud_user", properties);
    

    3)、getConnection(String url)

    这个方法就是把所有的需要的参数都放在这个url里头了,其组成如下:

    jdbc:数据库管理软件名称://ip地址|主机名:port端口号/数据库?user=value&password=value
    

    3、创建Statement对象

    通过连接connection去创建,就能够获得一个statement对象。并且需要一条sql语句的字符串。

    Statement statement = connection.createStatement();
    

    4、发送SQL语句

    String sql = "SELECT * FROM tb_user WHERE username = 'lyd';";
    int i = statement.executeUpdate(sql);
    ResultSet resultSet = statement.executeQuery(sql);
    

    当使用的是executeUpdate就会返回一个int数值,使用executeQuery将会返回一个结果集。

    我们需要根据不用的SQL类型去使用对应的方法,在statement接口中已经标明了注释。

    使用executeQuery:如果发送的sql语句是静态sql SELECT语句,返回的结果就是包含给定查询产生的数据的ResultSet对象,如果是没有数据,那就返回为null。

    使用executeUpdate:如果语句是SQL数据操作语言(DML)语句,(INSERT、UPDATE或DELETE);或者是不返回任何结果的SQL语句,比如DDL语句。返回的结果就是数据操作语言(DML)语句的行数,没有就是返回0。

    image-20230716160924816.png

    学习一下SQL主要的分类:

    数据定义语言(Data Definition Language,DDL):DDL用于创建和管理数据库对象,如表、视图、索引等。常见的DDL语句包括CREATE(创建)、ALTER(修改)、DROP(删除)等。

    数据操作语言(Data Manipulation Language,DML):DML用于查询和操作数据库中的数据记录。它包括SELECT(查询)、INSERT(插入)、UPDATE(更新)、DELETE(删除)等语句,用于从数据库中检索、插入、更新和删除数据。

    数据控制语言(Data Control Language,DCL):DCL用于管理数据库的访问权限和安全性。它包括GRANT(授权)和REVOKE(撤销授权)等语句,用于控制用户对数据库对象的访问权限。

    事务控制语言(Transaction Control Language,TCL):TCL用于控制数据库中的事务处理。它包括BEGIN TRANSACTION(开始事务)、COMMIT(提交事务)、ROLLBACK(回滚事务)等语句,用于确保数据库操作的原子性、一致性、隔离性和持久性。

    除了上述常见的分类,SQL还可以根据具体的数据库系统和实现方式进行进一步分类,如存储过程语言(Stored Procedure Language)、游标语言(Cursor Language)等。每种类型的SQL语句都有其特定的语法和功能,开发人员可以根据需要选择合适的语句来进行数据库操作。

    5、解析结果集

    当查询找到了所需要的数据,就会将找到的数据封装到ResultSet对象,结果集ResultSet对象维护一个指向其当前数据行的游标。最初,游标位于第一行之前。next方法将光标移动到下一行,因为当ResultSet对象中没有更多的行时,它返回false,所以可以在while循环中使用它来遍历结果集。

    我们通过断点可以看到,刚开始结果集指向的当前行是-1,代表是具体数据的上一行。

    image-20230716162104620.png

    我们通过while循环去遍历数据,并且使用next将游标移动到下行,如果有数据,此时结果集就指向了数据行。

    通过resultSet.getLong(columnIndex|columnLabel)来获取对应类型的数据,这个get属性可以使用两种方式来获取:

    ①、通过列数据的下标,这个下标是从1开始。

    ②、通过列标签,这里的列标签可以是列名也可以是别名,当sql语句中使用了AS 给字段取别名时,这就需要使用别名了。

    while (resultSet.next()) {
        long aLong = resultSet.getLong(1);
        String username = resultSet.getString("username");
    
        System.out.println("id: " + aLong + ", username: " + username);
    }
    

    6、关闭资源

    当使用完之后就需要将资源进行销毁

    // 6、关闭资源
    resultSet.close();
    statement.close();
    connection.close();
    

    总结

    使用jdbc与数据库进行通信,简单来说就只有6个步骤,首先需要注册驱动,获取连接,接着创建statement对象,用来存放sql语句并且执行,然后将获得到的数据进行解析,最后就是要把资源进行销毁。这里只是基本的使用jdbc,像mybatis、jpa、ibatis等持久层框架,都是对jdbc进行封装,万变不离其宗,想要学习底层知识,就需要把这学基础知识给学好!

    相关文章

    JavaScript2024新功能:Object.groupBy、正则表达式v标志
    PHP trim 函数对多字节字符的使用和限制
    新函数 json_validate() 、randomizer 类扩展…20 个PHP 8.3 新特性全面解析
    使用HTMX为WordPress增效:如何在不使用复杂框架的情况下增强平台功能
    为React 19做准备:WordPress 6.6用户指南
    如何删除WordPress中的所有评论

    发布评论