一、JDBC简介及类型
JDBC(Java Data Base Connectivity,java数据库连接)是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java语言编写的类和接口组成。JDBC为工具/数据库开发人员提供了一个标准的API,据此可以构建更高级的工具和接口,使数据库开发人员能够用纯 Java API 编写数据库应用程序。
由于JDBC本身属于一个标准,所以一个数据库如果希望使用Java进行程序开发的话,那么各个数据库的生产商必须实现这些标准——提供专门的数据库的操作包。
JDBC定义了4种不同的驱动程序,现分述如下:
类型 1: JDBC-ODBC Bridge (JDBC-ODBC桥驱动程序)
在JDBC出现的初期,JDBC-ODBC桥显然是非常有实用意义的,因为当时没有纯JDBC驱动。通过JDBC-ODBC桥,把jdbc方法翻译成ODBC函数调用,使Java应用程序可以通过访问ODBC驱动程序访问数据库。开发人员可以使用JDBC来存取ODBC数据源。不足的是,他需要在客户端安装ODBC驱动程序,换句话说,只能用于windows和Sun Solaris 操作系统。使用这一类型你需要牺牲JDBC的平台独立性。缺点是不易于移植,运行速度慢。
2: JDBC-native driver bridge(本地库Java实现驱动程序)
JDBC本地驱动程序桥提供了一种JDBC接口,它建立在已有本地数据库驱动程序的基础上。 将JDBC方法翻译成本地已有的专用驱动程序。其中的翻译工作采用Java语言实现,而专用驱动程序通常采用C语言编写,依赖于本地库文件运行,因此这种驱动程序中部分由Java实现。他的它的特点是能够利用已有的专用驱动程序,缺点是不具有跨平台型。
JDBC驱动程序将对数据库的API从标准的JDBC调用转换为本地调用。使用此类型需要牺牲JDBC的平台独立性,还要求在客户端安装一些本地代码。
类型 3: JDBC-network bridge(网络协议驱动程序)
JDBC网络桥驱动程序不再需要客户端数据库驱动程序。它使用网络上的中间服务器来存取数据库。由中间件把JDBC方法翻译成数据库客户端请求,再向数据库服务器发送请求,中间件组件和数据库客户端通常位于中间层服务器上。此类驱动程序完全由Java实现,适用于基于网络的分布式应用。这种方式很灵活,但涉及网络安全问题。这种应用使得以下技术的实现有了可能,这些技术包括负载均衡、连接缓冲池和数据缓存等。具有平台独立性,而且不需要在客户端安装并取得控制权,所以很适合于Internet上的应用。
类型 4: Pure Java driver(纯Java驱动方式)
第4种类型是全新结构的驱动程序。它的特点是应用程序直接与数据库服务器端通信。这种方式需要数据库开发商的强力支持。提供基于特定数据库的网络插件,实现对特定数据库的通信协议,使JDBC驱动程序通过网络插件直接与数据库服务器通信。此类驱动程序全部采用Java编写。通过使用一个纯Java数据库驱动程序来执行数据库的直接访问。此类型实际上在客户端实现了2层结构。要在N-层结构中应用,一个更好的做法是编写一个EJB,让它包含存取代码并提供一个对客户端具有数据库独立性的服务。
·类:DriverManager
·接口:Connection、PreparedStatement、Statement、ResultSet
二、主要接口简介
2.1、DriverManager类创建与指定数据库连接
public class DriverManager
{
public static Connection getConnection(String url, String user, String password)throws SQLException
public static Connection getConnection(String url) throws SQLException
}
2.2、Connection接口管理连接对象
public interface Connection
{
Statement createStatement() throws SQLException; //创建执行SQL的语句对象
Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException;
//参数指定结果集属性
void close() throws SQLException; //关闭数据库连接
boolean isClosed() throwsSQLException; //判断数据库连接是否已关闭
DatabaseMetaData getMetaData() throwsSQLException; //获取所连接数据库的元数据
}
2.3、DatabaseMetaData接口获得数据库元数据
public interface DatabaseMetaData
{
String getURL() throws SQLException; //返回连接数据库的URL
String getUserName()throws SQLException; //返回数据库的用户名
String getDatabaseProductName() throwsSQLException; //返回数据库名称
String getDatabaseProductVersion()throws SQLException; //返回数据库版本号
String getDriverName() throwsSQLException; //返回驱动程序名称
String getDriverVersion() throwsSQLException; //返回驱动程序版本号
}
2.4、Statement接口执行SQL语句
public interface Statement
{
int executeUpdate(String sql) throwsSQLException; //执行数据定义和数据更新SQL语句
ResultSet executeQuery(String sql) throws SQLException; //执行数据查询SQL语句
boolean execute(String sql) throwsSQLException; //执行SQL语句
int getUpdateCount() throwsSQLException; //获得数据更新所影响的行数
ResultSet getResultSet() throwsSQLException; //获得数据查询结果集
void close() throws SQLException; //关闭语句
}
2.5、ResultSet接口存储结果集
int getRow() throws SQLException; //获得当前行位置
boolean next() throws SQLException; //设置当前行的后一行成为新的当前行
//获得当前行指定列的数据项值
Object getObject(int columnIndex) throws SQLException;
Object getObject(String columnName) throws SQLException;
String getString(int columnIndex) throws SQLException;
String getString(String columnName) throws SQLException;
例如,
while(resultset.next())
System.out.println(resultset.getString(1)); //获得当前行指定列的值
2.6、ResultSetMetaData接口从结果集中获得元数据
public interface ResultSetMetaData
{
int getColumnCount()throws SQLException; //返回列数
StringgetColumnName(int column) throws SQLException; //返回列名
StringgetColumnTypeName(int column) throws SQLException; //返回列数据类型名
intgetColumnDisplaySize(int column) throws SQLException; //返回列所占的最大字符宽度
}
三、数据库操作例子
3.1、获得数据库连接
在进行数据库连接的时候需要使用以下的几个信息:
·数据库的驱动程序:oracle.jdbc.driver.OracleDriver
·连接地址:jdbc:oracle:thin:@localhost:1521:orcl
·用户名:scott
·密码:tiger
要想连接需要使用Connection接口进行连接对象的保存,但是此接口必须依靠DriverManager类才可以完成对象的实例化操作。
import java.sql.Connection;
import java.sql.DriverManager;
public class ConnectionDemo {
public static final String DBDRIVER = "oracle.jdbc.driver.OracleDriver";
public static final String MysqlDBDRIVER = "com.mysql.jdbc.Driver";//mysql
public static final String DBURL = "jdbc:oracle:thin:@localhost:1521:orcl";
public static final String MysqlDBURL = "jdbc:mysql://localhost:3306/test";//mysql
public static final String DBUSER = "scott";
public static final String DBPASSWORD = "tiger";
public static void main(String[] args) throws Exception {
Connection conn = null; // 表示的是数据库连接
Class.forName(DBDRIVER); // 1、加载数据库驱动程序
conn = DriverManager.getConnection(DBURL, DBUSER, DBPASSWORD); // 连接数据库
System.out.println(conn); // 如果不为null,表示已连接
conn.close(); // 数据库的操作必须关闭
}
}
3.2、PreparedStatement接口实现增删改查
在开发中不会使用Statement进行操作,而都使用其子接口PreparedStatement完成。
PreparedStatement操作实际上属于预处理的操作。如果要创建PreparedStatement接口的对象需要依靠Connection接口中的prepareStatement()方法完成,而且必须传入一个预处理的SQL语句,所有的占位符使用“?”表示。
如果现在执行的是模糊查询,要使用LIKE语句。
建表:
CREATE TABLE USERINFO
( ID INTEGER NOT NULL,
NAME VARCHAR2(50),
AGE INTEGER,
BIRTHDAY DATE)
增删改查语句:
INSERT INTO 表名称(列名称1,列名称2,…) VALUES (值1,值2,…) ;
UPDATE 表名称 SET 字段=值,字段=值,.. [WHERE更新条件]
DELETE FROM 表名称 [WHERE删除条件]
数据库的更新操作本身非常的容易,直接使用executeUpdate()语句,但是如果要是查询的话就不一样,查询使用的方法是executeQuery()方法完成,
方法:public ResultSet executeQuery(String sql) throwsSQLException
查询的时候是将所有的内容都保存在了ResultSet接口的对象之中。取得ResultSet对象之后,就可以通过next()方法往下取每一行的数据,但是需要注意的是,如果要想取出某一列的内容,则使用getXxx()的形式,其中Xxx表示的是具体的数据类型,例如:getFloat()、getInt()、getDate()。既可以根据列名称,也可以根据列编号,从1开始
package com;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Date;
public class Insert {
public static final String DBDRIVER = "oracle.jdbc.driver.OracleDriver";
public static final String DBURL = "jdbc:oracle:thin:@localhost:1521:orcl";
public static final String DBUSER = "wangshengzhuang";
public static final String DBPASSWORD = "wangshengzhuang";
public static void main(String[] args) throws Exception {
Connection conn = null;
Class.forName(DBDRIVER);
conn = DriverManager.getConnection(DBURL, DBUSER, DBPASSWORD);
// 插入数据
String insertSql = "insert into userinfo(id,name,age,birthday) values(?,?,?,?)";
PreparedStatement pstmt = conn.prepareStatement(insertSql);
pstmt.setInt(1, 1);
pstmt.setString(2, "wangshengzhuang");
pstmt.setInt(3, 23);
pstmt.setDate(4, new java.sql.Date(new Date().getTime()));
Integer len = pstmt.executeUpdate();
System.out.println("插入" + len + "行数据");
// 修改数据
String updateSql = "update userinfo set age=24 where id=?";
pstmt = conn.prepareStatement(updateSql);
pstmt.setInt(1, 1);
len = pstmt.executeUpdate();
System.out.println("修改" + len + "行数据");
// 查询数据
String querySql = "select* from userinfo where id=?";
pstmt = conn.prepareStatement(querySql);
pstmt.setInt(1, 1);
ResultSet rs = pstmt.executeQuery();
while (rs.next()) {
Integer id = rs.getInt(1);
String name = rs.getString(2);
Integer age = rs.getInt(3);
Date date = rs.getDate(4);
System.out.println("id-->" + id + "name-->" + name + "age-->" + age
+ "birthday-->" + date);
}
// 删除数据
String deleteSql = "delete from userinfo where id=?";
pstmt = conn.prepareStatement(deleteSql);
pstmt.setInt(1, 1);
len = pstmt.executeUpdate();
System.out.println("删除" + len + "行数据");
rs.close();
pstmt.close();
conn.close(); // 数据库的操作必须关闭
}
}
3.3、批处理
在JDBC 2.0之后增加了许多的新功能,例如:可滚动的结集、使用ResultSet更新数据库、批处理等等,所谓的批处理就是指所有的操作可以一次性的提交到数据库之中。
如果要使用批处理则需要使用Statement接口中的addBatch()方法。
package com;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.util.Date;
publicclass Batch {
publicstaticfinal String DBDRIVER = "oracle.jdbc.driver.OracleDriver";
publicstaticfinal String DBURL = "jdbc:oracle:thin:@localhost:1521:orcl";
publicstaticfinal String DBUSER = "wangshengzhuang";
publicstaticfinal String DBPASSWORD = "wangshengzhuang";
publicstaticvoid main(String[] args) throws Exception {
Connection conn = null;
Class.forName(DBDRIVER);
conn = DriverManager.getConnection(DBURL, DBUSER, DBPASSWORD);
// 插入数据
String insertSql = "insert into userinfo(id,name,age,birthday) values(?,?,?,?)";
PreparedStatement pstmt = conn.prepareStatement(insertSql);
pstmt.setInt(1, 1);
pstmt.setString(2, "wangshengzhuang");
pstmt.setInt(3, 23);
pstmt.setDate(4, new java.sql.Date(new Date().getTime()));
pstmt.addBatch();
pstmt.setInt(1, 2);
pstmt.setString(2, "wangshengqi");
pstmt.setInt(3, 24);
pstmt.setDate(4, new java.sql.Date(new Date().getTime()));
pstmt.addBatch();
int score[] = pstmt.executeBatch();
for (int i = 0; i < score.length; i++) {
System.out.println(score[i]);
}
pstmt.close();
conn.close(); // 数据库的操作必须关闭
}
}
此时,一次性的会将所有的SQL语句发送到数据库之中执行,一次性更新5条记录。那么如果现在假设这5条记录都是有关联的5条。在使用批处理的操作中发现,如果中间有一条语句出错了,则默认情况下是将出错之前的代码进行提交,这是由于JDBC采用了自动的事务提交的方式才造成的结果。
3.4、事务处理
如果此时要进行事务处理的话,则需要按照如下的方式进行:
1、 取消自动提交:public void setAutoCommit(boolean autoCommit) throws SQLException
2、 执行更新操作:
3、 如果没有错误,则提交事务:public void commit() throwsSQLException
4、 如果有错误,则进行回滚:public void rollback() throwsSQLException
package com;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.util.Date;
publicclass Transaction {
publicstaticfinal String DBDRIVER = "oracle.jdbc.driver.OracleDriver";
publicstaticfinal String DBURL = "jdbc:oracle:thin:@localhost:1521:orcl";
publicstaticfinal String DBUSER = "wangshengzhuang";
publicstaticfinal String DBPASSWORD = "wangshengzhuang";
publicstaticvoid main(String[] args) throws Exception {
Connection conn = null;
Class.forName(DBDRIVER);
conn = DriverManager.getConnection(DBURL, DBUSER, DBPASSWORD);
conn.setAutoCommit(false);
// 插入数据
String insertSql = "insertinto userinfo(id,name,age,birthday) values(?,?,?,?)";
PreparedStatement pstmt = conn.prepareStatement(insertSql);
pstmt.setInt(1, 1);
pstmt.setString(2, "wangshengzhuang");
pstmt.setInt(3, 23);
pstmt.setDate(4, new java.sql.Date(new Date().getTime()));
pstmt.executeUpdate();
pstmt.setInt(1, 1);
pstmt.setString(2, "wangshengqi");
pstmt.setInt(3, 24);
pstmt.setDate(4, new java.sql.Date(new Date().getTime()));
try{
pstmt.executeUpdate();
conn.commit();
}catch (Exception e) {
System.out.println("回滚");
conn.rollback();
}
pstmt.close();
conn.close(); // 数据库的操作必须关闭
}
}
四、ResultSet进一步讨论
ResultSet常用方法 JDBC 2.0 API 为结果集增加了两个新的基本能力:可滚动性和可更新性。
Statement createStatement(int resultSetType,int resultSetConcurrency) throws SQLException
创建一个Statement
对象,该对象将生成具有给定类型和并发性的ResultSet
对象。此方法与上createStatement
方法相同,但它允许重写默认结果集类型和并发性。
参数:resultSetType
-结果集类型,表明结果集是否可以滚动,它是ResultSet.TYPE_FORWARD_ONLY
、ResultSet.TYPE_SCROLL_INSENSITIVE
或ResultSet.TYPE_SCROLL_SENSITIVE
之一。
ResultSet.TYPE_FORWARD_ONLY:(缺省类型),ResultSet指针只允许向前移动,并且不会受到其他用户对该数据库所作更改的影响。
TYPE_SCROLL_INSENSITIVE:ResultSet指针可以前后移动,甚至可以进行特定定位,例如移至列表中的第四个记录或者从当前位置向后移动两个记录。不会受到其他用户对该数据库所作更改的影响。
TYPE_SCROLL_SENSITIVE:ResultSet指针可以前后移动,也可以定位,但这种类型受到其他用户所作更改的影响。
resultSetConcurrency
-并发类型;该参数确定是否可以更新 ResultSet,它是ResultSet.CONCUR_READ_ONLY
或ResultSet.CONCUR_UPDATABLE
之一。
CONCUR_READ_ONLY:这是缺省值,当前ResultSet对象只能读,不能更新。
CONCUR_UPDATABLE:当前ResultSet可以更新
返回:一个新的Statement
对象,该对象将生成具有给定类型和并发性的ResultSet
对象
抛出:SQLException
- 如果发生数据库访问错误,或者给定参数不是指示类型和并发性的ResultSet
常量
在滚动结果集中可用的方法有:
rs.previous();//向前滚动
rs.next();//向后滚动
rs.getRow();//得到当前行号
rs.absolute(n);//光标定位到n行
rs.relative(int n);//相对移动n行
rs.first();//将光标定位到结果集中第一行。
rs.last();//将光标定位到结果集中最后一行。
rs.beforeFirst()//将光标定位到结果集中第一行之前。
rs.afterLast();//将光标定位到结果集中最后一行之后。
rs.moveToInsertRow();//光标移到插入行
rs.moveToCurrentRow();//光标移回到调用
rs.moveToInsertRow()方法前光标所在行
//测试光标位置
rs.isFirst()
rs.isLast()
rs.isBeforeFirst()
rs.isAfterLast()
在可更新结果集中可用的方法有:(单表)
rs.insertRow();//把插入行加入数据库和结果集
rs.deleteRow();//从数据库和结果集中删除当前行
rs.updateXXX(int column,XXX data);XXX代表int/double/String/Date中类型之一
rs.updateXXX(String columnName,String Data); //以上两个方法更新结果集当前行
rs.updateRow();//更新内容发送到更新数据库