Java之JDBC数据库编程

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: Java之JDBC数据库编程


什么是数据库API:

先来看看百度是怎么说的:

API(Application Programming Interface, 应用程序 编程接口)是一些预先定义的 函数 ,目的是提供 应用程序 与开发人员基于某 软件 或硬件得以访问一组 例程 的能力,而又无需访问源码,或理解内部工作 机制 的细节。

就好比, 你家门口有一个饭店, 这个饭店为你提供了以下服务:

  1. 预定座位
  2. 提前点餐
  3. 在线支付
  4. 外卖送餐

.......

API就相当于这个饭店的门面,只有你知道这个门面,你才能享受他的服务.这个饭店就相当于一个数据库, 而这些服务就是API接口提供的操作方法, 或者称为函数. 只不过这些服务都是在代码层次的, 不同数据库都提供了不同的API接口. 程序员就可以通过这些接口来调用里面的方法,以便更快速地操作数据.

什么是java-JDBC编程

在处理一些复杂的SQL语句, 或者是有一个数据量非常大的数据集等着被写入数据库, 那么这种一个一个使用SQL语句插入的效率是非常低效和麻烦的. 于是就有了用java语句来操作数据库的这种方法, 但是众所周知, 数据库不只有MySQL一个, 还有oracle和SQL server等, 他们都提供了不同的API接口, 如果一个java程序员要操作MySQL数据库, 那么他就要去书序MySQL的API接口, 如果是oracle,那么就要去学习oracle的API接口, 因此程序员的学习成本将会变得很高.

然后sun公司就为这些数据库规范了一套API接口, 各个数据库厂商就按这个规范提供这套API接口的实现. 这套规范并不是说直接把这些数据库原来的API接口直接覆盖了, 而是把在原来的基础上把这些接口封装一下, 然后供JDBC使用. 于是这些厂商就提供了封装自身API的程序.

这个程序用来完成对API的转换, 将其转换为JDBC可以使用的API, 这些程序就被称为数据库驱动包.如果java程序员要想进行数据库开发, 就需要在其项目中导入 对应数据库的驱动包, 才能编写代码. 平时我们也可能看到常用的硬件驱动设备. 硬件驱动是让操作系统认识新的硬件设备, 数据库的驱动是让JDBC认识数据库的API接口.

如何导入数据库?

1.创建一个java项目

创建一个java项目

这个就不多讲~~

2.驱动包下载

驱动包是数据库厂商提供的, 对于MySQL这种开源数据库, 我们可以怎么获取他的驱动包?

  1. MySQL官方网站获取(但是MySQL被oracle合并之后, 官网也合并了)
  2. GitHub
  3. maven中央仓储

这里主要讲解maven下载的方式

什么是中央仓储? 比如你要下载一个软件, 你可以去手机app商店下载, 也可以去这个软件的官网下载. 这个maven就像一个app商店, 里面集合了很多常用的软件. maven是一个软件, 这个中央仓储是一个服务器, 这个服务器托管了各种软件程序包, 所以就可以通过maven这个软件访问仓储服务器, 来下载程序包.

maven仓库 <-- maven网址

在其中搜索mysql即可, 然后选择MySQL Connector Java :

如何检索出MySQL的API程序包

点进去之后可以看到里面有很多版本, 这些版本大致分为:

2.0 3.0 3.1 5.0 5.1 6.0 8.0 这几个版本,

但是这些版本需要和我们的数据库服务器相匹配

这个 ? vulnerabilities 也就是漏洞的意思, 是一些bug, 可能会带来一些风险, 黑客可能利用这个漏洞来攻击你的电脑.

数据库版本相关

注意: 数据库服务器的版本要和驱动包的大版本一致. 例如 数据库服务器的是5.0系列, 驱动包也需要

使用5.0版本.

我们选择5.1.49版本的驱动包 进入5.1.49的详细页面, 然后点击jar开始下载:

这种 .jar 是java发布程序的典型方式, java通过.java源文件编译成.class文件, 然后jvm来解释执行.class文件. 每一个.Java文件对应一个.class文件, 但是如果一个项目里面.java文件很多呢? 那么就会将一大堆的.class文件, 给压缩成类似.rar / .zip的.jar压缩包文件, 将jar包打包给别人,别人就可以直接使用jvm来使用.

3.驱动包导入(IDEA)

这个jar包并不是单独地去运行, 而是将其导入创建的Java项目当中, 然后可以调用其中的方法和类来进行编程!!!

这里的导入不用解压, jvm会自动识别.

导入完之后还需要将这个目录标记为 项目的库:

