JDBC (JavaDatabase Connectivity) 是用于执行SQL 语句的Java 应用程序接口,由一用Java 语言编写的类和接口组成。
JDBC 是一种规范,各数据库厂商为Java 程序员提供标准的数据库访问类和接口,使得独立于DBMS 的Java 应用程序的开发工具和产品成为可能。
JDBC 概述
JDBC TM是一种应用编程接口,它制定处理表格数据和常见的关系型数据的标准框架
数据库的基本概念:
数据库本质上是表的“智能”容器。
表是由行组成的容器。行(概念上) 是由列组成的容器。
列是具有名称、类型和值的单个数据项目。
ODBC相关知识
ODBC (Open Database Connectivity,开放式数据库连接性) 是基于C 语言的界面,它指向基于SQL的数据库引擎,提供了与数据库通信以及访问数据库元数据( 元数据是关于数据库系统供应商与数据存储方式等方面的信息) 的一致性界面。
SQL 非常适合于操作数据库,但其设计目的是仅作为与数据库通信的工具而设计的,还需要一个更通用和更完整的编程语言,来安排SQL 语句和向数据库输入,并处理结果以供数据操作、视觉显示或报表生成。
Java TM 编程语言和JDBC
编写正确且遵守规范的Java 程序,可以无需重新编译就在任何启用Java技术的平台上运行。启用Java 技术的平台必须支持已知的核心库。
java.sql 包或JDBC 就是这样的一个库,它们可以视为ODBC的可移植版本,且其本身就是重大的标准。 Java 编程语言和JDBC 一起使用,可以给编写数据库应用程序提供正确的可移植性解决方案
JDBC 驱动程序属于类,它实现JDBC 驱动程序界面,并可以为特别的数据库转换程序(一般是SQL) 请求。
大多数的数据库供应商现在都提供驱动程序,以实现特定系统的JDBC API。这些通常都是免费提供的。第三方驱动程序也可以获得。
Sun Microsystems维护着包括来自众多厂商的超过200 个JDBC 驱动程序。
JDBC API 基本的数据访问准则
主要由以下界面(interface) 和类组成:
Driver (interface)
DriverManager (class):驱动管理类通过获取不同数据库的驱动类实现不同的登录方式。
Connection (interface): 用于和数据库进行连接类。
Statement (interface):用于执行静态sql语句
PreparedStatement (interface):用于执行预编译的sql语句,语句中使用?来传值,安全的查询方式。
CallableStatement (interface):用于调用存储过程函数。
ResultSet (interface):游标对象抓取行。
DatabaseMetaData (interface):可以获取数据库的结构信息,表信息,视图
ResultSetMetaData(interface):可以用于获取查询列的信息
JDBC中执行SQL的步骤
1.首先,要将“驱动程序”传递到DriverManager
2.然后获得“连接”
3.其次,创建Statement、PreparedStatement、或CallableStatement,并将它们用于更新数据库或执行查询
4.最后,查询返回包含有已请求数据的ResultSet,ResultSet 是按“类型”检索的。 DatabaseMetaData 和ResultSetMetaData 接口可以用来提供有关数据库或ResultSet的信息。
连接数据库
public static Connection getConnection() throws Exception{
//连接数据库的四要素
//mysql URL 是 jdbc:mysql://ip地址:3306(端口)/数据库名
//oracle URL 是 jdbc:oracle:thin:@ip地址:1521:sid(orcl)
String url = "jdbc:mysql://localhost:3306/test";
//告诉jdbc使用的是什么数据库 不同数据提供一些不同类型
String driverClass="com.mysql.jdbc.Driver";
//
String username="root";
String password="123456";
//需要jvm加载该类
Class.forName(driverClass);
//登录成功
Connection con = DriverManager.getConnection(url,username,password);
return con;
}
查询
public static List<Map<String,String>> queryStu() throws Exception{
Connection con = getConnection();
//Statement用于执行静态的sql语句
Statement statement = con.createStatement();
//ResultSet游标遍历数据行 next()
ResultSet rs = statement.executeQuery("select * from student");
//可以用于获取查询列的信息
ResultSetMetaData rsmd = rs.getMetaData();
//列的总数
int count = rsmd.getColumnCount();
//用于装所有行的数据
List<Map<String,String>> list = new ArrayList<>();
//遍历数据行
while(rs.next()){
Map<String,String> map = new HashMap<>();
//循环获取列名 下标从1开始
for(int i=1;i<=count;i++){
map.put(rsmd.getColumnName(i),rs.getString(i));
}
list.add(map);
}
return list;
}
结果
JDBC 的结构
JDBC 主要有两种接口,分别是面向程序开发人员的JDBC API 和面向底层的JDBC Driver API,如下图所有:
JDBC API
JDBC API 是一系列抽象的接口,它使得应用程序员能够进行数据库连接,执行SQL 语句,并且得到返回结果
一些重要的接口和类:
java.sql.DriveManager:用来处理装载驱动程序并且为创建新的数据库连接提供支持。
java.sql.Connection:完成对某一指定数据库连接功能。
java.sql.Statement:在一个给定的连接中作为SQL执行声明的容器;它包含了两个重要的子类型。
java.sql.PrepareStatement:用于执行预编译的SQL 声明。
java.sql.CallableStatement:用于执行数据库中存储的过程的调用。
java.sql.ResultSet:控制对于给定声明取得结果列的途径。
JDBC Driver Interface
JDBC Driver API 是面向驱动程序开发商的编程接口,对于大多数数据库驱动程序来说,仅仅实现JDBC API 提供的抽象的类就可以了。
当java.sql.DriveManager 需要为一个特定的数据库URL 装载驱动程序时,每个驱动程序就需要提供一个能实现java.sql.Driver 接口的类。
JDBC 驱动程序根据其实现方式分为4 种类型:
第一种驱动程序:JDBC-ODBC 桥
JDBC-ODBC 桥是一个JDBC 驱动,它把JDBC调用转换为ODBC 操作。这个桥使得所有支持ODBC 的DBMS 都可以和Java 应用程序交互。
JDBC-ODBC 桥接口作为一套共享动态C 库提供的。ODBC 提供了客户方一套适合于客户方操作系统的库和驱动。这些ODBC 调用都是C 调用,而且客户必须带有ODBC 驱动和相关的客户方库的本地副本。这限制了它在基于Web 的应用程序中的使用。
第二种本地的JAVA驱动程序
本地Java 驱动程序( native-API partly-Java driver ),因为它们直接将JDBC API 翻译成具体数据库的API。将JDBC调用转换为对数据库的客户端API 的调用。
第三种网络驱动程序
(net protocol all-Java driver (JDBC Proxy)),它将JDBC API 转换成独立于数据库的协议。JDBC 驱动程序并没有直接和数据库进行通讯;它和一个中间件服务器通讯,然后这个中间件服务器和数据库进行通讯。这种额外的中间层次提供了灵活性:可以用相同的代码访问不同的数据库,因为中间件服务器隐藏了Java 应用程序的细节。
第四种是纯Java 驱动程序
(native protocol all-Java driver ),它直接与数据库进行通讯。 很多程序员认为这是最好的驱动程序,因为它通常提供了最佳的性能,并允许开发者利用特定数据库的功能。当然,这种紧密耦合会影响灵活性,特别是如果您需要改变应用程序中的底层数据库时。 这种驱动程序通常高度分布的应用程序。
通过JDBC 访问数据库
使用JDBC 提供的API 对数据库进行操作。
1、建立数据库连接
2、创建数据库表
3、查询数据库
4、修改表数据
第1步:加载驱动程序
Class.forName(“oracle.jdbc.driver.OracleDriver");1. 加载Sun 公司的jdbc-odbc 驱动程序
Class.forName(“com.mysql.jdbc.Driver");
2. 加载Oracle 的驱动程序
Class.forName("oracle.jdbc.driver.OracleDriver");
3. 加载Microsoft SQL Server 的驱动程序
Class.forName("com.microsoft.jdbc.sqlserver.SQLServerDriver");
第2步:建立连接
DriverManager 类的getConnection(String url) 方法用于建立与某个数据源的连接。
每个JDBC 驱动程序使用一个专门的JDBC URL 作为自我标识的一种方法。 JDBC URL 的格式为:jdbc:sub-protocol:database locator。子协议(sub-protocol) 与JDBC 驱动程序有关,可以是odbc、oracle、db2 等等,根据实际的JDBC 驱动程序厂商而不同。
数据库定位器(database locator) 是与驱动程序有关的指示器,用于唯一指定应用程序要和哪个数据库进行交互。根据驱动程序的类型,该定位器可能包括主机名、端口和数据库系统名。
第3步:建立数据库连接
String url = “jdbc:odbc:pubsdb”;
Connection con = DriverManager.getConnection(url);
//或者
Connection con = DriverManager.getConnection(url, username,password);
常见的几种JDBC URL
//1. Sun的jdbc-odbc 驱动的URL
url = “jdbc:odbc:pubsdb”;
//2. Microsoft SQL Server 的URL
url=“jdbc:microsoft:sqlserver://127.0.0.1:1433;databaseName=mydb”;
//3. Oracle 的URL
url=“jdbc:oracle:thin:@127.0.0.1:1521:myora”;
//4.mysql 的URL
url=“jdbc:mysql://127.0.0.1:3306/mydb;
ResultSet中的获取数字类型值
Statement与PreparedStatement
1.atement 对象在每次执行SQL 语句时都将该语句传给数据库,在多次执行同一语句时,这样做效率较低。
2.可以使用PreparedStatement 对象。如果数据库支持预编译,它可以将SQL语句传给数据库作预编译,以后每次执行这个SQL 语句时,速度就可以提高很多。如果数据库不支持预编译,则在语句执行时,才将其传给数据库。这对用户来说是透明的。
3.eparedStatement 对象的SQL 语句还可以接收参数。在语句中指出需要接收哪些参数,然后进行预编译。在每一次执行时,可以给SQL 语句传输不同的参数,这样就大大提高了灵活性。
4.eparedStatement 接口是Statement 接口派生的子接口,因此它可以使用Statement接口中的方法。
使用事务(Transactions)
如何把一系列语句组织成一个事务?
如果事务中所有命令都能正确执行,就可提交这个事务;否则,如果事务中有一个命令出现错误,回滚这个事务,并返回到提交以前的状态,好像什么也没有发生。
把所有命令组合成事务的主要目的是为了保证数据库的完整性。
对于一个事务而言,要么事务中语句全部得到正确执行,事务可被提交了,要么它中间出现错误。后一种情况,可以调用rollback() 方法,数据库将自动放弃上一次提交事务以来的全部变化。
一个数据库连接的缺省模式是autocommit 模式,每个SQL 命令一执行就会提交给数据库。一旦某个命令已提交,就不能把它退回。
可以用Connection 接口的getAutocommit() 方法,检验数据库的目前自动提交模式设置。
用命令con.setAutoCommit(false) 方法关闭自动提交模式。
用con.commit() 命令提交事务。
用con.rollback() 回滚一个事务。
存储过程调用(一)
很多数据库都支持在数据库内部执行的函数。这种方法有几个好处,包括更快的性能和改进的安全性。这些函数称为存储过程,而且虽然它们通常是用SQL 编写的,但也可以用数据库支持的任何编程语言编写。
随着Java 语言日趋流行,几个数据库厂商(包括Oracle 和IBM) 都启用了Java语言创建存储过程,还可以在不同数据库之间移动存储过程。存储过程可以支持三种类型的参数:IN、OUT 和INOUT,这对于存储过程在数据库内部真正能做什么来说,带来了很大的灵活性。
不管存储过程是用什么语言编写的,它都能以一种标准的方式从Java 应用程序调用。
存储过程的调用(二)
首先,您需要创建一个CallableStatement 对象。为了标识存储过程和过程需要的参数的类型和数量,还要允许使用三种类型的调用。下面的清单说明了这三种类型(假定我们正在调用一个名为AuthorList 的存储过程):
1、 {call AuthorList} 如果过程不需要参数
2、 {call AuthorList[(?, ?)]} 如果过程需要两个参数3、 {? = call AuthorList[(?, ?)]} 如果参数需要两个参数并返回一个
批处理
PreparedStatement ps = conn.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS);
for(int i=0; i<1000; i++) {
ps.setString(1,"Batch Name"+i);
ps.setDate(2, new java.sql.Date(System.currentTimeMillis()));
ps.setFloat(3, 3333.33f);
ps.addBatch();//将数据打包
} ps.executeBatch();//执行打包后的sql
JDBC Meta Data (元数据)
JDBC的元数据接口有:
DatabaseMetaData数据库级
ResultSetMetaData结果集级
DatabaseMetaData (数据库元数据)
在对数据源进行连接以后,得到一个Connection 的对象,可以从这个对象获得有关数据源的各种信息,包括关于数据库中的各个表,表中的各个列,数据类型和存储过程等各方面的信息。 根据这些信息,JDBC 程序可以访问一个事先并不了解的数据库。获取这些信息的方法都是在DatabaseMetaData 的对象上实现的,而DatabaseMetaData 对象是在Connection 对象之上获得的。
以在一个连接的基础上创建一个DatabaseMetaData 对象;
DatabaseMetaDatadbma =con.getMetaData();
例:
//批处理 批量导入数据
public static void processingBatch(List<Map<String,String>> list) throws Exception{
//获取与数据库的连接
Connection con = getConnection();
String sql = "insert into stu values(?,?,?,?)";
//用于执行预编译的sql语句,语句中使用?来传值,安全的查询方式。
PreparedStatement pst = con.prepareStatement(sql);
for(Map<String,String> map:list){
pst.setInt(1,Integer.valueOf(map.get("s")));
pst.setString(2, map.get("sname"));
pst.setInt(3,Integer.valueOf(map.get("sage")));
pst.setString(4, map.get("ssex"));
//加入批处理
pst.addBatch();
}
pst.executeBatch();
pst.close();
con.close();
}