JDBC详细介绍
【摘要】JDBC详细介绍~
前言
hi~
JDBC
JDBC概念
JDBC就是为了让java语言有能力去操作数据库,通过它可以发送sql命令,并取得返回的结果。
JDBC, Java Database Connectivity, JAVA数据库互联。
ODBC, Open Database Connectivity, 开放式数据库互联。
这个标准是由MS公司主导的一个标准,所有的数据库厂商的产品都实现了ODBC规范,并且这个标准是采用c语言编写的。这样一来,程序员可以通过ODBC来访问/操作数据库产品。
java语言刚开始时,也是通过ODBC来访问数据库的,但是,java语言需要把java的调用转换成符合ODBC规范的c调用,这样一来,效率就会很低。
在java语言访问数据库的驱动发展历程中,经历了以下4代
A. JDBC-ODBC桥接
B. 本地部份java驱动
C. 基于网络的本地部份java驱动
D. 本地纯java驱动 [第四代驱动]:所有的DB产品的产品都实现了JDBC规范,使用 java语言写。这个实现也叫 驱动[driver]。
所以,JDBC的API 有两部份组成
- 是 SUN 公司提供的 JDBC标准接口 和工具类。
java.sql 包[核心包]
javax.sql 包[扩展包] - JDBC的实现者,也就是各DB厂商的驱动程序。
JDBC有一个很大的优点,就是可以跨DB平台,一次编写,到处[数据库]运行。
JDBC核心包中的核心接口
java.sql.Driver 接口 驱动类接口,实现JDBC驱动的数据库产品必需要实现此接口java.sql.DriverManager 驱动管理类,它是连接的桥接器,它可以获取Connection。
注:在JDBC4.0规范中,做了修改,可以不需要事先注册驱动了。
1 | java.sql.Connection 连接[可以想象成客户端程序与DB之间的网络通道] |
JDBC编程步骤
- 注册数据库驱动
1
2//DriverManager.registerDriver(具体的驱动类)
Class.forName("驱动的全限定类名"); //它仅仅是一个字符串
- 注:不同的数据库产品,驱动类名不一样,如:
Oracle => oracle.jdbc.OracleDriver
mysql => com.jdbc.mysql.Driver
DB2 => i don’t know
sqlserver => i don’t know
… - 注:在JDBC4.0规范中,此步可以省略[DriverManager会自动搜索项目的类路径,找到并加载目标驱动,可以有多个]
- 建立连接
1
2
3
4String url = "jdbc:oracle:thin:@127.0.0.1:1521:XE";
String user = "jsd1707";
String pwd = "jsd1707";
Connection conn = DriverManager.getConnection(url, user, pwd); - 创建Statement
1
Statement stmt = conn.createStatement(); //空参
- 发送并执行 sql命令
1
2
3
4String sql = "select id,first_name,salary,start_date from s_emp"; //准备的sql命令
ResultSet rs = stmt.executeQuery(sql); //执行查询语句
//boolean b = stmt.execute(sql); //执行任意SQL语句
int count = stmt.executeUpdate(sql); //执行非查询语句 - 如果是查询命令,则处理结果集
1
2
3
4
5
6
7
8while(rs.next()) { //循 环读到结果集中的数据
//取列值
int id = rs.getInt(1); //取第一列
String fn = rs.getString(2);
double sal = rs.getDouble(3);
Date sd = rs.getDate(4);
//...
} - 释放资源
1
2
3rs.close();
stmt.close();
conn.close();
使用PreparedStatement 来执行sql命令
它的好处:
A.可以动态绑定参数,避免了SQL字符串的拼接,更加安全。
B.支持预编译,事先把sql送到数据库中编译、优化,然后,给定参数后再执行,如果执行多次话,只需要给出不同的参数即可,SQL本身无需再次编译、优化。缺点:
一个PreparedStatement只能绑定1条sql命令。
1 | // |
JDBC事务 [transaction]
Why use?
注:当删除主表记录时,如果这个记录有子记录存在,则删除是会失败的。
如果你想在删除主记录时,一起把子记录删除,有如下两种方式
编程式
在JDBC代码中,先删除子记录,再删除主记录,如:1
2
3
4delete from tbl_emp where dept_id = ?;
delete from tbl_dept where id = ?
--这两个?处的值是一样的。注:这种方式有一个很大的缺点,就是 牵一发而动全身。
就在建表时,指定外键在删除时的处理方式
当我们在添加外键约束时,可以指定如下两个选项:A. ON DELETE CASCADE
B. ON DELETE SET NULL
如:1
2
3
4
5
6
7
8
9
10
11create table tbl_dept(
id number primary key,
name varchar2(255)
);
create table tbl_emp(
id number primary key,
...,
dept_id number,
--添加外键
foreign key(dept_id) references tbl_dept(id) ON DELETE CASCADE
);JDBC事务概念
JDBC事务 [transaction]为了让JDBC跨多个数据库平台,JDBC规范中必然要制定出它自己的事务规范,因为不同的数据库对事务的粒度控制是不一样的。
比如:ORACLE中不允许有脏读,但是,在mysql中可以【需要设置】,它们的级别也不一样,这对于我们编写JDBC程序来说,就比较麻烦。
所以,我们程序人员就针对JDBC事务做出处理,而不是去编写与数据库产品相关的事务代码,在JDBC规范中,提供了事务的隔离级别的控制。
在Connection接口中,定义了5个常量来分别表示不同的JDBC事务隔离级别:
1 | TRANSACTION_NONE 0 |
其中,它们由数据库产品进行实现。
注:设置连接的事务隔离级别不一定有效果。
在Connection中,提供了方法:setTransactionIsolation(int level)
来设置级别。
另外,在JDBC中,默认情况下,事务是自动提交的[Auto Commit]。也就是执行一次sql命令,就自动提交事务一次。
如果你想手动控制事务,则需要:
1 | conn.setAutoCommit(false); // |
JDBC批处理[Batch]
JDBC从2.0规范开始,就支持批处理了,它的目的是为了提高数据插入的效率。利用它,可以高效地插入海量的数据到表中。
1.利用Statement执行批处理
1 | //Code: |
所以,Statement的批处理适合用来加载并执行sql脚本文件中的命令。
2.利用PreparedStatement 来做批处理
1 | //Code |
所以,PreparedStatement 适合用来批量插入同一种结构的数据.
注:select命令是不能使用批处理的。
针对PreparedStatement
1 | //Code |
JDBC元数据
元数据的定义: 用来描述其它数据的数据。它的API有:
1 | DatabaseMetaData 数据库元数据 |
sql异常
sql异常概述
java.sql.SQLException 【已检查异常】它是JDBC规范中顶级的异常,所有的JDBC异常都是继承于此类,如:
1 | SQLSyntaxErrorException 执行sql的语法有错误 |
如
1 | try { |
有关批处理的异常
1 | BatchUpdateException |
连接池 [connection pools]
概念
它是一种维护多个数据库连接的对象,也就是一种数据源的实现方式。在实际的开发中,连接池是比较常用的,因为它能够大大提高连接的使用效率。
正是因为普通的数据库连接使用效率太低,所以,JDBC规范中提出了连接池,它通过javax.sql.DataSource
这个对象来做为获取连接的标准。
DataSource 数据源,它是一个规范[接口],它有三种实现:
1.普通实现,也就是 DriverManager获取连接的方式
2.连接池实现
3.分布式事务实现
获取连接的方式
我们现在获取连接的方式:
1 | Connection conn = DriverManager.getConnection(url,user,pwd); |
连接池的实现
一般我们第三方的实现,如:
Apache组织的 commons-dbcp 组件就一个开源的连接池实现。
或者是一些轻量级的中间件产品,如:Tomcat/Jetty/Resin…
有了数据源,我们获取连接的方式:
1 | 数据源 数据源 = ...; |
所以,问题变成了我们在代码中如何得到 数据源对象?
主流的方式: 通过 JNDI 来获取[要有中间件、容器的支持]
备选方式:下载第三方的实现者,并通过API来创建.
有关commons-dbcp 组件
1 | 核心类: |
分布式事务的实现
它是基于连接池的,它更加复杂,一般也是由第三方提供,而且免费的产品不多,大多都是商业化的、收费的产品,如:
1 | IBM Webshere |
它的两个核概念
1.中央事务管理器
2.二阶段提交 [two phase commit]
结束语
bye~