Java JDBC技术

来源:互联网 发布:黑鹰刷枪软件 编辑:程序博客网 时间:2024/06/16 18:13

Java JDBC技术

Java JDBC技术

1、背景知识

1JDBCJava DataBase ConnectivityJava 数据库连接技术),它是将JavaSQL结合且独立于特定的数据库系统的应用程序编程接口。

2)目的

n        推广Java的应用

n        改进ODBC的平台问题

n        设计出一种通用的数据库访问接口。

3)主要功能

n        创建与数据库的连接;

n        发送SQL语句到任何关系型数据库中;

n        处理数据并查询结果。

4)利用JDBC的编程步骤

n        加载连接数据库的驱动程序(把指定的Class装载到JVM中来)

n        创建与数据源的连接

n        操作数据库:创建Statement对象并执行SQL语句以返回一个ResultSet对象。

n        获得当前记录集中的某一记录的各个字段的值

n        关闭查询语句及与数据库的连接(注意关闭的顺序先rsstmt最后为con,一般可以在finally语句中实现关闭)

下面给出实现过程的代码示例

try {

Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");  //1)创建与数据库的连接

    Connection con=DriverManager.getConnection("jdbc:odbc:DatabaseDSN","Login","Password");

Statement stmt=con.createStatement();

ResultSet rs=stmt.executeQuery("select * from DBTableName");//2)发送SQL语句到数据库中  while(rs.next()) {

String name=rs.getString("Name") ;            //3)处理数据并查询结果。

    int age=rs.getInt("age");

    float wage=rs.getFloat("wage");

 }

 rs.close();                                                                    //4)关闭

 stmt.close();

 con.close();

 }catch(SQLException e){  

System.out.println("SQLState:"+ e.getSQLState());

    System.out.println("Message:" + e.getMessage());

    System.out.println("Vendor:"  + e.getErrorCode());

}

5JDBC的两个主要的包

n        java.sql JDBC内核APIJDBC1.0

n        javax.sql JDBC标准扩展(JDBC2.0

2、利用JDBC API操作数据库
      
主要涉及三个语句类和其它类:StatementPreparedStatementCallableStatementConnectionResultSet等类

3、创建与数据源的连接

1)数据源的URLjdbc:<subprotocal>:[database locator]

其中:jdbc---指出要使用JDBCsubprotocal---定义驱动程序类型;database locator---提供网络数据库的位置和端口号(包括主机名、端口和数据库系统名等)

示例如:      

       String url="jdbc:microsoft:sqlserver://127.0.0.1:1433;DatabaseName=pubs";  

2)应用要点

n  JDBC URL 提供了一种标识数据库的方法,可以使相应的驱动程序能识别该数据库并与之建立连接。

n  JDBC的驱动程序编程员将决定用什么内容的JDBC URL来标识特定的驱动程序。

n  不同厂商的数据库系统,主要差别在JDBC的驱动程序及数据库的url格式。

n  对同一个数据库可以产生多个不同的连接

3)创建与数据源的连接(下面是采用直接连接的方法)

4)不同数据库的驱动程序类和URL示例

MS SQlServer2000

         String url="jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=DataBase";

         String DBDriver="com.microsoft.jdbc.sqlserver.SQLServerDriver";   

JDBC ODBC 桥方式

String url="jdbc:odbc:WebMisDB";

         String DBDriver="sun.jdbc.odbc.JdbcOdbcDriver";     

Oracle 数据库

String url="jdbc:oracle:thin:@localhost:1521:DBName"; //DBName为你的数据库名

       String DBDriver = "oracle.jdbc.driver.OracleDriver";

IBM DB2数据库

String url="jdbc:db2://localhost:5000/sample";        //sample为你的数据库名

        String DBDriver = "COM.ibm.db2.jdbc.net.DB2Driver";

MySQL数据库

String url="jdbc:mysql://localhost/testDB";    //testDB为你的数据库名

        String DBDriver = "com.mysql.jdbc.Driver";