将你创建的包含了驱动包的文件夹设置为项目库, 点击Add as Library

设置完之后, idea 就能识别这个目录里面的jar包, 从而调用里面的类和方法.

这样就可以看到里面的一些类和文件

编写JDBC代码

JDBC需要通过以下步骤来完成开发

  1. 创建并初始化一个数据源
  2. 和数据库服务器建立连接
  3. 构造一个SQL语句
  4. 执行SQL语句
  5. 释放必要的资源

1.创建数据源

数据源:描述数据从哪来, 也就是描述数据库服务器在哪, 也就是DataSource:

public class JDBC {
    public static void main(String[] args){
        DataSource dataSource = new MysqlDataSource(); // 使用驱动包中的类
    }
}

此处的DataSource是一个接口, 这里使用MysqlDataSource的向上转型, 然而MysqlDataSource里面的一些方法是父类DataSource里面没有的, 因此要使用这些子类中有的而父类中没有的方法就需要进行向下转型, 例如((MySQLDataSource)DataSource).strUtr();

当然你也可以不使用向上转型:

public class JDBC {
    public static void main(String[] args){
        MysqlDataSource dataSource = new MysqlDataSource(); // 使用驱动包中的类
    }
}

其中URL是一个网络常用术语, 描述网络资源的所在位置, 例如:

url:"jdbc:mysql://127.0.0.1:3306/test2?characterEncoding=utf8&useSSL=false"

public class JDBC {
    public static void main(String[] args){
        DataSource dataSource = new MysqlDataSource(); // 使用驱动包中的类
       // 创建数据源
         ((MysqlDataSource)dataSource).setUrl(
        "jdbc:mysql://127.0.0.1:3306/test2?characterEncoding=utf8&useSSL=false"
        );
    }
}

其中jdbc是固定的格式, 第一个冒号' : '后面的主要是看是啥数据库, 如果你是MySQL, 那么就写mysql.

我们前面提过, mysql是一个客户端服务器式的结构, 客户端和服务器之间通过网络来通信, 网络上确定主机的位置就是通过ip地址来确定的, 于是在数据库后面的' :// '后面写入ip地址:127.0.0.1, 这叫做环回ip. 表示你自己的当前的主机, 因为当前数据库客户端(也就是现在写的jdbc代码), 数据库服务器(存储数据的服务器)都是在一个主机上, 当然装在不同主机上就需要改变ip了.

再后面的3306是端口的意思, 一个主机上有很多个程序, 如果来识别是哪一个端口呢? 于是就有了端口的概念, 端口是用来区分应用程序的, 数据库的默认端口就是3306.

再后面的test2, 也就是我们的数据库名,如图 :

后面的characterEncoding=utf8 是表明数据库所使用的字符集为utf8.

后面的useSSL=false 是一个加密协议, 此处false, 也就是说不加密.

2.设置用户和密码

光有数据源还不够, 还需要设置用户名和用户密码:

public class JDBC {
    public static void main(String[] args){
        DataSource dataSource = new MysqlDataSource();
        // 创建数据源
        ((MysqlDataSource)dataSource).setUrl(
        "jdbc:mysql://127.0.0.1:3306/test2?characterEncoding=utf8&useSSL=false"
        );
        ((MysqlDataSource)dataSource).setUser("root");
        ((MysqlDataSource)dataSource).setPassword("238638");
    }
}

只有设置了数据源, 用户名和密码才能访问数据库服务器:

使用setUser和setPassword. 其中用户名默认就是root, 这里只是设置了一遍但还是root.

setPassword是你安装数据库的时候设置的密码, 例如你数据库的密码是123456, 那么setPassword的参数就是123456(字符串形式).

这两步完成之后, 还没有对数据库进行连接, 那么如何连接?

3.连接数据库

使用DataSource中的getConnecttion()方法.

public class JDBC {
    public static void main(String[] args){
        DataSource dataSource = new MysqlDataSource();
        // 创建数据源
        ((MysqlDataSource)dataSource).setUrl(
        "jdbc:mysql://127.0.0.1:3306/test2?characterEncoding=utf8&useSSL=false"
        );
        // 设置用户名
        ((MysqlDataSource)dataSource).setUser("root");
        // 输入数据库密码
        ((MysqlDataSource)dataSource).setPassword("238638");
        // 建立数据库连接
        datasource.getConnection();
    }
}

但是这样, getConnection()依然会报错, 如下:

这是一种受查异常, 所以我们应该在main方法上抛出此异常, 然后使用变量接收其返回值:

