Java批量出入数据回滚处理,部分代码如下:
int[] count2 = {1,2};
ConDB conDB = new ConDB();
BillTop billTop = sssForm.getBillTop();
List<BillDetail> billDetailList = sssForm.getBillDetailList();
String sql1 = "{?= call  YP_insertBillMasterOrder(?,?,?,?,?,?,?,?,?,?)}";
String sql2 = "{?= call  YP_insertBillDetailOrder(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)}";
Connection con = conDB.getConnection();
try {

CallableStatement cstm1 = conDB.getCstm(sql1);
CallableStatement cstm2 = conDB.getCstm(sql2);

cstm1.registerOutParameter(1, java.sql.Types.INTEGER);
cstm1.setString(2, billTop.getBillSN());
cstm1.setString(3, billTop.getInputDate());
cstm1.setString(4, billTop.getClientID());
cstm1.setString(5, billTop.getStaffID());
cstm1.setString(6, billTop.getFinishDate());
cstm1.setString(7, billTop.getStorageID1());
cstm1.setInt(8, billTop.getBillType());
cstm1.setString(9, billTop.getSummary());
cstm1.setString(10, billTop.getMemo());
cstm1.setString(11, loginerID);
cstm1.execute();
billID = cstm1.getInt(1);
System.out.println(billID);
con.setAutoCommit(false);
for(int n=0;n<billDetailList.size()-1;n++){
BillDetail billDetail = billDetailList.get(n);
cstm2.registerOutParameter(1, java.sql.Types.INTEGER);
cstm2.setInt(2, billID);
cstm2.setString(3,billDetail.getAccountID());
cstm2.setString(4,billTop.getInputDate());
cstm2.setString(5,billTop.getClientID() );
cstm2.setString(6,billTop.getStaffID() );
cstm2.setString(7,billTop.getStorageID1() );
cstm2.setString(8,billTop.getStorageID2() );
cstm2.setString(9,billDetail.getWareID() );
cstm2.setString(10,billDetail.getProducedDate());
cstm2.setString(11,billDetail.getBatchNo());
cstm2.setString(12,billDetail.getCostMode());
cstm2.setInt(13,billDetail.getUnit());

cstm2.setDouble(14,billDetail.getAmount() );
cstm2.setDouble(15, billDetail.getToAmount());
cstm2.setDouble(16, billDetail.getPrice());
cstm2.setDouble(17, billDetail.getCostPrice());
cstm2.setDouble(18, billDetail.getSumTo());
cstm2.setDouble(19, billDetail.getCostSumTo());
cstm2.setDouble(20, billDetail.getDiscount());
cstm2.setDouble(21, billDetail.getDiscountPrice());
cstm2.setDouble(22, billDetail.getDiscountSumTo());
cstm2.setDouble(23, billDetail.getTax());
cstm2.setDouble(24, billDetail.getTaxAtion());
cstm2.setDouble(25, billDetail.getTaxPrice());
cstm2.setDouble(26, billDetail.getTaxSumTo());
cstm2.setInt(27,billTop.getBillType());
cstm2.setString(28, billDetail.getOrientation());
cstm2.setDouble(29, billTop.getPeriod());
cstm2.setString(30, billDetail.getRe());
count2[n] = cstm2.getInt(1);
cstm2.addBatch();
//count2[n] = cstm2.getInt(1);
}

cstm2.executeBatch();
con.commit();

for(int n=0;n<count2.length;n++){
System.out.println("count_"+count2[n]);
if(count2[n]==0)
suc = false;
}
如果我把获取返回语句count2[n] = cstm2.getInt(1)去掉,则代码可以正常运行。
不去掉就会报下面的错误,上面两个位置都会报错:java.sql.SQLException: [Microsoft][SQLServer 2000 Driver for JDBC]The requested data is not available.
at com.microsoft.jdbc.base.BaseExceptions.createException(Unknown Source)
at com.microsoft.jdbc.base.BaseExceptions.getException(Unknown Source)
at com.microsoft.jdbc.base.BaseCallableStatement.getAndValidateOutParameter(Unknown Source)
at com.microsoft.jdbc.base.BaseCallableStatement.getInt(Unknown Source)
at net.yjiasoft.sss.dao.sss.InsertBillDAO.insertBillOrder(InsertBillDAO.java:78)
at net.yjiasoft.sss.action.sss.StorageSellAction.saveOrderBill(StorageSellAction.java:52)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.apache.struts.actions.DispatchAction.dispatchMethod(DispatchAction.java:274)
at org.apache.struts.actions.DispatchAction.execute(DispatchAction.java:194)
at org.apache.struts.action.RequestProcessor.processActionPerform(RequestProcessor.java:419)
at org.apache.struts.action.RequestProcessor.process(RequestProcessor.java:224)
at org.apache.struts.action.ActionServlet.process(ActionServlet.java:1194)
at org.apache.struts.action.ActionServlet.doPost(ActionServlet.java:432)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:710)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:269)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:188)
at net.yjiasoft.sss.filter.SetCharacterEncodingFilter.doFilter(SetCharacterEncodingFilter.java:60)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:215)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:188)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:213)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:174)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:117)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:108)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:151)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:874)
at org.apache.coyote.http11.Http11BaseProtocol$Http11ConnectionHandler.processConnection(Http11BaseProtocol.java:665)
at org.apache.tomcat.util.net.PoolTcpEndpoint.processSocket(PoolTcpEndpoint.java:528)
at org.apache.tomcat.util.net.LeaderFollowerWorkerThread.runIt(LeaderFollowerWorkerThread.java:81)
at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:689)
at java.lang.Thread.run(Thread.java:619)