Sybase数据库

           String url="jdbc:sybase:Tds:localhost:5007/testDB";    //testDB为你的数据库名

           String DBDriver = "com.sybase.jdbc.SybDriver";

4、对数据库的一般查询---利用Statement对象

1 Statement对象的作用:要想执行一条SQL语句,必须首先创建出Statement对象(它封装代表要执行的SQL语句命令)

2)编程实现的步骤

n        创建Statement对象

n        执行一个SQL语句(如查询语句),以查询数据库中的数据。这可以通过Statement类中的executeQuery ()方法来实现(其输入参数是一个SQL查询语句,其返回值是一个ResultSet类的对象);

n        关闭Statement对象:每一个Statement对象在使用完毕后,都应该关闭。

3)程序示例

Statement stmt=con.createStatement();

ResultSet rs=stmt.executeQuery("select * from DBTableName");

Stmt.close();

4)应用要点:每个Statement对象只保留一个结果集

import java.sql.*;

public class ResultSetTest{

   public static void main(String args[]){

             try{

                     Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");

                     Connection con=DriverManager.getConnection("jdbc:odbc:studlist");

                     Statement stmt=con.createStatement();

                     ResultSet rs1=stmt.executeQuery("select name from  student");

                     ResultSet rs2=stmt.executeQuery("select age from student");

                     while(rs2.next()){  //此时rs1已经被关闭

System.out.println(rs2.getObject(1));

                                   }

                                   rs2.close();

                                   stmt.close();

                                   con.close();

                            }catch(Exception e){

                                   System.out.println(e);

                            }    

       }

}

5、预编译方式执行SQL语句

1PreparedStatement的基本特性

n        Statement对象的特点:由于Statement对象在每次执行SQL语句时都将该语句传给数据库,如果需要多次执行同一条SQL语句时,这样将导致执行效率特别低,此时可以采用PreparedStatement对象来封装SQL语句。

n        PreparedStatement具有预编译的特性:如果数据库支持预编译,它可以将SQL语句传给数据库作预编译,以后每次执行该SQL语句时,可以提高访问速度;

n        但如果数据库不支持预编译,将在语句执行时才传给数据库,其效果类同于Statement对象。

2)作用:

n        SQL语句做预编译

n        另外PreparedStatement对象的SQL语句还可以接收参数。

3PreparedStatement的编程步骤

n        从一个Connection对象上可以创建一个PreparedStatement对象,并给出预编译的SQL语句。

n        调用executeQuery()来执行SQL语句,但与Statement方式不同的是,它没有参数,因为在创建PreparedStatement对象时已经给出了要执行的SQL语句,系统并进行了预编译。

n        关闭PreparedStatement对象

insertSql="insert into usertable values(?,?,?,?,?,?)";

    con=userInfoBeanID.getConnection();      

       ps=con.prepareStatement(insertSql,ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE);

    ps.setString(1,userName);

       ps.setString(2,userPassword);

       ps.setString(3,userDepartment);

       ps.setInt(4,wUserLevel);

       ps.setInt(5,wDepartLevel);

    ps.setBinaryStream(6,imageFIS,imageFIS.available());

       ps.executeUpdate();

       userInfoBeanID.close();

6、执行存储过程

1)编程执行存储过程的编程步骤

n        创建CallableStatement对象

(使用Connection类中的prepareCall()方法可以创建一个CallableStatement对象,其参数是一个String对象,一般格式为“{call 存储过程名()}”)。

n        执行存储过程(可以调用executeQuery()方法来实现)。

n        关闭CallableStatement

2)程序示例如下

storeProcStatement=con.prepareCall("{call au_info(?,?)}",       ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY);

storeProcStatement.setString(1,"Ringer");   //给存储过程的第一个输入参数赋值

storeProcStatement.setString(2,"Anne");     //给存储过程的第二个输入参数赋值

       rs=storeProcStatement.executeQuery();    //执行该存储过程

7ResultSet对象 ----检索结果集

1)为什么要提供ResultSet对象:提高数据检索的速度

