JDBC API的基本用法

    一、在java程序中,通过JDBC API访问数据库包括以下步骤:

1) 获得要访问的数据库的驱动程序的类库,把它放在classpath中。

2) 在程序中加载并注册JDBC驱动器,之中JDBC-ODBC驱动器是在JDK中自带的,默认已经注册。
  一下给出加载JDBC-ODBC驱动器,加载并注册SQLServer驱动器、Orcale驱动器和MySQL驱动器代码:

//加载JdbcOdbcDriver类
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");

//加载SQLServerDriver类
Class.forName("com.microsoft.jdbc.sqlserver.SQLServerDriver");
//注册SQLServer类
java.sql.DriverManager.registerDriver(new com.microsoft.jdbc.sqlserver.SQLServerDriver());

//加载OracleDriver类
Class.forName("oracle.jdbc.driver.OracleDriver");
//注册OracleDriver类
java.sql.DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver());

//加载MySQL Driver类
Class.forName("com.mysql.jdbc.Driver");
//注册MySQL Driver类
java.sql.DriverManager.registerDriver(new com.mysql.jdbc.Driver());//不是必要步骤

  有些驱动器的Driver类在被加载的时候能自动创建本身的实例,然后调用DriverManager.registerDriver()方法注册自身

 attention:通常情况下将负责加载数据库驱动的代码放在static块中,因为static块的特点就是只在其所在类第一次被加载时执行,即第一次访问数据库时执行,这样就可以避免反复加载数据库驱动,减少对资源的浪费,同时提高了访问数据库的速度。

public class JDBC{
  static{
      try{
  Class.forName();
     }catc(ClassNotFoundException e){
  e.printStackTrace();     }//输出捕获的异常信息
        }
public static void main(String arga[]){
 }
}

3)建立与数据库的连接
 Connection con=java.sql.DriverManager.getConnection(dburl,user,password);
   参数说明:dburl:表示连接数据库的JDBC URL
      user:表示用户名
      password:表示用户密码
   JDBC URL 的一般格式是:
      jdbc:drivertype:driversubtype://parameters
         参数说明:drivertype:表示驱动器类型
     driversubtype:表示驱动器子类型(可选参数)
     parameters:表示设定数据库服务器的IP地址、端口号和数据库名称。
  一下给出了几种常见的数据库JDBC URL形式
如果通过JDBC-ODBC Driver连接数据库
 jdbc:odbc:databasesource
对于Oracle数据库
 jdbc:oracle:thin:@localhost::sid
对于SQLServer数据库
 jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=?
对于MySQL数据库
 jdbc:mysql://localhost:3306/?
 说明:?为数据库名

   try{
 Connetion con=DriverManager.getConnecion();
 }catch(SQLException e){
  e.printStackTrace();  }

4)创建Statement对象,准备执行SQL语句:
   Statement stmt=con.createStatement();
   & PreparedStatement pst=con.prepareStatement();
  注: 运用preparedStatement不是线程安全的,当对一个PreparedStatement对象
    打开多个ResultSet对象是会导致SQLException。
       而Statement对象是线程安全的,可以被多个线程并发访问;虽然每次访问数据库时,
    都会创建新的数据库连接,运行性能比较差。

5)执行SQL语句
   String sql="select * from ?where…";
   ResultSet rs=stmt.executeQuery(sql);

6)遍历ResultSet对象中的记录

7)一次关闭ResultSet、Statement、Connection对象:
  rs.close();
  stmt.close();
  con.close();
   注意:ResultSet、Statement、Connection对象一旦调用close()方法就会立刻释放其所占用的系统资源,不允许在访问其方法等。

              二、处理SQLException

Ⅰ、getErrorCode():返回数据库系统提供的错误编号。
Ⅱ、getSQLState():返回数据库系统提供的错误状态。
    SQLException的子类SQLWarning,它表示访问数据库时产生的警告信息。警告信息不会影响程序的执行流程,程序也无法在catch语句中捕获SQLWarning。程序可以通过ResultSet、Statement、Connection对象的getWarnings()方法获得SQLWarning对象。SQLWarning采用串联模式,它的getnextWarning()方法返回后续的SQLWarning对象。

     三、输出JDBC日志
