什么是JDBC
JDBC(Java DataBase Connectivity,java数据库连接)是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java语言编写的类和接口组成。JDBC提供了一种基准,据此可以构建更高级的工具和接口,使数据库开发人员能够编写数据库应用程序
来自百度百科。
简而言之,如果我们想要在Java项目中连接并使用数据库,那么就要学会使用JDBC技术。利用JDBC就能连接数据库,插入、查询等等操作。
Java、JSP等等都可以使用。当然,首先要对Java和SQL有一定的了解才能学JDBC,然后关于数据库,下文用的是MySQL,因为是入门级文章,所以SQL语句还是比较简单的。
JDBC的架构图
JDBC 驱动选择
JDBC提供的API可以使得我们使用Java代码来操控程序,同时对于不同的数据库,我们需要用对应的驱动,也就是JDBC Driver来适配。
这也算是JDBC的一个缺点了,必须对应不同的数据库安装不同的驱动。
JDBC的一些接口
这一部分可以暂时跳过,撸代码的时候可以来看一看,这里算是一个小小的总结吧:
类名 | 描述 |
---|---|
DriverManager | 管理驱动的接口,可以识别确定驱动,并且进行匹配与连接 |
Driver | 驱动,处理与数据库的通信,一般用 DriverManager 来管理 |
Connection | 连接数据库 |
Statement | 提交 SQL 语句 |
ResultSet | 结果集,例如我们使用 select 查找以后,返回的数据就是一个结果集。类似于 Iterator 的方式可以遍历结果集 |
另外,SQL异常是有:SQLException。这些东西博主写的非常浅显,有需要的推荐专门搜索一些这些接口的功能,或者去阅读API。
驱动程序的安装
默认已经安装好JDK环境以及数据库的环境,再提醒一次,本文用的数据库是MySQL,默认已经安装好MySQL了,MySQL还是比较好安装的。
MySQL的驱动可以直接去下载,网页:
关于驱动的版本与MySQL的版本问题,有专门的版本对照表,不过如果是新下载的MySQL,那么使用最新的驱动是没问题的。如果害怕版本错误,最好先看一下自己的MySQL的版本,然后专门百度一下对应的JDBC驱动版本,这样就没有问题了。
因为是windows平台,所以下载zip压缩包就可以了,随便放在哪个位置都可以。
解压缩以后重要的是jar包,我们需要把jar包导入到IDE中就可以了。jar包的导入就不细说了,常用IDE像myeclipse、idea等网上一大堆。
如果用的不是MySQL数据库,一般都会提供对应的驱动,大家网上搜一搜下载就可以了。
JDBC驱动注册
数据库连接的第一步是注册(并不是连接),上面不是写过,DriverManager是负责管理驱动的,而驱动本身是Driver。
我们需要将Driver类加载到内存中。这里牵扯到了一行经典代码:
1
Class.forName("com.mysql.jdbc.Driver");
据说好多人是从这里入门JVM的不知道真假= =。
众所周知,Java源代码在经过编译以后是生成字节码文件(.class文件)的,而对于JDBC技术而言,我们需要使用Driver这个类,那么我们就应该使用类加载器,先将Driver类在内存中初始化,这样才能使用。
所以,注册就是在内存中实例化的过程。
那么当然,此时是可能抛出ClassNotFound异常的,需要捕捉。
# 数据库的连接
驱动注册之后就是连接了,根据上面写的常用接口,连接数据当然要使用Connection。
我们可以实例化一个连接对象,这个对象就代表了与数据库的连接。而这个连接的获取来源于驱动。
上面也写过,Driver本身是由DriverManager所管理的,所以我们有DriverManager的一个方法,来创建一个连接的实例。
```java
static String url = "jdbc:mysql://localhost:3306/数据库名";
static String username = "数据库用户名";
static String passwd = "数据库密码"
Connection con = (Connection) DriverManager.getConnection(url, username, passwd);
利用DriverManager的getConnection()
方法就可以获得一个连接实例了。
当然参数需要确定:数据库是什么、账号、密码。
这样利用Connection的实例就可以干很多操作了。注意这里也需要写异常处理,所以驱动注册、数据库连接,以及后续的数据库操作很多都是声明静态变量,然后在try块中进行操作,例如:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class Main{
static Connection conn = null;
static String url = "jdbc:mysql://localhost:3306/javatest";
static String username = "root";
static String passwd = "root";
public static void main(String[] args){
try{
Class.forName("com.mysql.jdbc.Driver");
conn = (Connection) DriverManager.getConnection(url, username, passwd);
}catch(Exception ex){
ex.printStackTrace();
}
}
}
SQL语句的提交
对数据库的操作是使用SQL语句,那么JDBC用的最多的部分就是在Java代码中写入SQL语句来对数据库进行操作。
还是看上面的接口表,Statement提供了从Java中向数据库提交SQL语句的方法,那么我们用Statement就可以对数据库进行操作。
但是Statement类用着不是很方便并且效率不高,一般地,我们用其子类PreparedStatement。PreparedStatement的详解就不太入门了,这里就不多说。
首先,SQL语句就用String类型来写,然后利用Connection来将改SQL语句处理为一个PreparedStatement实例,然后对于PreparedStatement实例就可以进行各种操作。
先看代码,以一个insert语句为例:
1
2
3
String sql = "insert into tests value('a','b','c');";
PreparedStatement ps = (PreparedStatement)conn.prepareStatement(sql);
ps.executeUpdate();
可以看到,Connection的实例是连接,其preparedStatement()
方法可以在该连接上创建一个SQL语句的实例,然后PreparedStatement的实例就可以调用运行函数来再合适的地方运行这个SQL语句。
这个运行方法是根据SQL语句的不同而有变化的。
上例插入的是insert语句,那么就要调用executeUpdate()
函数。由于正常数据库中insert也没有什么返回值所以就直接运行了,而例如select等语句,就会返回一个结果集,这个在接下来会写。
方法名 | 描述 |
---|---|
executeUpdate() | 执行的 SQL 语句应是 insert、delete 等没有返回值的语句 |
executeQuery() | 执行 SQL 语句,但是返回了一个结果集 |
execute() | 可执行任何 SQL 语句 |
如上表,executeUpdate()
和executeQuery()
用的相对多一点,很好理解,select就用executeQuery()
,其他不需要得到返回结果的就用executeUpdate()
。
另外,executeUpdate()
对于DDL语句也是支持的。
PreparedStatement对象需要被关闭,这个比较简单,close()
方法调用即可。
如果先对Connection对象进行关闭的话,PreparedStatement对象也会直接被关闭。所以想要省事的话可以最后统一关闭。
当然这个习惯貌似不太好,最好还是在需要关闭的时候及时关闭PreparedStatement对象。
结果集
结果集,ResultSet,顾名思义,SQL语句执行后的结果被存放进来。我们可以像Iterator一样利用指针移动的方式来获取结果。
对于一个ResultSet的对象,初始指针位置可以通过移动,一步一步地向末尾移动。
我们可以把一个ResultSet想象成正常SQL语句返回的一张表的结果,指针指的就是每一行,移动也是按行移动。
对于每一行,我们可以获取到具体列的数据,同时还可以对其数据进行修改(此时就不需要再重新写SQL语句了)。
指针移动是很灵活的,不是说跟Scanner一样一直next:
方法名 | 描述 |
---|---|
void first() | 指针移动到第一行 |
void last() | 指针移动到最后一行 |
void beforeFirst() | 指针移动到第一行之前 |
void afterLast() | 指针移动到最后一行之后 |
boolean absolute(int row) | 指针移动到指定行,返回值代表是否能够移动 |
boolean previous() | 指针移动到上一行,返回值代表指针是否还在结果集内 |
boolean next() | 指针移动到下一行,返回值代表指针是否还在结果集内 |
int getRow() | 返回当前行号 |
可以看出有很多种操作,可以让我们很方便地使用结果集。下面写一下select的代码与ResultSet的使用:
1
2
3
4
5
6
7
String sql = "select * from dept";
PreparedStatement prepared = (PreparedStatement)conn.prepareStatement(sql);
ResultSet rs = prepared.executeQuery();
while(rs.next()){
System.out.println("name: "+rs.getString(1));
System.out.println("number: "+rs.getString(2));
}
这个代码还是很简单的,只是在while循环中一直使用next()
来遍历了整个结果集。
不过这个代码主要使用了getString()
这个方法。我们知道,指针指向的是结果集的一个行,那么具体到某列就需要用getString()
方法。
不过这个get方法是有很多的,就好像对于数据库而言,列的数据结构是有很多的。那么相对地就有很多不同的get方法,例如:getInt()
、getDouble()
等。
上面也说道,我们可以直接更新结果集,对应的数据库中的数据也会被更新。这个更新并不是SQL语句中的更新一行,而是可以确定某个列的情况下单独更新数据。例如:
1
2
3
rs.updateInt("number",1);
rs.updateString("name","iwts");
rs.updateRow();
具体更新列的数据结构是什么,就要用对应的方法来更新。update支持Java的8中数据结构和一些例如String的特殊数据结构。当然,这样更新完后数据库是没有变化的,updateRow()
方法就好像一个提交按钮一样,提交更新结果。
方法名 | 描述 |
---|---|
void updateRow() | 更新当前行 |
void deleteRow() | 删除当前行 |
void cancelRowUpdates() | 取消对当前行所做的所有更新 |
void insertRow() | 在当前位置插入行 |
void refreshRow() | 刷新结果集 |
那么,这些方法都是如字面意思的操作,唯一需要多解释的是insertRow()
插入行方法。
在数据库正常操作也是,不能指定在某一行进行插入,在JDBC也一样,只有在当前指针指向位置可以插入行的时候才能够调用insertRow()
方法,我们可以用afterLast()
方法来直接移动到最后一行的下一行并且进行插入。
也跟更新一样,插入也是单独写上所有列的数据之后再进行插入。最后调用insertRow()
方法,代码如下:
1
2
3
rs.updateInt("number",1);
rs.updateString("name","iwts");
rs.insertRow();
对于每列新加的数据,还是用update。
总结
整体上入门还是蛮简单的,不过是自己在写的时候感觉还行,当初自己写的时候还是写的很不熟练,很多东西也不太了解。其实多写一些数据操作就能慢慢理解了。
这篇博文很入门了,所以很多东西都没写,例如PreparedStatement与Statement的区别啊,SQL相关的事务、批处理啊之类的都没写,所以只能是入门指北了。推荐手搓一遍代码,会理解很多。