public class JDBCInsert {
    public static void main(String[] args) throws SQLException {
        DataSource dataSource = new MysqlDataSource();
        ((MysqlDataSource)dataSource).setUrl("jdbc:mysql://127.0.0.1:3306/test2?characterEncoding=utf8&useSSL=false");
        ((MysqlDataSource)dataSource).setUser("root");
        ((MysqlDataSource)dataSource).setPassword("238638");
        Connection connection = dataSource.getConnection();
    }
}

注意此处的Connection接口为java.sql中的Connection接口, 而不是其他的接口.

如果服务器连接失败, 就抛出异常.

编写JDBC-SQL语句

在创建好数据源, 设置用户名和输入数据库密码, 连接数据库服务器之后, 就可以使用SQL语句进行增删改查的操作了.

以这个简单的表为例子:

create table student(age int, name varchar(20));

使用插入

String sql = "insert into student values(18,'张三');";
PreparedStatement statement = connection.prepareStatement(sql);

这个sql只是一个字符串的sql, 还不能被真正的执行. 所以还要进行预处理一下, 也就是下面的statement, 对我们的sql语句进行一个预编译:

PrepareStatement - > 提前预编译

这里的sql字符换服务器是可以处理的, 服务器首先需要对SQL进行解析, 理解这里的含义并执行, 但是如果客户端这里有几千万个sql字符串请求, 那么对于服务器来说压力就比较大.

编译构造完成之后, 就可以执行SQL语句了:

statement.executeUpdate();

int ret = statement.executeUpdate();
System.out.println("ret = "+ ret);

这一步操作将SQL语句发送给服务器.

对于executeUpdate是一个返回值为int 的方法, 表示你影响到的行数, 除了insert, 后面的delete和update都是用的executeUpdate方法:

statement对象

Statement对象主要是将SQL语句发送到数据库中。JDBC API中主要提供了三种Statement对象

  1. Statement, 用于执行不带参数的简单SQL语句
  2. PreparedStatement, 用于执行带或者不带参数的SQL语句, SQL语句会预编译在数据库系统, 执行速度快于Statement对象
  3. CallableStatement, 用于执行数据库存储过程中的调用

释放资源

数据库的服务器和客户端, 之间进行通信的时候会消耗一定的系统资源的, 包含:cpu, 内存, 硬盘, 带宽.....对于服务器来说同一时间要处理很多个客户端, 这个时候就产生了一个问题, 给一个客户端提供服务需要消耗一定的资源, 要是给10个, 或者更多的客户端提供服务, 那么就会消耗更多的资源.

怎么样才能节约或者更好地利用更多资源呢, 那么就得客户端尽量少使用资源, 不用的赶紧释放资源.

使用语句:

// 释放资源
statement.close();
connection.close();

完整代码:

public class JDBCInsert {
    public static void main(String[] args) throws SQLException {
        DataSource dataSource = new MysqlDataSource();
        ((MysqlDataSource)dataSource).setUrl("jdbc:mysql://127.0.0.1:3306/test?characterEncoding=utf8&useSSL=false");
        ((MysqlDataSource)dataSource).setUser("root");
        ((MysqlDataSource)dataSource).setPassword("238638");
        Connection connection = dataSource.getConnection();
 
        String sql = "insert into student values(18, '张三');";
        PreparedStatement statement = connection.prepareStatement(sql);
        int ret = statement.executeUpdate();
        System.out.println("ret = "+ ret);
    }
}

ResultSet对象(查询操作)

对于查询来说, 返回的结果就不是int这么简单了, 而是一个ResultSet对象 .

ResultSet对象被称为结果集, 它象征着数据库中的一个临时表的身份, 代表着符合SQL查询语句的所有行, 并且提供一套完整的get方法来对这些记录进行访问. ResultSet里面的数据是一行一行排列的, 每行有多个属性(字段), 并且有一个记录指针, 指向行首数据.

跟插入语句一样, 我们需要以下过程(除了第e步, 其他都类似):

  1. 创建数据源
  2. 建立连接
  3. 构造SQL语句
  4. 执行SQL语句
  5. 遍历结果集合
  6. 释放资源