以下代码使JDBC实现把日志输出到控制台:
  在程序开头用:
   DriverManager.setLogWriter(new PrintWriter(System.out,true));

     四、获得新插入记录的主键值
表的主键定义成auto_increment类型
 create table 表名 (ID bigint primary key auto_increment not null)
为了获得主键值,必须在Statement的executeUpdate()方法中设置Statement.RETURN_GENERATED_KEY参数,接着通过Statement的getGeneratedKeys()方法就能得到包含主键值的ResultSet对象。

     五、设置批量抓去属性

    ResultSet对象并不会存放很多条数据,而是在遍历结果集时,ResultSet对象才会到数据库中抓取相应的数据。抓去过程对程序完全透明。
    ResultSet、Statement、Connection接口中都提供了以下方法。
(1)setFetchSize(int size):设置抓去的数目。
(2)setFetchDirection(int direction):设置抓取的方向。
     参数有三个:1>ResultSet.FETCH_FORWARD(单向)
  2>ResultSet.FETCH_REVERSE(双向)
  3>ResultSet.FETCH_UNKNOWN(未知)
其中:Connection接口中的setFetchXxx()方法决定了由它创建的所有Statement对象的默认抓取属性。
      Statement接口中的setFetchXxx()方法决定了由它创建的所有ResultSet对象的默认抓取属性。
      ResultSet接口中的setFetchXxx()方法仅仅决定当前ResultSet对象的抓取属性。
另注意:setFetchXxx()方法仅仅向JDBC驱动器提供了批量抓取的建议,JDBC驱动器有可能会忽略这个建议。

            六、检测驱动器使用JDBC版本

通过DatabaseMetaData类的getJDBCMajorVersion()和getJDBCMinorVersion()方法来检测驱动器所用的JDBC版本。
    
     七、元数据

  在SQL中,用来描述数据库及其组成部分的数据成为元数据。元数据可以提供数据库结构和表的详细信息。
在JDBC API中,Connection接口的getMetaData()方法返回一个DatabaseMetaData对象,表示连接数据库的元数据。
              ResultSet接口的getMetaData方法返回一个ResultSetMetaData对象,表示相应结果集的元数据。
         ParameterMetaData接口的getParameterMetaData()方法返回一个ParameterMetaData对象。
【1】ResultSetMetaData

ResultSetMetaData具有一下的方法:
①int getColumnCount():返回结果集包含的列数;
②int getColumnLabel(int i):返回结果集中第i列的字段名,结果集中第1列字段的索引为1.
③int getColumnType(int i):返回结果集中第i列的字段的SQL类型。Types.VARCHAR表示SQL类型中的VARCHAR类型
④String getColumnTypeName(int i):返回结果集中第i列的字段的SQL类型。
ResultSet result;
ResultSetMetaData metaData=result.getMetaData();

【2】DatabaseMetaData
1>getTable()方法。它返回数据库中符合参数给定条件的所有表。给方法的完整的定义如下:
   public ResultSet getTables(String catalog,String schemapattern,String tableNamePattern,String[]types)throws SQLException
   各参数说明:
             catalog:指定表所在的目录。如果不支持目录就设为null
      schemaPattern:指定表所在的Schema,如不限制则设为null
      tableNamePattern:指定表名必须匹配的字符串模式
      types:指定表的类型。表的类型包括:"TABLE","VIEW","SYSTEM TABLE",GLOBAL TEMPORARY","LOCAL TEMPORARY","ALLIAS" "SYNONYM".

  getTable()方法返回一个ResultSet对象,它包括5个字段:即5列
·TABLE_CAT:   第1个字段,表示表的 目录,可以为null。
·TABLE_SCHEM: 第2个字段,表示的 Schema,可以为null。
·TABLE_NAME:  第3个字段,表示表的 名字。
·TABLE_TYPE:  第4个字段,表示表的 类型。
·REMARKS:     第5个字段,表示表的 注释。

2>getJDBCMajorVersion() 和getJDBCMinorVersion()方法。它返回int型的数值,分别表示驱动器使用的JDBC的主版本号和次版本号。

3>getMaxConnections()方法,它返回int型数值,表示数据库允许同时建立的连接的最大数目。

4>getMaxStatements()方法,它返回int型的数值,表示一个Connection对象允许同时打开的Statement对象的最大数目。如果此对象没有限制或者是未知则返回0.

