简说 JDBC (小白入门必备)

最近一直在忙着自己的一个小项目,没来得及写点东西,很是惭愧。本人也看过很多关于 JDBC 的文章,而本人希望以一个初学者的角度通过本篇文章把其他关于 JDBC 文章中精华的部分提取出来,并加上自己的理解来谈一谈 JDBC,并尽量做到浅显易懂,希望能对各位有所帮助。

JDBC 是什么

JDBC 代表 Java 数据库连接(Java Database Connectivity),它是用于Java编程语言和数据库之间的数据库无关连接的标准 Java API,换句话说:JDBC 是用于在 Java 语言编程中与数据库连接的 API。

JDBC API 支持用于数据库访问的两层和三层处理模型,但通常,JDBC 体系结构由两层组成:

  • JDBC API:提供应用程序到 JDBC 管理器连接。
  • JDBC 驱动程序 API:支持 JDBC 管理器到驱动程序连接。

JDBC API 使用驱动程序管理器(JDBC Driver Manager)并指定数据库的驱动程序来提供与数据库的连接。

JDBC 驱动程序管理器(JDBC Driver Manager)确保使用正确的驱动程序来访问每个数据源。 驱动程序管理器(JDBC Driver Manager)能够支持连接到多个数据库的多个驱动程序。

下图是我看到的一个比较好的 JDBC 架构模型图(后面会对这张图做出详细的解释):

JDBC 架构

我个人把使用 JDBC 划分为了以下六个步骤:

  • 加载驱动
  • 创建链接对象
  • 创建 sql 命令对象
  • 执行 sql 命令
  • 判断执行结果
  • 关闭资源

以上步骤就好比是打电话让朋友帮忙办件事儿,首先你得有个手机(加载驱动),然后利用手机给朋友打电话(创建链接对象),朋友接到电话(创建 sql 命令对象)然后执行你的要求(执行 sql 命令),执行命令之后朋友给你一个反馈,你来对这个反馈进行处理(判断执行结果),最后挂断电话(关闭资源)。

常见的 JDBC 组件

JDBC API 提供以下接口和类:

  • DriverManager:此类管理数据库驱动程序(也就是 Driver)。使用某种协议(无需纠结是什么协议)将来自 java 应用程序的连接请求与适当的数据库驱动程序进行匹配,然后进行一系列操作连接到数据库。
  • Driver:此接口处理与数据库服务器的通信,我们很少会直接与 Driver 对象进行交互,但会使用上面提到的 DriverManager 对象来管理这种类型的对象。
  • Connection:此接口具有用于联系数据库的所有方法,与数据库的所有通信都是通过该对象完成的。
  • Statement:使用此接口创建的对象将 sql 语句提交到数据库,执行 sql 命令。
  • PreparedStatement:此接口和 Statement 接口类似,用此接口创建的对象执行 sql 命令。
  • ResultSet:执行 sql 语句查询后,将返回后的数据存放在该对象中。

具体 JDBC 应用程序

1、向数据库插入数据

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
//导入需要的包,大多数情况下,使用 import java.sql.* 应该就足够了
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
public class TestJdbc {
public static void main(String[] args) throws ClassNotFoundException, SQLException{
//1、加载 JDBC 驱动
Class.forName("oracle.jdbc.OracleDriver");
//2、利用驱动创建链接对象
Connection conn=DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:orcl","(数据库账户名)","(密码)");
//3、创建 sql 命令对象并创建 sql 语句
String sql="insert into tdept values('x','xxx','x')";//往数据库插入数据
Statement stmt =conn.createStatement();
//4、执行 sql 命令并获取处理结果(是否插入成功)
int i=stmt.executeUpdate(sql);
//5、处理结果
if(i>0){
System.out.println("插入成功");
}else{
System.out.println("插入失败");
}
//6、关闭资源
stmt.close();
conn.close();
}
}

这段代码属于向数据库中插入数据,所以不用 ResultSet 对象,对于数据的增、删、改一般返回值都是一个 int 型数值(此处命名为 i),当对数据操作成功后返回值 i 为1,否则,返回值为 -1。

