• 【Java】JDBC基础使用教程


    一、JDBC简介

    JDBC 通过Java代码来操作数据库

    实际工作中大部分的数据库操作,都是通过代码来完成的.格子编程语言都可以操作数据库,主要是数据库提供了各种版本的API(一组函数 / 一组类),调用这些API就可以操作数据库。

    但是我们要注意:数据库的种类有许多,不同的数据库,提供的API不太一样(因为不同的数据库是不同的厂商实现的)

    在这里插入图片描述
    程序员,要想通过代码来操作不同的数据库,就需要写多份代码,操作数据库1(写一份代码),操作数据库二(写一份代码),这样造成开发成本变高,学习成本变高。
    在这里插入图片描述
    那么我们想解决这个:很多编程语言的做法,就是把各种数据库的API再次封装一层,封装出一套统一的API,其中JAVA里面,这样的封装就是由Java标准库来完成的,此时这一套封装,称为JDBC

    更准确的说JDBC就是Java标准库提供的API,这组API相当于把不同的数据库都统一成一种风格了,通过这一组API,就可以操作任何数据库(不需要关心数据库与数据库之间,API细节的差异了)


    二、JDBC原理

    这里看一个图:

    了解了上面,我们开始进行JDBC开发。

    JDBC API 是标准库自带的,直接使用


    二、 JDBC使用

    MySQL的JDBC驱动,这个不是系统自带的,需要额外的进行下载安装

    那么我们怎么安装呢?在哪里下载

    1. 对应的官网对应MySQL的JDBC驱动来说,一定可以在官网找到(Oracle管网)
    2. 对应开源的库,可以去github对应的项目主页,去找,
    3. 中央仓库,有一些大佬,搞的第三方中央仓库,中央仓库上收集许多第三方库,后面一些第三方也会主动把自己上传到这个库上。

    但是上面的前2个方法很难找到,官网的差别很大,我们这里一般是中央仓库,后面的学习中用到的第三方库,全是中央仓库去找。

    中央仓库地址

    在这里插入图片描述
    然后点进去发现有许多版本,我们选择什么版本呢?具体使用什么版本还是看你安装的mysql服务器的版本~

    Mysql主流的服务器版本就是两套

    1. 8.x系列(使用8.x系列)
      在这里插入图片描述

    2. 5.x系列 (使用5.1.x系列) 小版本区别不大,关键是大版本
      在这里插入图片描述

    小版本指的是:5.1.49 和5.1.48 这些区别不大,如果5版本使用8版本的 可能会出现连不上的问题。

    下载:点击按钮下载驱动
    在这里插入图片描述

    这个驱动包,是一个jar包,就称为jar包,这是java程序打包部署的一种常见格式,这个.jar 就和压缩包类似,jar包本质就是把一些.class文件以压缩包的形式,给打包在一起了


    引用jar包:开始使用 先来搞一个简单的以后教大家更加科学的方式:

    在这里插入图片描述


    开始JDBC 写代码

    使用mysql workbench,也需要建立一个连接,也需要指定数据库的ip和端口
    在这里插入图片描述
    ip:127.0.0.1表示主机自身 (是区分在哪个主机上)
    port:3306安装数据库服务器的时候,手动设置的一般默认就是3306(区分在主机上的什么程序上)

    使用JDBC来实现数据库的增加:

    我们这里有个insert方法里面就是写代码来实现功能

    1. 创建一个数据源在这里插入图片描述
      DataSource 是标准库里面的,也就是自带的,它是一个interface 接口
      MysqlDataSource 是jar包的,也就是说如果jar包没有导入成功就没有办法使用 实现了DataSource interface的类

    DataSource 这个概念表示“数据库在哪里”,对于Mysql来说,数据库就是一个服务器程序,因此就可以通过DataSource 来描述服务器的地址,端口,用户名,密码,要访问数据库名等等

    1. 把数据库的位置信息,设置到. DataSource 中
      1)数据库的ip端口 ,数据名通过URL表示
      使用到一个 setUTL 这个方法,这个setURL方法属于 MysqlDataSource 不是DataSource 的方法,此处需要向下转型
      在这里插入图片描述
      这个操作涉及了向下转型,我们为什么要这样写:
      使用这种转型的写法,也很常见,带来的好处就是,代码中其他部分拿到的dataSource都是 DataSource类型,和具体的数据库种类无关.日后如果需要切换数据库,其他代码就完全不用改动了.

    比如使用的是MysqlDataSource ,因为MysqlDataSource 是Mysql的如果数据库变量了那么其他需要变一点不方便
    来看看set.URL里面的内容分别是什么意思
    在这里插入图片描述
    还有新增的2个 useSSL:加密

    **加粗样式**

    为什么要加密:
    在这里插入图片描述
    到底需要打开吗加密吗?
    在这里插入图片描述

    2)设置登录数据库的用户名
    在这里插入图片描述MySQL支持自己创建用户.
    MySQL只要安装好之后,就会自带一个用户,就是root.表示"管理员”,拥有最高的权限,可以管理其他用户的权限.当前阶段咱们不必过多的关注这里的权限.(权限的话以后到公司里,都是有专门的人来给你分配好的)
    3)设置登录数据库的密码
    在这里插入图片描述
    3.连接数据库,进行真正的网络通信
    在这里插入图片描述
    这个就是开始进行网络操作,如果数据库连接上了,会返回一个实例,如果失败会抛出一个异常
    在这里插入图片描述
    啥时候会连接失败呢?原因非常多,例如 ip ,端口,密码,这些错误会失败,用户没有权限也会失败,数据库没有正确启动也会失败
    异常处理 注意是这个库里面的:import java.sql.Connection;
    在这里插入图片描述
    4.构造一个SQL语句,为插入准备!
    通过其他语言来操作数据库,其实还是通过SQL来完成!
    这里有一个数据库,结构是这样的:
    在这里插入图片描述
    此处不需要use数据库的操作,在URL中已经设定好数据库的名字了,此时客户端连上去之后就能直接确定数据库
    在这里插入图片描述
    执行语句写好了,我们还需要执行, 有一个专门的对象 :PreparedStatement
    在这里插入图片描述
    这里要介绍一下为什么要这个对象:我们的SQL语句不一定是直接写死的值直接给你的,可能里面的信息是要动态拼接,就是不是已经给值的,说白了重要的功能是动态拼接SQL

    5.执行SQL客户端把SQL通过网络请求,发送给mysql服务器,mysqk服务器来解析这个SQL请求,执行具体操作,并返回响应结果,此处使用excuteUpdate 来完成数据库内容的变更(边更包含 insert,update,delete),返回值是整数,返回多少就是影响多少行操作 executeQuery:数据查询.针对select =>返回值是个ResultSet .
    在这里插入图片描述
    最后一步:我们要关闭资源
    在这里插入图片描述
    为什么关闭,客户端通过网络和服务器建立连接,客户端和服务器之间各自会分配一些资源,来保持这样的连接信息(记录对端的ip port)每维护一个连接,就都得分配一些硬件资源,如果一直不关闭资源越耗越多,最后没有资源,程序就无法正常运行

    调用close的顺序,应该是按照申请顺序的“逆序”来进行的~
    前面的代码,是先创建Connection,再创建PreparedStatement
    后面的代码,就是先关闭PreparedStatement,后关闭Connection

    最后我们执行,全部的代码放在下面最后看看结果:

    public class start {
    
    
        public static void main(String[] args) throws SQLException {
            insert();
        }
    
        public static  void insert() throws SQLException {
            //1. 创建一个数据库源
            MysqlDataSource dataSource = new MysqlDataSource();
            ((MysqlDataSource)dataSource).setURL("jdbc:mysql://127.0.0.1:3306/java101?characterEncoding=utf8&&useSSL=false");
            ((MysqlDataSource)dataSource).setUser("root");
            ((MysqlDataSource)dataSource).setPassword("200224");
    
            //2.连接数据库,进行真正的网络通信
            Connection connection = dataSource.getConnection();
    
            //3.构造一SQL语句,为插入做准备
            //此处不需要use数据库的操作,在URL中已经设定好数据库的名字了,此时客户端连上去之后就能直接确定数据库
            String sql = "insert into test values (1,'张三') ";
    
            //执行SQL 专门的对象prepareStatement
            PreparedStatement statement = connection.prepareStatement(sql);
    
            //影响行数
            int ret = statement.executeUpdate();
            System.out.println("ret:"+ret);
    
            //执行完SQL之后,还要回收一些资源
            statement.close();
            connection.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

    数据库最后执行成功会新增一个数据:
    在这里插入图片描述


    如果我们想动态拼接怎么办呢??

    可以尝试这样的写法:
    在这里插入图片描述
    但是通过字符串拼接,确实可以动态的构造出SQL,但是不建议这样使用,这样拼接比较麻烦,另一方面这样不安全,容易被SQL注入。

    那么我们要怎么样实现,更加安全呢?

    在这里插入图片描述
    我们只需要把,SQL语句的拼接全部变成? ?,这样也可以清楚的看清楚我们有那几个值,而且也更加方便,下面是赋值

    在这里插入图片描述
    那个1,就是id替换了第一个?的地方,那个2就是name替换了第二个? 然后第一个是int类型,第二个替换成String类型的。

    statement就支持一组setxxx 这样的方法,xxx值得是一个具体的类型~,根据要设置的类型不同,来决定使用不同的方法,数据库的所以的类型基本上全都支持
    在这里插入图片描述
    setxxx方法内部对于设置的值,进行了比较严格的校验,如果用户插入的内容是包含这种疑似SQL注入的时候,setxxx 就可以识别出来。

    我们可以看statement里面的SQL
    在这里插入图片描述
    拼装后的样子:
    在这里插入图片描述
    最后数据库也成功了:在这里插入图片描述

    在这里插入图片描述

    public static  void insert2() throws SQLException {
            //1. 创建一个数据库源
            MysqlDataSource dataSource = new MysqlDataSource();
            ((MysqlDataSource)dataSource).setURL("jdbc:mysql://127.0.0.1:3306/java101?characterEncoding=utf8&&useSSL=false");
            ((MysqlDataSource)dataSource).setUser("root");
            ((MysqlDataSource)dataSource).setPassword("200224");
    
            //2.连接数据库,进行真正的网络通信
            Connection connection = dataSource.getConnection();
    
            //3.构造一SQL语句,为插入做准备
            //此处不需要use数据库的操作,在URL中已经设定好数据库的名字了,此时客户端连上去之后就能直接确定数据库
            Scanner scanner = new Scanner(System.in);
            System.out.println("请输入学号");
            int id = scanner.nextInt();
            System.out.println("请输入姓名");
            String name = scanner.next();
    
            String sql = "insert into test values (?,?)";
            //执行SQL 专门的对象prepareStatement
            PreparedStatement statement = connection.prepareStatement(sql);
            statement.setInt(1,id);
            statement.setString(2,name);
            System.out.println("sql"+statement);
    
            //影响行数
            int ret = statement.executeUpdate();
            System.out.println("ret:"+ret);
    
            //执行完SQL之后,还要回收一些资源
            statement.close();
            connection.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

    写完了插入,我们来写一下删除呗:

     public static void delete() throws SQLException {
            //删除和插入差不多 只是把SQL从SQL变成delete
            //1.创建数据源,吧数据库的位置信息设置进去
            DataSource dataSource = new MysqlDataSource();
            ((MysqlDataSource)dataSource).setURL("jdbc:mysql://127.0.0.1:3306/java101?characterEncoding=utf8&&useSSL=false");
            ((MysqlDataSource)dataSource).setUser("root");
            ((MysqlDataSource)dataSource).setPassword("200224");
            //2.和数据库建立连接
            Connection connection= dataSource.getConnection();
            //3.构造SQL
            Scanner scanner = new Scanner(System.in);
            System.out.println("请输入要删除的id:");
            int id= scanner.nextInt();
            String sql = "delete from test where id = ?";
            PreparedStatement statement = connection.prepareStatement(sql);
            statement.setInt(1,id);
            //4.执行SQL
            int ret = statement.executeUpdate();
            System.out.println("ret="+ret);
            //5.释放资源
            statement.close();
            connection.close();
         }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    其实发现就是SQL有区别其他地方没有区别对吧
    在这里插入图片描述
    但是发现我们的JDBC 操作数据库是不是有点太麻烦了,的确,但是我们之后会告诉简化的方法的,毕竟代码是给我们带来方便的 。
    在这里插入图片描述
    结果:
    在这里插入图片描述
    数据库:
    在这里插入图片描述


    写一下修改:

    public static  void update() throws SQLException {
            //1.创建数据源
             DataSource dataSource = new MysqlDataSource();
             ((MysqlDataSource)dataSource).setURL("jdbc:mysql://127.0.0.1:3306/java101?characterEncoding=utf8&&useSSL=false");
             ((MysqlDataSource)dataSource).setUser("root");
             ((MysqlDataSource)dataSource).setPassword("200224");
             //2.创建连接
             Connection connection = dataSource.getConnection();
             //3.构造数据库
             System.out.println("请输入要修改的id");
             Scanner scanner = new Scanner(System.in);
             int id = scanner.nextInt();
             System.out.println("请输入要修改的name");
             Scanner scanner1 = new Scanner(System.in);
             String name = scanner1.nextLine();
             String sql = "update  test set name = ? where id = ?";
             PreparedStatement statement = connection.prepareStatement(sql);
             statement.setString(1,name);
             statement.setInt(2,id);
             //4.执行SQL
             int ret = statement.executeUpdate();
             System.out.println("ret"+ret);
             //5.关闭
             statement.close();
             connection.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

    在这里插入图片描述
    数据库:
    在这里插入图片描述


    查找:查询和修改插入删除,就有一些区别了!

    插入删除修改,执行完的返回结果,只有一个int而已

    查找操作,执行完的结果,是包含一组结果集合(一张临时表),

    此处就需要写一些额外的代码,把这个临时表/结果表里的内容获取到

    在这里插入图片描述
    这个结果的集合的遍历,就非常类似于"迭代器"的遍历
    resultSet.next() 获取当前行,同时切换到下一行 这个操作类似 i++

    resultSet 就相当于一张表,每次next得到其中的一行,就可以进一步的根据这一行,得到里面的列

    如果获取到了这一行 会返回一个true 如果遍历到了表的末尾,在尝试next 就会返回false
    在这里插入图片描述
    在这里插入图片描述
    使用getxxx方法要和表里的类型相对
    在这里插入图片描述

    public static void search() throws SQLException {
            //1.创建数据源
             DataSource dataSource = new MysqlDataSource();
             ((MysqlDataSource)dataSource).setURL("jdbc:mysql://127.0.0.1:3306/java101?characterEncoding=utf8&&useSSL=false");
             ((MysqlDataSource)dataSource).setUser("root");
             ((MysqlDataSource)dataSource).setPassword("200224");
             //2.创建数据库
             Connection connection = dataSource.getConnection();
             //3.SQL语句
             String sql = "select * from test ";
             PreparedStatement statement = connection.prepareStatement(sql);
             //4.执行SQL语句
             ResultSet resultSet = statement.executeQuery();
             //5.遍历结果集合
             // resultSet.next() 获取当前行,同时切换到下一行 这个操作类似  i++
             //resultSet 就相当于一张表,每次next得到其中的一行,就可以进一步的根据这一行,得到里面的列
             //如果获取到了这一行 会返回一个true 如果遍历到了表的末尾,在尝试next 就会返回false
                while(resultSet.next()){
                    //resultSet 就表示当前的这一行
                    //从这一行里面就能获取到具体的列
                    int id = resultSet.getInt("id");
                    String name = resultSet.getString("name");
                    System.out.println("id:"+id);
                    System.out.println("name:"+name);
    
                }
                //6.释放资源
                resultSet.close();
                statement.close();
                connection.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

    在这里插入图片描述
    数据库:
    在这里插入图片描述
    还有些编程语言/库里,把ResultSet也叫做光标
    在这里插入图片描述


    三、JDBC小结

    1.DataSource和MysqlDataSource表示数据源(数据在哪里)

    • DataSource :通用的,能够支持各种数据库
    • MysqlDataSource:是MySQL驱动包里提供的专门针对·MySQL的类,设置用户名,密码,URL…基本信息

    2 .Connection connection = dataSource.getConnection()

    • 通过DataSource来建立Connection (要先知道服务器的位置才可以连接)

    3.构造SQL
    在这里插入图片描述
    PreparedStatement:

    里面包含的不仅仅是SQL,要通过这个对象来把用户构造的SQL通过网络发送给服务器

    Connection是自身真的服务器的位置的(从DataSource过来的)通过connection创建出的PreparedStatement,PreparedStatement也知道服务器的位置
    在这里插入图片描述
    executeQuery / executeUpdate:通过网络发送,前提知道在哪里

    4.遍历结果集合
    在这里插入图片描述
    通过网络,数据集合已经拿回来了,到了本地,响应的结果已经在客户端代码的内存中,可以在本地遍历,获取内容

    通过这些,大家要记住一句话,MySQL是一个“客户端 服务器” 结构的程序,服务器是Mysql的本体,负责管理数据,客户端有许多形态(cmd,workbench ,JDBC…)


    四、JDBC封装

    刚刚上面的代码比较冗余,许多代码重复的还写,其实我们可以把部分代码封装一下,即可轻松一点:

    URL部分

    在这里插入图片描述
    接下来创建数据源

    其实每个项目里面有一个数据源就可以了

    像DataSource这样的实例只要有1个就可以了,不应该被创建多个

    在这里插入图片描述
    我们通过Static来修饰,此处的Static是表示的是“类成员”,“类方法”

    DBUtil在程序中,只存在一份!! 这个类里面的成员,也就是只有一份了!

    我们写的类,被编译成.class文件,程序运行的时候,jvm就会从指定的路径中,加载.class文件,.class文件是有固定格式的…(从jvm的实现规范上看到)

    JVM就会把.class文件内容进行解析,并且加载到内存中,并且在内存构造一个“类对象”,(类对象里面就包含了这个类的关键信息,这个类叫什么名字,类里面有哪些属性,每个属性叫什么,每个属性是public还是private,还有什么方法,叫什么名字,方法的参数叫什么,返回值是啥public /private)

    类就是图纸~

    JVM在加载的时候,就会先看看这个类是不是已经在内存中存在了,如果存在,就不要重复加载,如果不存在才从.class加载
    在这里插入图片描述
    所以才要加static
    在这里插入图片描述
    像这样的操作,保证类中在程序只有唯一实例,称为“单例模式”,也是一种设计模式

    接下来我们需要执行数据库连接,以及后续的建立连接和关闭释放资源
    在这里插入图片描述
    直接调用close就可以关闭,调用connectio可以连接,最后的代码就是这样的DBUtil

    package bookManager;
    
    
    import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;
    
    import javax.sql.DataSource;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.sql.Connection;
    
    /**
     * Created by Lin
     * Description:
     * User: Administrator
     * Date: 2022-01-14
     * Time: 14:45
     */
    //通过这个类 把数据库连接操作封装一下
    public class DBUtil {
        private static String url = "jdbc:mysql://127.0.0.1:3306/good?characterEncoding=utf8&useSSL=false";
        private static String username ="root";
        private static String password = "200224";
    
        //接下来创建数据源
        //其实每个项目里面有一个数据源就可以了
        //像DataSource这样的实例,不应该被创建多个
        private static DataSource dataSource = new MysqlDataSource();
    
        //静态代码块 执行时间是在类加载阶段
        static {
            ((MysqlDataSource)dataSource).setURL(url);
            ((MysqlDataSource)dataSource).setUser(username);
            ((MysqlDataSource)dataSource).setPassword(password);
        }
    
        //提供一个方法,来建立连接
        public static Connection getConnection() throws SQLException {
            return dataSource.getConnection();
        }
        //释放资源代码
        //这里的参数不要null就关闭
        public static void close(Connection connection, PreparedStatement statement, ResultSet resultSet){
            if(resultSet != null){
                try {
                    resultSet.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (statement != null){
                try {
                    statement.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (connection !=null){
                try {
                    connection.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    
    
    • 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
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67

    为什么我们这里要这样写,因为如果我们就嵌套一层try catch的话,那就会出现问题,如果第一个close出现异常,那么就会去catch语句,其他的就不执行了,所以我们使用这样的
    在这里插入图片描述


  • 相关阅读:
    基于后端和爬虫创建的代理ip池
    Windows环境部署Hadoop-3.3.2和Spark3.3.2
    matlab, python串口10ms毫秒 连续发送16进制数组
    计算机毕业设计选什么题目好?springboot 幼儿园管理系统
    计算机毕业设计ssm软件工匠p1rs1系统+程序+源码+lw+远程部署
    如何在C#中使用 Excel 动态函数生成依赖列表
    Linux小总结
    Hoops编程指南:03_4_viewing_windows
    基于级联广义积分器(CGI)的谐波信号提取MATLAB仿真
    VCS工具学习笔记(8)
  • 原文地址:https://blog.csdn.net/qq_46874327/article/details/122259757