2)什么是ResultSet对象:执行完查询SQL语句后,将返回一个查询结果集,并将该结果集保存在内存中。

3ResultSet对象中的记录指针:ResultSet对象维持一个指向当前行的指针,利用ResultSet类的next()方法可以移动到下一行,如果next()的返回值为false,则说明已到记录集的尾部。

4)获得某一列(字段)的结果值的方法

n        利用ResultSet类的getXXX()方法可以获得某一列的结果,其中XXX代表JDBC中的Java数据类型,如 getInt()getString()getDate()等。

n        访问时需要指定要检索的列(可以采用 int值作为列号(从1开始计数)或指定列(字段)名方式,但字段名不区别字母的大小写))。

5)代码示例

while(rs.next()) { 

String name=rs.getString("Name"); //采用"列名"的方式访问数据

    int age=rs.getInt("age");

    float wage=rs.getFloat("wage");

    String homeAddress=rs.getString(4); //采用"列号"的方式访问数据

 }

8、获得结果集中的一些结构信息

1)结构信息:提供用来描述列的数量、列的名称、列的数据类型等。

2)方法:利用ResultSet类的getMetaData()方法

3)程序示例如下

       metaData = rs.getMetaData();

       for(int column = 0; column < metaData.getColumnCount(); column++){

         System.out.print(metaData.getColumnName(column+1)+"/t");

    }                  

     System.out.println("");

     while(rs.next()){  // Field Name 不区分大小写

              for (int i = 1; i <= metaData.getColumnCount(); i++)       {

                     System.out.print(rs.getObject(i)+"/t");

        }                          

              System.out.println("");

        }

4)用途:实现动态地访问各种未知结构的数据库表

9ResultSetCursor(游标)

1)缺省设置

游标只能前进不能后退并且数据不能更改;在ResultSet对象或其父类Statement对象关闭之前,光标一直保持有效。

2)在创建StatementPreparedStatement对象时可以指定ResultSet的游标及允许数据更新两个特性参数

 Statement st=connection.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);

3)当游标允许前进或后退,可以调用下面的方法

 

 

 

 

 

 

 

4)当数据允许被修改时,可以通过ResultSet类中的如下方法来直接更新记录。

updateXXX()

updateRow()

deleteRow()

insertRow()

10、修改数据库表中的数据---利用ResultSet

1)方法:不仅可以通过发送SQL语句的方式,也可以直接通过ResultSet来实现修改记录

2)更新指定记录中的字段

3)插入一条记录的代码示例

11、修改数据库表中的数据---采用SQL语句

1)主要涉及修改、插入和删除等操作(即SQL语句中的InsertUpdateDeleteCreatDrap等)

2)主要方式有

修改、插入和删除表中的记录

创建和删除表

增加和删除表中的某一列

3)实现手段:利用Statement类或 PreparedStatement 类中的executeUpdate()方法

4)程序示例

import java.sql.*;

public class DBUpdateSetTest{

     public static void main(String args[])        {

             try{

                     Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");

                     Connection con=DriverManager.getConnection("jdbc:odbc:studlist");

                     Statement stmt=con.createStatement();

                     ResultSet rs=stmt.executeQuery("select * from student");

                     System.out.println("Result before executeUpdate");

                     while(rs.next()){

                                          System.out.println(rs.getString("name"));

                        System.out.println(rs.getString("age"));

                                   }

                     stmt.executeUpdate("Update student set name='Yang' where id=0");

                     stmt.executeUpdate("Delete from student where id=2");

       stmt.executeUpdate("Insert into student(id,name,age,sex) values(2,'zhang',30,true)");

                     rs=stmt.executeQuery("select * from student");

                     System.out.println("Result After executeUpdate");

                     while(rs.next()){

                                          System.out.println(rs.getString("name"));

                           System.out.println(rs.getString("age"));

                                   }

                     rs.close();

                     stmt.close();

                     con.close();

                     }   catch(Exception e) {

                                   System.out.println(e);

                            }    

          }

}

12、带输入参数的SQL语句

1)要求:要实现使用SQL语句的输入与输出参数,必须在PreparedStatement类的对象上进行操作;同时由于CallableStatement类是PrepareStatement类的子类,所以在CallableStatemen对象上的操作也可以使用输入与输出参数(存储过程可以支持三种类型的参数:INOUT INOUT)

2)编程原理

n        在生成CallableStatementPreparedStatement类的对象时,可以在SQL语句中指定输入或输出参数(采用?代替参数)

n        在执行这个SQL语句之前,要对输入参数进行赋值。

PreparedStatement pstmt=con.prepareStatement("Update TableName set Name=? where ID=?");

    pstmt.setString(1,"zhang Hua");  //设置第一个参数(Name)为 “zhang Hua

    for(int i=1;i<3;i++)

    {  pstmt.setInt(2,i); //设置第二个参数(ID)为 1,2

       pstmt.executeUpdate();

    }

3)对参数赋值

setXXX方法用于给相应的输入参数进行赋值,其中XXXJDBC的数据类型,如:intString等。setXXX方法有两个参数

n        第一个是要赋值的参数在SQL语句中的位置

n        第二个参数是要传递的值,如100、“Beijing”等,随XXX的不同而为不同的类型。

4)程序示例:存储过程getTestData有三个输入参数

CallableStatement cstmt = con.prepareCall("{? = call getTestData (?,?,?)}");

cstmt.setString(1,Value);                                   //设置输入参数

cstmt.setInt(2,Value);

cstmt.setFloat(3,Value);

cstmt.registerOutParameter(1,java.sql.Types.VARCHAR);       //登记输出参数

ResultSet rs = cstmt.executeQuery();          //执行存储过程

rs.getString(1);                                                 //获得第一个字段的值

String returnResult=cstmt.getString(1);                  //获得返回的输出参数的值

13、关闭 JDBC Connection PreparedStatement 的正确方式

if (con!=null) {

      try {

   con.close();

            } catch (Exception ex) {

                     System.out.println(ex);                         

            }

         }

2.2  JavaJdbc技术深入

2.2.1 读写数据库中二进制字段(图像或者Word文档)

1、概述

1)二进制字段

所谓二进制字段,是指任何二进制类型的文件,可以保存在数据库的字段中,如图像文件或者Word文档文件等。 对二进制字段,在Access数据库中一般设计为OLE对象,而在SQLServer中则设计为image类型。

 

 

 

 

 

 

 

                                  

2)所涉及的技术

处理大二进制字段主要利用字节数组,当然也需要利用流的知识。

3)代码示例

import java.sql.*;

import java.io.*;

public class ReadWriteImage{

       String url="jdbc:odbc:studlist";

       String DBDriver="sun.jdbc.odbc.JdbcOdbcDriver";  

       Connection con=null;

     PreparedStatement ps=null;

       ResultSet rs=null;

       public ReadWriteImage(){   

              try{

              Class.forName(DBDriver);

              }catch(ClassNotFoundException e) {

  System.out.println(e);

           }        

              try{

        con=DriverManager.getConnection(url,"yanguser","1234");     

        } catch(SQLException e){

         }     

       }

       public boolean WriteImage() {     //将磁盘中的图像文件存储到数据库中

String fileName="SplashImage.jpg";    //也可以是Word文档的文件名称

String fileName="JavaDoc.doc"; 

String sqlStatement="insert into Person values(?,?,?,?,?,?)";                          

              try{

                     FileInputStream imageFIS = new FileInputStream(fileName); //所要保存的图像文件名称                                                                               ps=con.prepareStatement(sqlStatement,ResultSet.TYPE_SCROLL_SENSITIVE,

ResultSet.CONCUR_UPDATABLE);            //以下的代码是设置该记录中的各个字段的数据值           

                     ps.setString(1,"Yang");                      //用户名称

            ps.setString(2,"1234");                             //密码

            ps.setString(3,"市场部");                        //所在的部门

            ps.setInt(4,1);                                               //权限一

            ps.setInt(5,1);                                         //权限二

            ps.setBinaryStream(6,imageFIS,imageFIS.available());//用户的照片图像

            ps.executeUpdate();

              ps.close();                                //must close

            con.close();

           }catch(FileNotFoundException e) {

       System.out.println("没有找到"+fileName+"的文件");

                return false;

         }catch(IOException e) {

System.out.println(e.toString());

                return false;                   

         }catch(SQLException e)       {

       System.out.println(e.toString());

                return false;                   

         }

