【Java】JDBC基础使用教程

本文涉及的产品
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
简介: 实际工作中大部分的数据库操作,都是通过代码来完成的.格子编程语言都可以操作数据库,主要是数据库提供了各种版本的 API(一组函数 / 一组类),调用这些API就可以操作数据库。

一、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系列)

     ![在这里插入图片描述](https://ucc.alicdn.com/images/user-upload-01/76bc2bbac0ee4a49bdc6ffc0b0b5af3c.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5oSP5oS_5LiJ5LiD,size_20,color_FFFFFF,t_70,g_se,x_16)
    
  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();
    }
}


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


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

可以尝试这样的写法:
在这里插入图片描述
但是通过字符串拼接,确实可以动态的构造出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();
    }

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

 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();
     }

其实发现就是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();

     }

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


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

插入删除修改,执行完的返回结果,只有一个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();
     }

在这里插入图片描述
数据库:
在这里插入图片描述
还有些编程语言/库里,把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();
            }
        }
    }
}

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


相关实践学习
基于CentOS快速搭建LAMP环境
本教程介绍如何搭建LAMP环境,其中LAMP分别代表Linux、Apache、MySQL和PHP。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
3天前
|
XML JavaScript Java
Java 中文官方教程 2022 版(四十)(4)
Java 中文官方教程 2022 版(四十)
33 0
|
1天前
|
SQL Java 数据库连接
Java从入门到精通:2.3.1数据库编程——学习JDBC技术,掌握Java与数据库的交互
ava从入门到精通:2.3.1数据库编程——学习JDBC技术,掌握Java与数据库的交互
|
1天前
|
Web App开发 数据采集 Java
《手把手教你》系列技巧篇(三十)-java+ selenium自动化测试- Actions的相关操作下篇(详解教程)
【4月更文挑战第22天】本文介绍了在测试过程中可能会用到的两个功能:Actions类中的拖拽操作和划取字段操作。拖拽操作包括基本讲解、项目实战、代码设计和参考代码,涉及到鼠标按住元素并将其拖动到另一个元素上或指定位置。划取字段操作则介绍了如何在一段文字中随机选取一部分,包括项目实战、代码设计和参考代码。此外,文章还提到了滑动验证的实现,并提供了相关的代码示例。
11 2
|
1天前
|
安全 Java
Java基础教程(15)-多线程基础
【4月更文挑战第15天】Java内置多线程支持,通过Thread类或Runnable接口实现。线程状态包括New、Runnable、Blocked、Waiting、Timed Waiting和Terminated。启动线程调用start(),中断线程用interrupt(),同步用synchronized关键字。线程安全包如java.util.concurrent提供并发集合和原子操作。线程池如ExecutorService简化任务管理,Callable接口允许返回值,Future配合获取异步结果。Java 8引入CompletableFuture支持回调。
|
3天前
|
XML 算法 搜索推荐
Java 中文官方教程 2022 版(四十九)(4)
Java 中文官方教程 2022 版(四十九)
31 0
|
3天前
|
XML 自然语言处理 安全
Java 中文官方教程 2022 版(四十九)(3)
Java 中文官方教程 2022 版(四十九)
22 0
|
3天前
|
XML Java 编译器
Java 中文官方教程 2022 版(四十九)(2)
Java 中文官方教程 2022 版(四十九)
24 0
|
3天前
|
XML 网络协议 Java
Java 中文官方教程 2022 版(四十八)(3)
Java 中文官方教程 2022 版(四十八)
7 0
|
3天前
|
小程序 安全 Java
Java 中文官方教程 2022 版(四十七)(3)
Java 中文官方教程 2022 版(四十七)
9 0
|
3天前
|
安全 Java 编译器
Java 中文官方教程 2022 版(四十六)(2)
Java 中文官方教程 2022 版(四十六)
20 0