解决方案 »

  1.   

    我要返回的是存储过程里面的返回值,如return 5455,就得到5455
    而不是影响的记录条数!!!
      

  2.   

    复杂的返回值     
        
      关于存储过程的知识,很多人好像就熟悉我们所讨论的这些。如果这是存储过程的全部功能,那么存储过程就不是其它远程执行机制的替换方案了。存储过程的功能比这强大得多。     
      当你执行一个SQL查询时,DBMS创建一个叫做cursor(游标)的数据库对象,用于在返回结果中迭代每一行。ResultSet是当前时间点的游标的一个表示。这就是为什么没有缓存或者特定数据库的支持,你只能在ResultSet中向前移动。     
      某些DBMS允许从存储过程中返回游标的一个引用。JDBC并不支持这个功能,但是Oracle、PostgreSQL和DB2的JDBC驱动器都支持在ResultSet上打开到游标的指针(pointer)。     
      设想列出所有没有活到退休年龄的诗人,下面是完成这个功能的存储过程,返回一个打开的游标,同样也使用PostgreSQL的pl/pgsql语言:     
        
      create   procedure   list_early_deaths   ()   return   refcursor   as   'declare     
        
              toesup   refcursor;   
        
      begin     
        
              open   toesup   for   SELECT   poets.name,   deaths.age   FROM   poets,   deaths   --   all   entries   in   deaths   are   for   poets.   --   but   the   table   might   become   generic.     
        
              WHERE   poets.id   =   deaths.mort_id   AND   deaths.age   <   60;     
        
              return   toesup;   
        
      end;'   language   'plpgsql';     
        
      下面是调用该存储过程的Java方法,将结果输出到PrintWriter:     
      PrintWriter:     
        
      static   void   sendEarlyDeaths(PrintWriter   out){     
        
              Connection   con   =   null;   
        
              CallableStatement   toesUp   =   null;   
        
              try   {   
        
                      con   =   ConnectionPool.getConnection();     
        
                        //   PostgreSQL   needs   a   transaction   to   do   this...   con.   
        
                      setAutoCommit(false);   //   Setup   the   call.     
        
                      CallableStatement   toesUp   =   connection.prepareCall("{   ?   =   call   list_early_deaths   ()   }");     
        
                        toesUp.registerOutParameter(1,   Types.OTHER);     
        
                        toesUp.execute();     
        
                        ResultSet   rs   =   (ResultSet)   toesUp.getObject(1);     
        
                        while   (rs.next())   {   
        
                                      String   name   =   rs.getString(1);   
        
                                      int   age   =   rs.getInt(2);     
        
                                      out.println(name   +   "   was   "   +   age   +   "   years   old.");     
        
                          }     
        
                          rs.close();     
        
                    }       
        
                catch   (SQLException   e)   {   //   We   should   protect   these   calls.   toesUp.close();   con.close();   
        
              }   
        
      }     
        
      因为JDBC并不直接支持从存储过程中返回游标,我们使用Types.OTHER来指示存储过程的返回类型,然后调用getObject()方法并对返回值进行强制类型转换。     
      这个调用存储过程的Java方法是mapping的一个好例子。Mapping是对一个集上的操作进行抽象的方法。不是在这个过程上返回一个集,我们可以把操作传送进去执行。本例中,操作就是把ResultSet打印到一个输出流。这是一个值得举例的很常用的例子,下面是调用同一个存储过程的另外一个方法实现:     
        
      public   class   ProcessPoetDeaths{     
        
              public   abstract   void   sendDeath(String   name,   int   age);   
        
      }   
        
              static   void   mapEarlyDeaths(ProcessPoetDeaths   mapper){     
        
              Connection   con   =   null;     
        
              CallableStatement   toesUp   =   null;     
        
              try   {   
        
                        con   =   ConnectionPool.getConnection();     
        
                        con.setAutoCommit(false);     
        
                        CallableStatement   toesUp   =   connection.prepareCall("{   ?   =   call   list_early_deaths   ()   }");   
        
                          toesUp.registerOutParameter(1,   Types.OTHER);     
        
                          toesUp.execute();     
        
                          ResultSet   rs   =   (ResultSet)   toesUp.getObject(1);     
        
                        while   (rs.next())   {     
        
                        String   name   =   rs.getString(1);     
        
                        int   age   =   rs.getInt(2);     
        
                      mapper.sendDeath(name,   age);     
        
      }     
        
      rs.close();     
        
      }   catch   (SQLException   e)   {   //   We   should   protect   these   calls.   toesUp.close();     
        
      con.close();     
        
      }   
        
      }     
        
      这允许在ResultSet数据上执行任意的处理,而不需要改变或者复制获取ResultSet的方法:     
        
      static   void   sendEarlyDeaths(final   PrintWriter   out){     
        
                          ProcessPoetDeaths   myMapper   =   new   ProcessPoetDeaths()   {     
        
                                                                  public   void   sendDeath(String   name,   int   age)   {     
        
                                                                                                          out.println(name   +   "   was   "   +   age   +   "   years   old.");     
        
                                                                }     
        
                        };     
        
      mapEarlyDeaths(myMapper);   
        
      }     
        
      这个方法使用ProcessPoetDeaths的一个匿名实例调用mapEarlyDeaths。该实例拥有sendDeath方法的一个实现,和我们上面的例子一样的方式把结果写入到输出流。当然,这个技巧并不是存储过程特有的,但是和存储过程中返回的ResultSet结合使用,是一个非常强大的工具。 
      

  3.   

    肯定会出错呀,首先count2定义数组的长度是2
    当你循环的时候billDetailList.size()-1的大小超过2以后肯定就会抛出异常了。
      

  4.   

    其实用你那种方法没必要,有点麻烦调用sqlserver 存储过程。直接拿rs就行,和执行sql语句一样,不用call 
    例如: 
    String sql = "select * from user"; 
    Connection conn = DatabaseConnection.getConnection(); // 获得数据库连接 
    stmt  = conn.prepareStatement(sql); 
    rs = stmt.executeQuery(); 
    以上没问题吧,如果是调用存储过程 
    String sql = "spWWWClear 200812"; 
    Connection conn = DatabaseConnection.getConnection(); // 获得数据库连接 
    stmt  = conn.prepareStatement(sql); 
    rs = stmt.executeQuery(); 这样就OK了  
    http://topic.csdn.net/u/20090708/15/9d9c00c9-4868-4eb5-83f3-7baa80bdf85c.html
      

  5.   

    这个是我发的吧,sqlserver可以这样用,其他的数据库我就不保证能够成功了;