public class JDBCSelect {
    public static void main(String[] args) throws SQLException {
        // 建立数据源
        DataSource dataSource = new MysqlDataSource();
        ((MysqlDataSource)dataSource).setUrl("jdbc:mysql://127.0.0.1:3306/test?characterEncoding=utf8&useSSL=false");
        ((MysqlDataSource)dataSource).setUser("root"); // 用户名(一般为root)
        ((MysqlDataSource)dataSource).setPassword("238638"); // 密码, 数据库初始密码
        // 建立连接 java.sql这个包
        Connection connection = dataSource.getConnection();
 
        // 编写SQL语句对象
        String sql = "select * from student;";
        // 预编译
        PreparedStatement statement = connection.prepareStatement(sql);
 
        // 遍历集合
        ResultSet resultSet = statement.executeQuery();
        while(resultSet.next()) {
            // 把resultSet想象成一个表格, 同时表里面有个光标, 初始情况下这个表的光标指向最上面一个记录
            // 每个next光标就会往下走一个记录
            int age = resultSet.getInt("age");
            String name = resultSet.getString("name");
            System.out.println("age = " + age + ", name = " + name);
        }
        // 释放资源
        statement.closs();
        connection.close();
        resultSet.close();
    }

查询到的这个临时表就是resultSet

硬编码

要插入的数据是写死的, 这样的操作成为硬编码. 这种方式就很不合适, 更合适的做法是, 把数据通过其他的方式让用户输入:

public class JDBCInsert {
    public static void main(String[] args) throws SQLException {
        Scanner scanner = new Scanner(System.in);
 
        // 创建数据源
        DataSource dataSource = new MysqlDataSource();
        ((MysqlDataSource)dataSource).setUrl("jdbc:mysql://127.0.0.1:3306/test?characterEncoding=utf8&useSSL=false");
 
        // 设置用户名, 输入数据库密码(都是以字符串为参数)
        ((MysqlDataSource)dataSource).setUser("root");
        ((MysqlDataSource)dataSource).setPassword("238638");
 
        // 连接数据库服务器
        Connection connection = dataSource.getConnection();
        System.out.println("请输入姓名:>");
        String name = scanner.next();
        System.out.println("请输入年龄:>");
        int age = scanner.nextInt();
        // 输入SQL语句
        String sql = "insert into student values(" + age + ", ' "+ name+ "');";
 
        // 预编译SQL语句, 减少数据库服务器负担
        PreparedStatement statement = connection.prepareStatement(sql);
 
        // 执行SQL语句并接收返回值
        int ret = statement.executeUpdate();
        System.out.println("ret = "+ ret);
    }
}

但是这只是一种下策, 虽然确实可以让用户动态输入. 但是这种输入的代码非常的丑陋膈应, 比如这个字符串拼接, 非常容易写错, 而且可读性很差.不推荐, 还可能带来一个风险,也就是SQL注入, 这是网络安全中典型的攻击方式. 而且这样写, 非常的麻烦.

所以我们可以使用占位符 ? 的形式来进行自由插入数据:

public class JDBCInsert {
    public static void main(String[] args) throws SQLException {
        Scanner scanner = new Scanner(System.in);
 
        // 创建数据源
        DataSource dataSource = new MysqlDataSource();
        ((MysqlDataSource)dataSource).setUrl("jdbc:mysql://127.0.0.1:3306/test?characterEncoding=utf8&useSSL=false");
 
        // 设置用户名, 输入数据库密码
        ((MysqlDataSource)dataSource).setUser("root");
        ((MysqlDataSource)dataSource).setPassword("238638");
 
        // 连接数据库服务器
        Connection connection = dataSource.getConnection();
        System.out.println("请输入姓名:>");
        String name = scanner.next();
        System.out.println("请输入年龄:>");
        int age = scanner.nextInt();
        // 输入SQL语句
        String sql = "insert into student values(?, ?);";
        // 预编译SQL语句, 减少数据库服务器负担
        PreparedStatement statement = connection.prepareStatement(sql);
        statement.setInt(1, id);
        statement.setString(2, name);
        // 执行SQL语句并接收返回值
        int ret = statement.executeUpdate();
        System.out.println("ret = "+ ret);
    }
}

使用 :

String name = scanner.next();
int age = scanner.nextInt();
String sql = "insert into student values(?, ?);";
        // 预编译SQL语句, 减少数据库服务器负担
PreparedStatement statement = connection.prepareStatement(sql);
statement.setInt(1, id);
statement.setString(2, name);

此时可以对statement进行打印:使用System.out.print(statement);

后面就是拼装好的SQL语句. 如果你的插入语句出错了, 你就可以把你的写的SQL语句打印出来, 然后就可以从这里看出来哪里有语法问题. 或者是直接将其拷贝到SQL控制台去操作.

以上只是给出了int和varchar类型数据的插入. 类似的还有DATETIME, Long等类型:

DriverManager

除了DataSource这种写法, 还有一种写法为DriverManager, DriverManager是通过反射的方法来加载驱动包中的类, 进一步进行后续的SQL语句等相关操作.

反射属于java的特殊手段, 相当于伤敌一千, 自损八百的那种类型, 其代码的可读性非常差, 编译器难以对代码的正确性进行验证和检查, 非常容易在运行的时候产生异常. 所以在使用上更推荐DataSource.

而DataSource类内置了数据库连接池, 可以复位连接, 提高服务器的效率.

那什么是数据库连接池呢? 可以类比于字符串常量池, 池(pool) 是计算机中使用非常广泛的专业术语, 本质上就是对资源进行 预申请, 就相当于使用空间换时间,

总结

