文章目录
一、JDBC概念及其诞生原理
1.1 什么是JDBC
JDBC(Java Database Connectivity java数据库连接)是Java提供的一套用来操作数据库的API,程序员可以通过调用该 API 来操作数据库。
- API VS interface:
- API VS interface:应用程序编程接口(Application Programming Interface),是一个广义的概念。Java中的一个类,一个interface接口都可以理解为一个API。
- interface:Java中的一种特殊的语法格式,interface可以作为Java中一种提供API的方式
1.2 诞生原理
- 不同数据库提供的不同API
一个成熟的数据库(MySQL、Oracle、SQLServer、SQLite等)一般都会提供一些API 供程序员使用,但由于各自负责设计的工程师不同,所以各个数据库提供的API不同。所以一旦程序员要进行与数据库相关的编程,就需要学习相对应的API,十分麻烦。 - Java 统一口径,提出JDBC
JDBC就是Java这边提出的一套操作数据库的API,Java要求每个数据库都遵循Java提供的JDBC API,所以Java程序员只需要了解如何调用JDBC的API即可。 - 其他的数据库API是如何遵循JDBC的
每个数据库厂商提供了数据库的驱动包(一些代码),类似于翻译,将API进行转化
二、使用步骤
2.1 创建项目
2.2 引入MySQL的驱动包,作为项目的依赖
-
MySQL驱动包:
- 名字:mysql-connector-java
- 版本问题:数据库驱动包的版本要和数据库服务器的版本一致(小版本不要求,大版本要求一致),选择【jar】
-
关于jar包:
- .jar 是 Java定义的一种压缩格式
- 类似于rar这样的压缩包,主要包含了很多.class文件
- 实用性:jar 包是Java中发布程序的一种典型方式
要想发布程序给别人,就需要发送.class文件(由,java文件编译而来),而一旦要发送的class文件很多,就会很繁琐,此时jar包的形式可以提高发送效率
-
如何下载MySQL驱动包:
- Oracle 官方网站
- GitHub/Gittee
- 中央仓库:相当于应用商店,有人将知名的第三方库都收集起来,方便人使用
-
如何在项目中导入这个jar包:
- 创建一个目录lib(library 库)
- 直接将下载好的驱动包拷贝到 lib 中
- 选中 lib,选择 [Add as library] 。配置一下,使 idea 知道该目录放的是库文件,直接点ok即可
2.3 编写代码
(1)创建一个数据源 DataSource:
数据源:数据从哪来,以及数据库服务器在哪
DataSource dataSource = new MysqlDataSource();
- DataSource:由JDBC提供的一个接口
- MysqlDataSource:Mysql驱动包中提供的类,实现了 DataSource 的接口
(2)给DataSource对象设置属性
((MysqlDataSource) dataSource).setUrl("jdbc:mysql://127.0.0.1:3306/Test?characterEncoding=utf8&useSSL=false");
((MysqlDataSource) dataSource).setUser("root");
((MysqlDataSource) dataSource).setPassword("123456");
-
为什么要强转为 MysqlDataSource:为了调用这三个方法
setUrl、setUser、setPassword 这三个方法只有MysqlDataSource子类有,父类 DataSource 没有 -
为什么要转型,可不可以在第一步中用“MysqlDataSource x = new MysqlDataSource(),然后用x调用3个方法:
理论上可行,但转型主要是为了降低 Mysql驱动包 和项目代码之间的耦合关系,不让MysqlDataSource 这个类扩散到代码的其他部分,避免后续更换数据库时,有太大的成本。 -
setUrl:
- URL:唯一资源定位符,通常使用URL来描述网络上的一个资源的位置,mysql本体是服务器,相当于是网络上的资源
- jdbc:mysql://127.0.0.1:3306/Test?characterEncoding=utf8&useSSL=false
- jdbc:mysql:表示这个url是什么类型/用途的。此处意思是,【给JDBC的mysql使用的】
- 127.0.0.1:一个特殊IP,特指自己的主机
- 3306:端口号,用来区分主机上的应用程序(进程)。Mysql的默认端口号是3306
- Test:数据库名
- characterEncoding=utf8:统一字符集是utf8
- useSSL=false:SSL指HTTPS的加密方案,不写是默认加密,不写的话有可能因为证书有问题,会连不上数据库。false不加密,true加密
-
setUser:一般来说,大家都是【root】
-
setPassword:安装数据库时,自己设置的密码
(3)和数据库建立连接
原理:前面只是描述了数据源信息,并未真正和数据库服务器建立联系。TCP连接
Connection connection = dataSource.getConnection();
- 关于 Connection 版本:
使用 JDBC 提供的(java sql),而不是com,mysql.jdbc(这是Mysql驱动包的Connection) - 异常:
该操作非常容易出现异常,比如服务器不愿意建立连接,或者输入的数据库名、IP等信息有误,没有正确找到服务器等,需要手动处理。
(4)构造SQL语句
String sql = "insert into student values(1, “张三”)";
PreparedStatement statement = connection.prepareStatement(sql);
- 对转换过程的理解:
- 我们构造出来的 sql 语句是 String 类的,但是数据库并不认String类,但是认statement(语句),故我们需要把 String 转换成 Statement 再发给服务器执行
- 但是我们一般不用statement,而是用 prepareStatement(预处理的语句),因为prepareStatement能让客户端先自己初步解析一下SQL,如检查构造的sql语句有没有语法问题。此时服务器就不用做这些检查了,可以在一定程度上缓解数据库服务器的压力。Statement 则是把SQL原封不动的直接发给数据库服务器。
(5)执行SQL语句
int n = statement.executeUpdate();
System.out.println("n = " + n);
- executQuery():
- 本质是“读”操作, 通常用于查询语句
- 方法执行后返回单个结果集 ResultSet,表示了一个“表格”
- executeUpdate():
- 本质都是“写”操作,通常用于更新、插入、删除语句
- 方法返回值是一个整数,指示受影响的行数,
(6)释放必要的资源:Statement、Connection、ResultSet
创建的语句对象和连接对象,都会持有一些计算机的硬件/软件上的资源,这些资源不用了就应该要及时释放。
java中虽然有“垃圾回收”机制,可以自动释放内存,但是计算机的资源又不仅仅是内存,这些其他的资源就需要手动释放(一般都是会提供close方法,专门负责释放资源的方法)
result.close() //如果是查询操作的情况下
statement.close();
connection.close();
- 关闭顺序:先创建的对象,后关闭
- 为什么要close,java不是有“垃圾回收机制吗”:
- 创建的语句对象和连接对象,都会持有一些计算机的硬件/软件上的资源,这些资源不用了就应该要及时释放
- java中虽然有“垃圾回收”机制,可以自动释放内存,但是计算机的资源又不仅仅是内存,这些其他的资源就需要手动释放(一般都是会提供close方法,专门负责释放资源的方法)
- 关闭的对象:
- PrepareStatement 和 DataSource 是都要关闭的
- 如果是查询操作,需要创建 ResultSet 对象,相比于增删查改,还需要额外关闭这个
2.4 JDBC 与 ORM 与 Mybatis
- ORM 和 Mybatis 前景:JDBC 的API一套流程下来,还是十分繁琐的。因此,一些Java大佬对其进行了封装,得到了一些“数据库操作的框架”,如ORM、Mybatis等,这些可以帮助我们更简单的操作数据库
- JDBC 使用前景:虽然项目中不一定直接使用JDBC,往往是使用框架。但JDBC作为最基础的,是不会变的,可以在必要的时候,魔改出框架,或者创造一个新的框架。
三、示例代码
3.1 向数据表中插入一行数据
(1)不涉及动态输入
public static void main(String[] args) throws SQLException {
DataSource dataSource = new MysqlDataSource();
((MysqlDataSource)dataSource).setURL("jdbc:mysql://127.0.0.1:3306/book_test?characterEncoding=utf8&useSSL=false");
((MysqlDataSource)dataSource).setUser("root");
((MysqlDataSource)dataSource).setPassword("123456");
Connection connection = dataSource.getConnection();
String sql = "insert into user values(1, '张三')";
PreparedStatement statement = connection.prepareStatement(sql);
int n = statement.executeUpdate();
System.out.println(n);
statement.close();
connection.close();
}
(2)涉及动态输入
String sql = "insert into user values(?, ?)";
PreparedStatement statement = connection.prepareStatement(sql);
Scanner scanner = new Scanner(System.in);
int id = scanner.nextInt();
String name = scanner.next();
statement.setInt(1, id);
statement.setString(2, name);
- 更改【构造SQL语句部分的代码即可】
- String sql = “insert into student values(” + id + ", " + name + "):
这种写法也可以达到动态输入的效果,但看起来较混乱,而且这种拼接字符串的方式,并不安全(可能会受到SQL注入攻击,黑客会通过一些特定的输入,达成对数据库攻击的效果)。综上所述,并不推荐这种写法 - 关于?:
是一个占位符,占据一个位置,后续PreparedStatement 会把变量的数值,代入到?中 - 关于数字问题:数字是几就指是第几个?,如 setInt(1, id)的1就是指,第一个?
3.2 查询数据表里的所有数据
public static void main(String[] args) throws SQLException {
DataSource dataSource = new MysqlDataSource();
((MysqlDataSource)dataSource).setURL("jdbc:mysql://127.0.0.1:3306/book_test?characterEncoding=utf8&useSSL=false");
((MysqlDataSource)dataSource).setUser("root");
((MysqlDataSource)dataSource).setPassword("123456");
Connection connection = dataSource.getConnection();
String sql = "select * from user";
PreparedStatement statement = connection.prepareStatement(sql);
ResultSet resultSet = statement.executeQuery();
while (resultSet.next()){
int id = resultSet.getInt("id");
String name = resultSet.getString("name");
System.out.println("id:" + id + ", name:" + name);
}
resultSet.close();
statement.close();
connection.close();
}
- 关于修改的地方:【构造SQL语句】 和 【关闭资源】部分
- ResultSet对象:
结果集,是一个“临时表”。它代表符合SQL语句条件的所有行,并且它通过一套getXXX方法提供了对这些行中数据的访问 - ResultSet的遍历问题: