一、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,让它包含存取代码并提供一个对客户端具有数据库独立性的服务。

        java基础---->jdbc数据库操作_java   

                   ·类: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_ONLYResultSet.TYPE_SCROLL_INSENSITIVEResultSet.TYPE_SCROLL_SENSITIVE之一。

ResultSet.TYPE_FORWARD_ONLY:(缺省类型),ResultSet指针只允许向前移动,并且不会受到其他用户对该数据库所作更改的影响。

TYPE_SCROLL_INSENSITIVE:ResultSet指针可以前后移动,甚至可以进行特定定位,例如移至列表中的第四个记录或者从当前位置向后移动两个记录。不会受到其他用户对该数据库所作更改的影响。
TYPE_SCROLL_SENSITIVE:ResultSet指针可以前后移动,也可以定位,但这种类型受到其他用户所作更改的影响。

resultSetConcurrency -并发类型;该参数确定是否可以更新 ResultSet它是ResultSet.CONCUR_READ_ONLYResultSet.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();//更新内容发送到更新数据库