  1. 什么是数据库API
  2. 什么是数据库JDBC编程
  3. 如何导入数据库(包含数据库驱动包的下载)
  4. 编写代码
  5. 创建数据源, 描述数据库服务器的位置
  6. 和服务器建立连接
  7. 构造SQL语句
  8. 执行SQL语句
  9. 释放资源
  10. 新的类和方法
  11. DataSource, 描述数据源
  12. Connection, 和数据库服务器建立连接(由数据源建立)
  13. PreparedStatement, 对SQL语句进行一个预编译, 让数据库服务器减轻相关负担
  14. ResultSet, 查询操作的结果集合, 使用while和next来遍历
  15. 硬编码: 方便书写
  16. 为什么要对资源进行释放


相关实践学习
基于CentOS快速搭建LAMP环境
本教程介绍如何搭建LAMP环境,其中LAMP分别代表Linux、Apache、MySQL和PHP。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
19小时前
|
Java 数据安全/隐私保护
Java 封装:打破传统,创新你的编程思维!
【6月更文挑战第16天】Java中的封装是将数据和操作数据的方法封装在类中,隐藏内部细节,通过公共接口交互。这样保证了数据安全,降低了耦合度,便于验证(如`Shape`类中构造函数的类型检查)和控制(如`setType`方法中添加额外操作)。封装使代码更清晰、可维护,鼓励创新编程思维。
|
1天前
|
Java
谁说 Java 封装很难?跟我学,秒变编程大神!
【6月更文挑战第15天】Java封装,就是将数据和相关操作打包,保护数据免受非法访问。比如`SuperHero`类,它的属性用`private`隐藏,通过`get/set`方法控制访问。这样提高了数据安全性和稳定性。就像超级英雄的超能力,不能随意使用。掌握封装,编程就变得更简单,助你成为Java大神!开始征服代码高峰吧!💪🎉
|
1天前
|
Java 程序员
Java关键字:不只是简单的词汇,更是编程的“魔法咒语”!
【6月更文挑战第15天】Java关键字是编程的基石,如&quot;class&quot;定义类,&quot;new&quot;创建对象,&quot;if/else&quot;控制流程,&quot;for/while&quot;实现循环,&quot;public/private&quot;设置访问权限。示例展示了如何使用这些关键字来定义类、条件判断和循环,强调掌握关键字对提升代码效率至关重要。
|
2天前
|
存储 设计模式 前端开发
[笔记] 疯狂JAVA讲义(第3版)第12章 Swing编程
[笔记] 疯狂JAVA讲义(第3版)第12章 Swing编程
|
2天前
|
前端开发 Java 图形学
[笔记] 疯狂JAVA讲义(第3版)第11章 AWT编程
[笔记] 疯狂JAVA讲义(第3版)第11章 AWT编程
|
2天前
|
存储 Java 编译器
【编程秘籍】掌握这些技巧,让Java中的条件语句if-else和switch为你的项目加分!
【6月更文挑战第14天】本文探讨了在Java中优化if-else和switch语句的方法,以提高代码可读性和维护性。通过案例展示了如何使用Map替换if-else结构,简化会员等级折扣计算,并利用switch语句处理有限选择,以及在操作类型增加时采用策略模式或工厂模式。此外,文章还提到了性能考量,指出在不同场景下选择合适的条件语句。掌握这些技巧对于提升代码质量和性能至关重要。
|
2天前
|
算法 安全 Java
什么是Java伪随机数,基础打牢。 #程序员 #Java #编程
什么是Java伪随机数,基础打牢。 #程序员 #Java #编程
6 0
|
2天前
|
存储 安全 Java
Java多线程编程--JUC
Java多线程编程
|
2天前
|
安全 Java
Java 并发编程详解:Lock 接口及其实现 ReentrantLock
Java 并发编程详解:Lock 接口及其实现 ReentrantLock
9 1
|
2天前
|
Java Maven 数据安全/隐私保护
详解 Java AOP:面向方面编程的核心概念与 Spring 实现
详解 Java AOP:面向方面编程的核心概念与 Spring 实现
13 1