         System.out.println("已经将磁盘文件"+fileName+"写到数据库的userImage字段中");     

        return true;   

       }

       public boolean ReadImage(){       //从数据库中读出图像文件的数据并存储到磁盘文件中

String userName="Yang";            //数据库“person”中的某一个用户名称

String fileName="PersonImage.jpg";    //也可以是Word文档的文件名称]

String fileName="JavaCopy.doc";

String sqlStatement = "select * from Person where name='" + userName+"'";       

       try{               ps=con.prepareStatement(sqlStatement,ResultSet.TYPE_SCROLL_SENSITIVE,

ResultSet.CONCUR_UPDATABLE);

                     rs=ps.executeQuery();                       

                     if (!rs.next()){ //如果没有该用户的信息时,将向页面返回错误的提示

               System.out.println("数据库中没有该"+userName+"用户名称,请换另一个用户名称");

                      return false;

               }

 //如果有该用户的信息时,将获得该用户的图像数据,然后 保存到磁盘文件中

      FileOutputStream imageFOS = new FileOutputStream(fileName); //图像的文件名称

    InputStream in = rs.getBinaryStream("userImage"); //由于在数据库中存储的数据为二进制数据,因此获得该字段的二进制数据流

   byte byteBuffer[] = new byte[1024];           

   int byteCounter;

while((byteCounter = in.read(byteBuffer))!=-1){

imageFOS.write(byteBuffer, 0, byteCounter);//将所读出的图像二进制数据写入到磁盘文件中

}

   imageFOS.close();

   in.close();

              }catch(IOException e) {

       System.out.println(e.toString());

                return false;                   

         }catch(SQLException e)       {

System.out.println(e.toString());

                return false;                   

         }

         System.out.println("已经从数据库中读出了图像的数据并且将它存储到"+fileName+"文件中");

        return true;   

       }

       public static void main(String args[]){

       ReadWriteImage readWriteImage=new ReadWriteImage();

//            readWriteImage.WriteImage();

              readWriteImage.ReadImage();

       }

}

2、二进制图像字段

1)将图像保存到数据库中(完整的程序代码请见ReadWriteImage.java程序),    执行该程序后将在数据库的Person表中增加一条字段。

2)读出数据库中的图像字段数据(完整的程序代码请见ReadWriteImage.java程序),执行该程序后将在磁盘中产生出一个PersonImage.jpg文件。

3、二进制Word文档字段的读写:方法与读写二进制图像字段相同。

JDBC对数据库的事务操作

1、概述:

1)事务及事务的特性

JDBC的数据库操作中,一项事务是由一条或是多条表达式所组成的一个不可分割的工作单元。事务具有原子性、隔离性等的ACID(代表不可分割性---atomicity、一致性---consistency、隔离性----isolation和稳定性----durability)。

事务是一组语句,不过为了保持数据的完整性,这组语句都被看成是一个单一的语句。默认的情况下,JDBC工作在自动提交(auto-commit)的事务模式。你可以使用Connection类的setAutoCommit()方法来覆盖它。

我们通过提交commit()或是回滚rollback()来结束事务的操作。关于事务操作的方法都位于接口java.sql.Connection类中。

2)为什么要提供事务

事务是一种手段,用于保证一系列的数据库操作能够准确的完成。使用事务的一个重要原因,是完成一个操作可能需要使用多步,其中任何一步操作的失败,都希望全部回滚。以银行转账系统为例:

如右图所示,转账是通过两步完成的,但转账时,提款是正确的,但存款错误,总的账目将发生不平衡,显然这是不允许的。

 

 

 

3)怎么解决这个问题呢?

你可以把存款、提款、转账这三个商业对象注册到一个事务中去,当某个对象无法完成操作的时候,其它的对象自动恢复成原来的状态。

这个关系可以用右面的图来表示。

 

 

 

 

2JDBC中的事务特点

1JDBC中,打开一个连接对象Connection时,缺省是auto-commit模式,也就是说,一条对数据库的更新表达式代表一项事务操作,操作成功后,系统将自动调用commit()来提交,否则将调用rollback()来回滚。

每个SQL语句都被当作一个事务,即每次执行一个语句,都会自动的得到事务确认。为了能将多个SQL语句组合成一个事务,要将auto-commit模式屏蔽掉。在auto-commit模式屏蔽掉之后,如果不调用commit()方法,SQL语句不会得到事务确认。在最近一次commit()方法调用之后的所有SQL会在方法commit()调用时得到确认。

2)在jdbc中,可以通过调用setAutoCommit(false)来禁止自动提交。之后就可以把多个数据库操作的表达式作为一个事务,在操作完成后调用commit()来进行整体提交,倘若其中一个表达式操作失败,都不会执行到commit(),并且将产生响应的异常;此时就可以在异常捕获时调用rollback()进行回滚。

这样做可以保持多次更新操作后,相关数据的一致性

 

 

 

 

 

 

 

 

 

 

3)示例如下

try {

     conn = DriverManager.getConnection("URL","username","userpwd");

      conn.setAutoCommit(false);                   //禁止自动提交,设置回滚点

      stmt = conn.createStatement();

stmt.executeUpdate(alter table …”);         //数据库更新操作1

stmt.executeUpdate(insert into table …”); //数据库更新操作2

      conn.commit(); //事务提交

conn.setAutoCommit(true);     

}catch(Exception ex){

    ex.printStackTrace();

     try {

    conn.rollback(); //操作不成功则回滚

    }catch(Exception e) {

       e.printStackTrace();

    }

}

上述代码中的组件商务方法执行前,首先调用Connection对象实例consetAutoCommit方法并在方法中指定参数false,通知数据库服务器不自动提交SQL语句的执行结果。当组件中的方法执行成功后,调用con对象实例中的commit方法提交所有的数据库操作结果。在方法执行过程中如果发生任何类型的异常均导致事务范围内所有方法的运行结果回滚。

 

 

 

 

 

 

 

 

                                                                                   

JDBC事务管理方式是通过数据库管理系统的事务管理器(Transaction Manager)实现的。在该方式中,通过java.sql.Connection对象中的connect方法界定出事务的起始位置后,与相关对应的数据库管理器将启动一个事务过程。当组件方法运行结束后可以根据组件商务方法的运行情况调用commit方法向数据库提交运行结果或者调用rollback方法将事务范围内方法的运行结果回滚。

3、事务编程实例

1)创建数据库中的数据表和填入数据值

在教学示例的数据库文件stud.mdb中创建出两个数据库表,其各个字段的结构如下的FanTable1表中包含有三个字段。

编号,int ,4字节,为主键

姓名,varchar20字节

金额,money8字节

FanTable2表中包含有三个字段

编号,int ,4字节,为主键

姓名,varchar20字节

金额,money8字节

然后分别在该两表中输入数据

 

 

 

 

 

 

                                                                     

2)设计一个考虑JDBC事务的Java 应用程序---请见JDBC目录下的程序

执行该Java应用程序----注意JTAInJavaApp.javamain() 所在的程序

在转帐的金额中输入待转帐的数目,如5000,然后点击“从源到目标”按钮,将实现从1向表2进行转帐并提示正确地转帐的提示。

当表1中的用户的金额不足的时候,如果再次进行转帐,将出现错误的提示文字并且没有向目标方进行转帐。

 

 

                                                              

也可以点击“从目标到源”按钮,实现反转帐

 

 

                                                                                              