5>supportsXxx()方法。它判断驱动器或底层数据库系统是否支持某种特性。
  例如:supportsOuterJoins()方法判断数据库是否支持外连接;supportsGroupBy()方法判断数据库是否支持group by语句。

    八、可滚动及可更新的结果集

 默认情况下,结果集的油表只能从上往下移动,只要调用ResultSet对象的next()方法,就能使游标下移一行。当到达结果集的末尾时,next()方法就会返回false,否则返回true。此外,默认情况下,只能对结果集执行读操作,不允许更新结果集的内容。
  结果集的开头是指第一条记录的前面的位置,这是游标的初始位置。结果集的末尾是指最后一条记录的后面位置。

 为了获得可滚动或可更新的ResultSet对象,需要通过Connection接口的一下方法构造Statement或PreparedStatement对象:
     createStatement(int type,int concurrency)              //创建Statement对象
     PrepareStatement(String aql,int type,int concurrency)  //创建PreparedStatement对象
type参数可以是:
·ResultSet.TYPE_FORWARD_ONLY:游标只能从上往下移动,即结果集不能滚动。这是默认值。
·ResultSet.TYPE_SCROLL_INSENSITIVE:游标可以上下移动,即结果集可以滚动。当程序对结果集的内容作了修改,游标对此不敏感。
·ResultSet.TYPE_SCROLL_SENSITIVE:游标可以上下移动,即结果集可以滚动。当程序对结果集的内容作了修改,游标对此敏感。
concurrency参数可以是:
·CONCUR_READ_ONLY:结果集不能被更新。
·CONCUR_UPDATABLE:结果集可以被更新。
  值得注意的是:即使在创建Statement或PreparedStatement时,把type和concurrency参数分别设为可滚动和可更新,实际上得到的结果集有可能仍然不允许滚动和更新,这有两个方面的原因:
   ··底层JDBC驱动器有可能不支持可滚动和可更新的结果集。程序可以通过DatabaseMetaData类的supportsResultSetType()和supportsResultSetConcurrency()方法,来了解驱动器所支持的type和concurrency类型。
   ··某些查询语句的结果集不允许被更新。例如:JDBC规范规定,只有对一张表查询,并且查询字段包含表中所有的主键,这样的查询语句的结果集才可以被更新。

ResultSet接口提供了一系列用于移动游标分方法。
1>first():使游标移动到第一条记录。
2>last():使游标移动到最后一条记录。
3>beforeFirst():使游标移动到结果集的开头。
4>afterLast():使游标移动到结果集的末尾。
5>previous():使游标从当前位置向上(或者说向前)移动一行。
6>next():使游标从当前位置向下或者说是向后移动一行。
7>relative(int n):使游标从当前位置移动n行。n>0,就向下移动,否则向上移动。当n=1,等价于调用next()方法;当n=-1就等价于previous()方法。
8>absolute(int n):使游标移动到第n行。参数n指游标的绝对位置。

   使用以上方法需要注意两点:
第一:除了beforeFirst()和afterLast()方法返回void类型之外,其余方法都返回boolean类型,如果游标移动到目标位置到达结果集      的开头或者是结尾,就返回false,否则返回true。
第二:只有当结果集可以滚动时,才可以调用以上所有方法。如果结果集不可以滚动,则只能调用next()方法,当程序调用其他方法时,这些方法会抛出SQLException。

ResultSet接口的一下方法判断游标是否在特定位置。

1>isFirst():判断游标是否在第一行。
2>isLast():判断游标是否在最后一行。
3>isBeforeFirst():判断游标是否在结果集的开头。
4>isAfterLast():判断游标是否在结果集的末尾。
5>getRow():返回游标当前所在的位置的行号。

下面介绍如何在结果集中插入、更新、删除记录、
(1)插入记录
   ResultSet接口的moveToInsertRow()方法把游标移动到特定的插入行。
   值得注意的是,程序无法控制在结果集中添加记录的位置,因此新纪录到底插入到哪一行对程序是透明的。ResultSet接口的insertRow()方法会向数据库中插入记录。ResultSet接口中的moveToCurrentRow()方法把游标移动到插入前的位置,即调用moveToInsertRow()方法前所在的位置。
(2)更新记录
   ResultSet接口中的updateRow()方法会更新数据库中的相应的记录。
(3)删除记录
   ResultSet接口中的deleteRow()方法会删除数据库中的相应的记录。

    九、处理Blob和Clob类型的数据

在数据库中有两种特殊的处理SQL数据类型。

<<<<1>>>>Blob(Binary large object):存放大容量的二进制数据。
<<<<2>>>>Clob(Character object):存放大容量的由字符组成的文本数据。

 【1】数据库通过调用ResultSet对象的getBlob()方法返回一个Blob对象,Blob对象实际上仅仅持有数据库中相应FILE字段的引用。
 ①Blob blob=(new ResultSet()).getBlob();
  为获取数据库中的Blob数据,可以调用Blob对象的getBinaryStream()方法获得一个输入流,然后从这个输入流中读取Blob数据。
 ②InputStream in=blob.getBinaryStream();
  PreparedStatement的setBinaryStream()方法向数据库中写入Blob数据,该方法定义为:
        ③public void setBinaryStream(int parameterIndex,InputStream in,int length)throws SQLException
   上述InputStream类型的对象指定了Blob数据源,参数length指定了Blob数据的字节数。
MySQL中Blob数据分为4中类型:TINYBLOB(容量为256B)、BLOB(容量为64KB)、MEDIUMBLOB(容量为4GB)。

  PreparedStatement stmt=con.prepareStatement("insert into ABLOB(ID,FILE)values(?,?)");
  stmt.setLong(1,1);
  FileInputStream fin=new FileInputStream("test.gif");
  smt.setBinaryStream(2,fin,fin.available());
  stmt.executeUpdate();
  fin.close();
  stmt.close();

注:MySQL数据库限制了接收和发送的数据包的大小。过大会抛出com.mysql.jdbc.PacketToolbigException。
    可以修改MySQL服务器的max_allowed_packet系统属性,把它设为更大值。

【2】Clob数据处理方式与Blob相似

  ①ResultSet接口的getClob()方法:从结果集中获得Clob对象。
  ②Clob接口的getCharacterStream()方法,返回一个Reader对象,用于读取Clob数据中的字符。
  ③PreparedStatement接口的setCharacterStream()方法:想数据库中写入Clob数据。
    完整定义:public void setCharacter(int parameterIndex,Reader reader,int length)throws Exception

    十、控制事务

~1、事务是指一组相互依赖的操作行为
数据库事务必须具备ACID特征,ACID是Atomic(原子性)、Consistency(一致性)、Isolation(隔离性)、Durability(持久性)。
·原子性:指整个数据库事务是不可分割的工作单元。
·一致性:指数据库事务不能破坏关系数据库的完整性及业务逻辑上的一致性。
·隔离性:指的是在并发环境中,当不同的事务同时操纵相同的数据时,每个事务都有各自的完整数据空间。
·持久性:指的是只要事务成功结束,它对数据库所做的更新操作就必须永久保存下来。
数据库采用日志来保证事务的原子性、一致性、持久性。
数据库通过锁机制来实现隔离性。
~2、声明事务的边界的概念。
    数据库系统向客户程序只要向数据库声明了一个事务,数据库系统就会自动保证事务的ACID特性。声明事务包含以下内容
·事务开始的边界
·事务的正常结束边界(COMMIT):提交事务,永久保存被事务更新后的数据库状态。
·事务的异常结束边界(ROLLBACK):撤销事务,或者说回滚事务,使数据库退回到执行事务前的初始状态。
~3、数据库系统支持两种事务模式。
·自动提交模式:每个SQL语句都是一个独立的事务,当数据库系统执行完一个SQl事务语句后,会自动提交事务。
·手工提交模式:必须由数据库的客户程序显式指定事务开始边界和结束边界。
~4、数据库表的分类
·INNODB:支持数据库事务
·BDB支持数据库事务
·MyISAM不支持数据库事务(默认表类型)
      create table 表名{}type=INNODB;
 对于已存在的表,可以采用一下形式的DDL语句修改它的表类型:
  alter table 表名 type=INNODB;
~5、通过JDBC API声明事务边界
Connection接口提供了以下用于控制事务的方法:
·setAutoCommit(boolean sutocommit):设置是否自动提交事务
·commit():提交事务
·rollback():撤销事务

    十一、保存点

Connection接口的setSavepoint()方法用于在事务中设置保存点。它有两种重载形式:
 public SavePoint setSavepoint()throws SQLException
 public SavePoint setSavepoint(String name)throws SQLException
第一个不带参数的setSavepoint()方法设置匿名的保存点,第二个setSavepoint(String name)方法name参数表示保存点的名字。
这两个setSavepoint()方法都会返回一个表示保存点的Savepoint对象
  
Connection接口的releaseSavepoint(Savepoint point)方法取消已经设置的保存点。
Connection接口的rollback(Savepoint point)方法使事务回滚到参数指定的保存点。

可以通过DatabaseMetaData接口的supportsSavepoint()方法可以判断驱动器是否支持保存点,false表示不支持保存点。

    十二、批量更新

Statement接口中提供了支持批量更新的两个方法。
·addBatch(String sql):加入一条SQL语句。
·executeBatch():执行批量更新。
   Statement接口的executeUpdate(String sql)方法返回一个整数值,表示数据库中受SQL语句影响的记录数。而executeBatch()方法则返回一个int数组,数组中每个元素分别表示受每条SQL语句影响的记录数。

批量更新需要注意:
1>必须把批量更新中的所有操作放在单个事务中。
2>批量更新中可以包括SQL update /delete/insert语句等,但是不能包括select查询语句否则Statement的executeBatch()方法会抛出BatchUpdateException异常。
3>可以通过DatabaseMetaData接口中的supportsBatchUpdate()方法可以判断驱动器是否支持批量更新。

 BatchUpdateException还有一个getUpdateCounts()方法,返回一个int类型的数组,数组中元素分别表示受已经执行成功的每条SQL语句影响的记录数。

    十三、设置事务的隔离级别

数据库提供了4中事务隔离级别。
-1、Serializable:串行化
-2、Repeatable Read:可重复读
   可以看到其他事务已经提交的新插入的记录,但是不能看到其他事务对已有记录的更新
-3、Read Committed:读已提交数据
   可以看到其他事务已经提交的新插入的记录,而且能看到其他事务已经提交的对已有记录的更新
-4、Read UnCommitted:读未提交数据
   可以看到其他事务没有提交的新插入的记录,而且能看到其他事务没有提交的对已有记录的更新

 注:隔离级别越高,越能保证数据库中数据的完整性和一致性,但是对并发性能的影响也越大。

Connection接口的setTransactionIsolation(int level)用来设置数据库使用的隔离级别,这种设置只对当前的连接有效。
level可选值:Connection.TRANSACTION_READ_UNCOMMITTED
      Connection.TRANSACTION_READ_COMMITTED
      Connection.TRANSACTION_READ_REPEATABLED_READ
      Connection.TRANSACTION_READ_SERIALIZABLE

    十四、数据库连接池

   数据库连接池的基本原理是,事先建立一定数量的数据库连接,这些数据库连接存放在连接池中,当Java应用程序执行一个数据库事务时:只需从连接池中取出空闲的数据库连接;当Java应用程序执行完成事务后,再将数据库连接放回连接池。
  使用数据库连接池需要注意:
·限制连接池中最多可以容纳的连接数目,皮面过度消耗系统资源。
·当客户请求连接,而连接池中所有的连接都已经被占用时,该如何处理?一种方法是让客户一直等待,直到有空闲连接,还有一种方式是为客户分配一个新的临时的连接。
·当客户不再使用连接时,需要把连接重新放入连接池。
·限制连接池中允许处于空闲状态的连接的最多数目。

    十五、DataSource数据源

 DataSource接口的最主要的功能就是获得数据库连接,它的getConnection()方法提供这一服务。
 DataSource接口并不强求其实现必须带有连接池,不过,多数DataSource实现都是用了连接池。
假定某种应用程序服务器发布了一个JNDI名字为“jdbc/SAMPLEDB”的数据源,Java应用程序通过JNDI API中的javax.naming.Context接口来获得这个数据源的引用。
   Context ctx=new InitialContext();
  DataSource ds=(DataSource)ctx.lookup("java:comp/env/jdbc/SAMPLEDB");
 得到的DataSource对象的引用后,就可以通过DataSource对象的getConnection()方法获得数据库连接对象Connection:
  Connection con=ds.getConnection();

你可能感兴趣的:(JDBC API的基本用法)