J2EE之oracle、mysql存儲過程調用


      最近幾天在研究hibernate、JPA對存儲過程的調用,主要是針對有返回結果集的存儲過程的調用方法,個人感覺存儲過程是個好東西,雖然說heibernate對數據訪問封裝的比較不錯,再加上他的緩存機制,確實很多情況下足夠了,不過存儲過程還是有他的用武之地,如果能用他提高性能,為何不用....

      好吧,不討論他有沒有用處,掌握了以后備用也是不錯的選擇,重點看看oracle的存儲過程調用,mysql的要簡單的多。

      (一)、oracle存儲過程調用

        先在pl/sql中建立一個存儲過程,代碼如下:

--創建帶有游標的包
create or replace package mypackage as
  type mycursor is ref cursor;
end mypackage;

--創建存儲過程
create or replace procedure searchUsers(user_cursor out mypackage.mycursor) is
begin
  open user_cursor for select * from wyuser order by id asc;
end;

建立完成以后,如果想測試,可以先看打印出來的結果測試一下,下面是我的測試代碼:

--執行存儲過程
declare
outcursor mypackage.mycursor;
myid number;
mydate Date;
mypassword varchar2(20);
myname varchar2(20);
begin
   dbms_output.put_line('輸出');
   searchUsers(outcursor);
   loop
      fetch outcursor into myid,mydate, mypassword,myname;
      exit when outcursor%notfound;
      dbms_output.put_line(myname||' '||mypassword);
    end loop;
end;

執行后是沒有問題的,然后我們重點在如何調用。
   ①hibernate中調用

     在hibernate中調用oracle的存儲過程,可能會繞過heibernate,直接用jdbc操作,所以,我一直在找可有什么方法可以得到connection數據庫連接,在hibernate3.0之前提供session.connection()方法可以直接獲取到連接,不過我用的是hibernate4.0這個方法已經被廢棄了,而是用dowork方式代替,下面就看看這種方式下的調用:

    /**
     * 調用存儲過程訪問數據
     */
    public List<Object[]> searchProc() {
        final List<Object[]> rtnObjs = new ArrayList<Object[]>();
        try {
            Session session = this.sessionFactory.openSession();
            session.beginTransaction();
            Work work = new Work() {
                public void execute(Connection cn) throws SQLException {
                    CallableStatement csmt = cn
                            .prepareCall("{call searchUsers(?)}");
                    csmt.registerOutParameter("user_cursor", OracleTypes.CURSOR);
                    csmt.execute();
                    ResultSet rs = (ResultSet) csmt.getObject("user_cursor");
                    while (rs.next()) {
                        //結果用數組保存,這里只是為了測試,使用定長數組****不通用                         Object[] objects = new Object[4];
                        objects[0] = rs.getLong("ID");
                        objects[1] = rs.getTimestamp("createtime");
                        objects[2] = rs.getString("password");
                        objects[3] = rs.getString("username");

                        rtnObjs.add(objects);
                    }
                }
            };
            session.doWork(work);
            session.getTransaction().commit();

        } catch (Exception e) {
            System.out.println("DAO層訪問存儲過程失敗");
        }

        return rtnObjs;
    }

返回的結果是一個Object數組集合,這樣,就可以在業務層對這個數組進行處理,可以將其實例化為需要的對象等等.....

    ②Spring JDBC訪問oracle存儲過程

      本來想用JPA訪問存儲過程的,不過貌似對於有返回值的存儲過程JPA處理起來不夠強大,故,如法炮制,依然繞到繞過去,用SpringJDBC來處理。存儲過程依然是上面使用的那個,下面看看JAVA的調用代碼:

    /**
     * Spring JDBC方式調用ORACLE存儲過程,返回結果集
     */
    @Override
    public List<Object[]> search() {
        List<Object[]> rtnObjs = new ArrayList<Object[]>();

        rtnObjs = this.jdbcTemplate.execute(new CallableStatementCreator() {

            @Override
            public CallableStatement createCallableStatement(Connection con)
                    throws SQLException {
                CallableStatement cs = con.prepareCall("{call searchUsers(?)}");
                cs.registerOutParameter("user_cursor", OracleTypes.CURSOR);
                return cs;
            }
        }, new CallableStatementCallback<List<Object[]>>() {

            @Override
            public List<Object[]> doInCallableStatement(CallableStatement cs)
                    throws SQLException, DataAccessException {

                cs.execute();
                ResultSet rs = (ResultSet) cs.getObject("user_cursor");
                List<Object[]> objs = new ArrayList<Object[]>();
                while (rs.next()) {
                    Object[] objects = new Object[4];
                    objects[0] = rs.getLong("ID");
                    objects[1] = rs.getTimestamp("createtime");
                    objects[2] = rs.getString("password");
                    objects[3] = rs.getString("username");

                    objs.add(objects);
                }
                return objs;
            }
        });

        return rtnObjs;
    }