而对于数据的查询一般都是需要用 ResultSet 对象来接住返回结果的。

2、查询数据库中的数据(加入异常处理)

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
//导入需要的包
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class TestSelect {
public static void main(String[] args){
//声明链接参数
String url="jdbc:oracle:thin:@localhost:1521:orcl";
String user="scott";
String pwd="123";
String driver="oracle.jdbc.OracleDriver";
//声明jdbc变量
Connection conn=null;
Statement stmt =null;
ResultSet rs=null;
try {
//加载驱动
Class.forName(driver);
//创建链接对象
conn=DriverManager.getConnection(url,user,pwd);
//创建 sql 命令对象并执行 sql 命令
String sql="select * from emp";
stmt=conn.createStatement();
//获取结果
rs=stmt.executeQuery(sql);
//处理结果
System.out.println("学号\t姓名\t班级");
while(rs.next()){
System.out.println(rs.getInt("deptno")+"\t"+rs.getString("daname")+"\t"+rs.getString("loc"));
}
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
//关闭资源
try {
stmt.close();
conn.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}

这段代码可以看成是用 JDBC 的正常步骤,先声明链接对象、声明 jdbc 对象,然后执行上面的六个步骤。

也许你会问,为啥是这几个步骤呢,因为… … 没有原因,就这么来用的,别在没必要的地方纠结。

到这里可能会有人对 ResultSet 有疑问,ResultSet 到底是个什么东东?其实可以把 ResultSet 看成一个迭代器:
Resultset 示意图
最开始的时候,指针处于黑色线条处,当 sql 语句被执行之后,返回的数据储存在 Resultset 中(如果有的话),然后当程序执行到 rs.next() 的时候,指针下移,指向返回的第一条数据,如果这条数据不为空(也就是说有返回的数据)时,rs.next() 为 true,然后进入 while 循环对返回的数据进行操作。

PreparedStatement 对象与 Statement 对象

在这里需要对这两个对象进行一定的解释但不深究,其实也没必要深究,自从我用 jdbc 以来,基本上都是用的 PreparedStatement对象,很少用 Statement,在此处就不深入探讨了还请见谅。

  • 使用 PreparedStatement可以防止 sql 注入(有兴趣的同学可以参考 sql 注入原理讲解),因为在创建此对象的时候已经将SQL传入,这样可以针对性的进行赋值.
  • PreparedStatement 的执行效率比 Statement 高

且看以下代码:

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
//导入包
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Statement;
public class TestPreparedStatement {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
//创建链接参数
//声明jdbc变量
//加载驱动
Class.forName("oracle.jdbc.OracleDriver");
//创建链接对象
Connection conn=DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:orcl", "(数据库账户)","(数据库密码)");
//创建 sql 命令对象并发送 sql 命令
String sql="insert into t_user values(?,?,?)";
& PreparedStatement ps=conn.prepareStatement(sql);
//PreparedStatement 可以给字段针对性的进行赋值
ps.setInt(1,6);
ps.setString(2,"李四");
ps.setString(3,"123");
&& int i=ps.executeUpdate();
//使用 Statement 的写法
String sql2="insert into t_user values(5,'张三','123')";
& Statement st=conn.createStatement();
&& int j=st.executeUpdate(sql2);
//获取结果
//处理结果
//关闭资源
}
}

从上面的代码可以看出(为了方便大家对比,不产生冗余,获取结果之后的代码在这里就不写出来了),创建 sql 命令对象的方式不同(标&处),另外执行 sql 命令的方式也不相同(标&&处),而且 PreparedStatement 可以给字段针对性的进行赋值,这点是这是 Statement 所不具备的,一般使用过程中使用 PreparedStatement 较多。

以上这些是两者使用方式的不同,个人觉得不需要深究,如果不理解,敲代码,敲代码,敲代码!!!学习一门技术如果只是纸上谈兵,永远也学不好,看完之后更重要的是要实践,毕竟实践是检验真理的唯一标准,而且你亲自多敲几遍代码会对知识有更深的理解。

以上只是个人的愚见,如有不妥之处,还请指出,一定改进!