3)代码示例

 void sourceButton_actionPerformed(ActionEvent e){

      boolean A=false;

      boolean B=false;

      try{

        conn=getConnection();

       conn.setAutoCommit(false);                //不考虑JDBC事务时,可以注释掉

        stmt = conn.createStatement();

        stmt.execute("select * from FanTable1 where 编号=" + sourceInputTextField.getText());

        rs = stmt.getResultSet();

        rs.next();

        double transData=Double.parseDouble(transInputTextField.getText());

        if (rs.getDouble("金额") >= transData) {

            stmt.executeUpdate("Update FanTable1 set 金额=金额-"+transInputTextField.getText()+" where 编号 ="+sourceInputTextField.getText());

            A=true;

        }

        if (transData >= 0){

            stmt.executeUpdate("Update FanTable2 set 金额=金额+"+transInputTextField.getText()+" where 编号 ="+targetInputTextField1.getText());

            B=true;

        }

       if (A && B)  {

            messageTextField.setText("转账正确");

           conn.commit();      //事务有效,如果不考虑JDBC事务时,可以注释掉

        }   else{

            messageTextField.setText("转账错误");

           conn.rollback();            //不考虑JDBC事务时,可以注释掉

        }

     } catch (Exception E){

       E.printStackTrace();

     }

    finally {

      if (rs != null) {

         try {

            rs.close();

         } catch(Exception ignore){

         }

      }

      if (stmt != null){

        try {

            stmt.close();

        }catch(Exception ignore){

        }

      }

      if (conn != null) {

        try {

            conn.close();

        }catch(Exception ignore){

        }

      }

      displayAllData();

    }

  }

4设计一个不考虑JDBC事务Java 应用程序

将原来的程序中的注释掉,也就是不需要事务处理的支持。再次执行该程序

可以看出来,当发生转账错误的时候,转入方(目标)的数据还是继续增加,这就造成了数据的错误,这是不能允许的。

 

 

 

                                                       

用批处理而不是用PreparedStatement语句来提高效率

1、概述

1addBatch()方法

更新大量的数据通常是准备一个INSERT语句并多次执行该语句,结果产生大量的网络往返。为了减少JDBC调用次数和提高性能,你可以使用PreparedStatement对象的addBatch()方法一次将多个查询送到数据库里。

2)应用示例:例如,让我们比较一下下边的例子,情形1和情形2

情形1:多次执行PreparedStatement语句

PreparedStatement ps = conn.prepareStatement("INSERT into employees values (?, ?, ?)");

for (n = 0; n < 100; n++) {

ps.setString(name[n]);

ps.setLong(id[n]);

ps.setInt(salary[n]);

ps.executeUpdate();

}

情形2:使用批处理

PreparedStatement ps = conn.prepareStatement( "INSERT into employees values (?, ?, ?)");

for (n = 0; n < 100; n++) {

ps.setString(name[n]);

ps.setLong(id[n]);

ps.setInt(salary[n]);

ps.addBatch();

}

ps.executeBatch();

在情形1中,一个PreparedStatement用于多次执行一个INSERT语句。在这个情况下,为了100次插入需要101次网络往返,其中一次用于准备语句,额外100次网络往返用于执行每一个操作。当addBatch()方法的时候,如情形2所述,仅需要两个网络往返,一个准备语句,另一个执行批处理。尽管使用批处理需要更多的数据库CPU运算开销,但性能可由减少的网络往返获得。

记住要让JDBC驱动在性能方面有良好的表现,就要减少JDBC驱动和数据库服务器之间的网络通讯量。

2、使用批量处理功能涉及下面的两个方法:

1addBatch(String) 方法

如果你正在使用Statement 那么addBatch 方法可以接受一个通常的SQL语句,或者如果你在使用PreparedStatement ,那么也可以什么都不向它增加(请见前面的例)。

2executeBatch方法

executeBatch 方法执行那些SQL语句并返回一个int值的数组,这个数组包含每个语句影响的数据的行数。

注意:如果将一个SELECT语句或者其他返回一个ResultSetSQL语句放入批量处理中就会导致一个SQLException异常。