翻看了jdbcTemplate中的方法,很多都是回調方法,而且很多大部分都可以可以返回List<Object[]>和List<Map<String,Vlaue>>這種類型,說實話這種結構在實際開發中很有用途,所以在上面的代碼中也按照這種方法,返回了List<Object[]>交給業務層可以靈活處理。上面的方法首先繼承CallableStatementCreator中創建CallableStatement的方法注冊存儲過程和定義返回類型,在CallableStatementCallback回調接口中的重寫do方法,讓之前注冊的存儲過程執行並得到起返回值,當然也可以自己寫兩個類分別繼承CallableStatementCreator接口Callable- -StatementCallback這兩個接口,實現其中的方法,然后在jdbcTemplate的execute中調用.....

 

    (二)、mysql存儲過程調用

      相對於oracle的存儲過程,mysql的存儲過程就簡單多了,這里也同樣編寫一個返回結果集的存儲過程,然后利用jdbcTemplate對其進行調用

CREATE DEFINER=`root`@`localhost` PROCEDURE `getuser`()
BEGIN
  select * from wyuser;
END

真是巨簡單,看看存儲過程的調用是不是也一樣簡單

/**
     * 調用mysql存儲過程
     * 
     * @return
     */
    @Override
    public List<Object[]> getUser() {

        List<Object[]> rtnObjs = new ArrayList<Object[]>();

        rtnObjs = this.getJdbcTemplate().execute("{call getuser()}",
                new CallableStatementCallback<List<Object[]>>() {
                    @Override
                    public List<Object[]> doInCallableStatement(
                            CallableStatement cs) throws SQLException,
                            DataAccessException {
                        List<Object[]> objects = new ArrayList<Object[]>();
                        ResultSet rs = cs.executeQuery();
                        while (rs.next()) {
                            Object[] objArr = new Object[4];
                            objArr[0] = rs.getLong("ID");
                            objArr[1] = rs.getTimestamp("createtime");
                            objArr[2] = rs.getString("password");
                            objArr[3] = rs.getString("username");

                            objects.add(objArr);
                        }
                        return objects;
                    }
                });

        return rtnObjs;

    }

好吧,呵呵,調用當然還是和調用oracle的procedure方式一樣,如果是針對有參數的調用也基本上沒有一致。

CREATE DEFINER=`root`@`localhost` PROCEDURE `finduser`(in uid int)
BEGIN
       select * from wyuser where id=uid;
END

調用代碼:

    /**
     * 調用mysql存儲過程,根據ID查找用戶
     */
    @Override
    public Object[] findUser(int id) {
        final int uid = id;
        Object[] objArr = new Object[4];
        objArr = this.getJdbcTemplate().execute("{call finduser(?)}",
                new CallableStatementCallback<Object[]>() {

                    @Override
                    public Object[] doInCallableStatement(CallableStatement cs)
                            throws SQLException, DataAccessException {
                        Object[] arr = new Object[4];
                        cs.setInt("uid", uid);  //為存儲過程中參數賦值                         ResultSet rs = (ResultSet) cs.executeQuery();
                        while (rs.next()) {
                            arr[0] = rs.getLong("ID");
                            arr[1] = rs.getTimestamp("createtime");
                            arr[2] = rs.getString("password");
                            arr[3] = rs.getString("username");
                        }

                        return arr;
                    }
                });

        return objArr;
    }

 對於其他的方式,比如有返回值的,可以結合網上的一些案例自己再嘗試下。

 至此,調用這兩種存儲過程的方式都介紹完了,說的比較簡單,呵呵,有代碼有真相.....

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM