<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    隨筆 - 9  文章 - 5  trackbacks - 0
    <2009年1月>
    28293031123
    45678910
    11121314151617
    18192021222324
    25262728293031
    1234567

    常用鏈接

    留言簿(1)

    隨筆分類

    隨筆檔案

    搜索

    •  

    最新評論

    閱讀排行榜

    評論排行榜

    (文章本人原創,若轉載請注明出處)

    下面看一下一些具體的實現,先看一下Sender接口的commitData方法的MySql實現,即SenderMySqlImp類:


        public void commitData(String path, String file) {
            ......
            Connection connect = null;
            try {
              //根據配置由Helper來確定是否用連接池,這只調用getConnection()即可
              connect = Helper.getConnection();
                connect.setAutoCommit(false);
                FileInputStream fis = new FileInputStream(path + file);
              
    //insert語句,有三個參數分別為id,image,filename字段。
               ps = connect.prepareStatement(sql.toString());
               ps.setString(1, UUID.randomUUID().toString());
             //將圖片文件流化,用jdbc直接寫到數據庫
              ps.setBinaryStream(2, fis, fis.available());
                ps.setString(3, file);
                ps.executeUpdate();
                connect.commit();
                count++;
                 Logger.writeLog("已處理文件數:"+count+",時間:"+new java.util.Date());

            } catch (Exception e) {
             ........
        }

        很簡單吧,其實就是用Stream來做,另外在網上可以找到有關Oracle上傳blob的實現,一般都是先insert一條記錄,blob字段用empty_blob()函數插入一個空數據,然后再取出這個blob字段,最后按字節寫入blob,具體參考SenderOracleImp類吧。個人感覺還是在mysql的這個效率高些并且看起來簡單了很多。

        然后來看看使用線程池的ProcessMulti類:


    public class ProcessMulti implements Process{
        
    private String path;
        
    private Vector<String> files = new Vector<String>();
        
    private Properties prop;

        ProcessMulti() {
            prop 
    = ConfigMgr.getProperties();  //取config.properties中配置信息
            
    this.path = prop.getProperty("path");
            
    this.files = Helper.getFiles(prop.getProperty("filetype"), this.path);
        }

        
    public void doProcess() {
    //正如前面兩篇所說,這里是線程池構建器,傳入相關參數
            BlobSenderThreadPool tpe 
    = new BlobSenderThreadPool(Integer
                    .valueOf(prop.getProperty(
    "corePoolSize")), Integer
                    .valueOf(prop.getProperty(
    "maxPoolSize")), Integer.valueOf(prop
                    .getProperty(
    "keepAliveTime")), TimeUnit.SECONDS,
                    
    new ArrayBlockingQueue<Runnable>(Integer.valueOf(prop
                            .getProperty(
    "maxPoolSize"))),
                    
    new BlobSenderThreadPool.DiscardPolicy(), files.size());

            Logger.writeLogForce(
    "開始處理." + new java.util.Date());
            
    for (int i = 0; i < this.files.size(); i++) {
                //向線程池提交要處理的任務,線程池根據其配置進行處理
                //Helper.getSender()會根據配置取得支持mysql或是oracel的寫入方法

                tpe.execute(
    new Runner(path, files.get(i), Helper.getSender()));
                Logger.writeLog(
    "已提交第" + (int)(i+1)  + "個文件" + ",時間為:"
                        
    + new java.util.Date());
            }
        //可以在這里寫一個打印輸出,實際上程序很快就執行完上面的for,運行到這里,但是處理并沒有完成,
           //主程序好像職業經理人,他的工作就是分配任務給下屬,自已就完成工作了,但下屬們還要接著忙活呵呵...

           System.out.println("任務已分配...");
        }
        //線程池類
        
    class BlobSenderThreadPool extends ThreadPoolExecutor {
            
    volatile int planTask;//計劃任務,即計劃要寫的文件數

            
    public BlobSenderThreadPool(int corePoolSize, int maximumPoolSize,
                    
    long keepAliveTime, TimeUnit unit,
                    BlockingQueue
    <Runnable> workQueue,
                    RejectedExecutionHandler handler, 
    int planTask) {
                
    super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
                
    this.planTask = planTask;
            }

            @Override
            //當某個線程處理完時會調用此方法
            
    protected void afterExecute(Runnable r, Throwable t) {
                Logger.writeLog(
    "當前已完成任務數:" + (int)(this.getCompletedTaskCount()+1)
                        
    + "計劃任務數:" + planTask);
               //若已處理完任務和計劃的任務數相同說明所有線程已完成處理,終止線程池處理
          if ((this.getCompletedTaskCount()+1)== planTask)
                    
    this.terminated();
                
    super.afterExecute(r, t);
            }

            @Override
            
    protected void terminated() {
                Logger.writeLogForce(
    "所有任務已完成 ,處理結束時間===>>" + new java.util.Date());
                System.exit(
    0);
            }

        }

    //要使用線程進行處理,類要實現Runable接口
        
    class Runner implements Runnable {
            String file;
            String path;
            Sender sender;

            Runner(String path, String file, Sender sender) {
                
    this.file = file;
                
    this.path = path;
                
    this.sender = sender;
            }
    //Runer的實例會被傳入線程池,線程被運行時會調用run方法
            
    public void run() {
                sender.commitData(path, file);
            }

        }
    posted @ 2009-03-21 10:40 依然Fantasy 閱讀(622) | 評論 (0)編輯 收藏

    (文章本人原創,若轉載請注明出處)

      在實際當中的情況是系統數據庫中需要上傳大量照片到數據庫中,數據量比較大,且不能在界面中通過操作逐個上傳,要批量自動進行。其實起來也比較簡單直接利用線程池將照片數據讀取成流再存入BLOB字段即可。但是在實現后些功能后又進入了一些改造,實現了線程池、單線程、是否使用用連接池、不同數據庫等不同的配置,這樣在不同配置下可以觀察到程序性能的不同。并且經過設計切換這些配置不需要修改程序。


    使用DbAccess接口的getConnect()取得數據庫連接,DbImp和DbPoolingImp實現了不使用連接池和使用連接池的兩個版本。Sender接口的commitData()用來把BLOB數據寫到數據庫中,因為不同數據庫可能寫法有點不同所以這里SenderMySqlImp和SenderOracleImp分別是Mysql和Oracle的實現。Process接口的doProcess()是開始進行處理的方法,無論是單線程還是多線程。因此ProcessMulti和ProcessSingle是分別使用線程池以及單線程處理的類。ConfigMgr用于取得config.properties文件內配置信息,Logger是日志類,Helper中匯集了一些共用的靜態方法。最后DataSender是主程序的類:)

    posted @ 2009-03-21 10:25 依然Fantasy 閱讀(306) | 評論 (0)編輯 收藏

    (文章本人原創,若轉載請注明出處)

       在JDK1.5提供了一個線程池ThreadPoolExecutor,可以處理用戶提交過來的線程。如果把要處理的任務比作蓋一個大樓,那么每一個建筑工人就相當于一個線程,那么這個ThreadPoolExecutor就好像包工頭,它來控制蓋這個大樓需要多少個工人,何時招進新工人,何時辭退已經長時間沒有事做的工人,等等此類事務。也就是說用戶程序不斷提交新的線程,ThreadPoolExecutor執行提交線程的同時會控制目前總共同時執行的線程數,銷毀已執行完閑置的線程等控制行為,保留最少閑置線程數,并且可以配置不同的處理策略。

       為什么要使用線程池呢,這與數據庫連接池的原理有點相仿,線程的創建是需要成本的,包括服務器CPU和內存資源,由于多線程是并行運行,程序運行過程中可能有的線程已經完成自身處理任務,處于閑置狀態,如果在這種情況下再不斷創建新任務就是在浪費服務器資源,此時應該盡量使用先前創建的好的并且是處理閑置狀態的線程來處理新任務,而線程池就可以有效的對此進行自動化管理,當然這個管理是可以由用戶配置的。

    ThreadPoolExecutor(int corePoolSize,
    int maximumPoolSize,
    long keepAliveTime,
    TimeUnit unit,
    BlockingQueue<Runnable> workQueue,
    RejectedExecutionHandler handler)

    這是線程池的構建器,用戶程序通過這個構建器傳參數,corePoolSize是線程池中核心線程數,運行的線程數不能少于這個核心線程數,否則就新建線程。maximumPoolSize是充許最大的線程數。keepAliveTime設置除核心線程外其它線程的空閑時間,超過這個時間線程就自動終止。unit是指的keepAliveTime的時間單位。BlockingQueue接口按生產則消費者算法設計的一個線程池內部處理線程隊列的接口,有三種實現SynchronousQueue、LinkedBlockingQueue和ArrayBlockingQueue,在實際運行程序時可以根據這三種實現得到不同的性能,比如有的實現可能在有新任務來時不新建線程,而是將其加入等待隊列,等有線程運行完時再分配給其使用。具體實現還是參看它們的JDK文檔吧,這里站在使用的角度它們是可以調整運行性能的開關。當最大線程和工作隊列容量都達到最大值時,再提交給線程池新任務就會被拒絕,此時線程池會調用RejectedExecutionHandler 接口進行處理,具體實現有四種策略。我們只需要選用其中一種在構建ThreadPoolExecutor時傳入即可。具體四種實現還是參看JDK文檔吧。關于ThreadPoolExecutor的JDK文檔。至此控制線程池運作的幾個參數都從構建器中傳入了。

    posted @ 2009-03-19 22:26 依然Fantasy 閱讀(846) | 評論 (0)編輯 收藏

    google了一篇不錯的例子,加了點注解,這樣看起來更方便了:)

    Oracle不像SQLServer那樣在存儲過程中用Select就可以返回結果集,而是通過Out型的參數進行結果集返回的。實際上是利用REF CURSOR

    --procedure返回記錄集:

    ----------------------聲明一個Package--------------
    CREATE OR REPLACE PACKAGE pkg_test
    AS
    TYPE myrctype IS REF CURSOR;

    PROCEDURE get (p_id NUMBER, p_rc OUT myrctype); --Package中聲明名為get 的Procedure(只有接口沒內容)

    END pkg_test;

    --------------------------------------------------------


    -----------------聲明Package Body,即上面Package中的內容,包括Procedure get---------------------
    CREATE OR REPLACE PACKAGE BODY pkg_test
    AS
    PROCEDURE get (p_id NUMBER, p_rc OUT myrctype)
    IS
    sqlstr VARCHAR2 (500);
    BEGIN
    IF p_id = 0 THEN
    OPEN p_rc FOR
    SELECT ID, NAME, sex, address, postcode, birthday
    FROM student;
    ELSE
    sqlstr :=
    'select id,name,sex,address,postcode,birthday
    from student where id=:w_id'; --w_id是個參數,

    --以下 p_rc是個REF CURSOR游標類型,而且是OUT型參數,即可返回一個記錄集了。USING p_id就是替換上面SQL中:w_id值拉:)
    OPEN p_rc FOR sqlstr USING p_id; 

    END IF;
    END get;
    END pkg_test;


    --function返回記錄集的例子,原理和上面相同,而是用function的return值來返回記錄集。

    函數返回記錄集:
    建立帶ref cursor定義的包和包體及函數:
    CREATE OR REPLACE
    package pkg_test as
    /* 定義ref cursor類型
    不加return類型,為弱類型,允許動態sql查詢,
    否則為強類型,無法使用動態sql查詢;
    */
    type myrctype is ref cursor;
    function get(intID number) return myrctype;
    end pkg_test;
    /

    CREATE OR REPLACE
    package body pkg_test as
    --函數體
    function get(intID number) return myrctype is
    rc myrctype; --定義ref cursor變量
    sqlstr varchar2(500);
    begin
    if intID=0 then
    --靜態測試,直接用select語句直接返回結果
    open rc for select id,name,sex,address,postcode,birthday from student;
    else
    --動態sql賦值,用:w_id來申明該變量從外部獲得
    sqlstr := 'select id,name,sex,address,postcode,birthday from student where id=:w_id';
    --動態測試,用sqlstr字符串返回結果,用using關鍵詞傳遞參數
    open rc for sqlstr using intid;
    end if;

    return rc;
    end get;

    end pkg_test;

    posted @ 2009-01-13 21:55 依然Fantasy 閱讀(1602) | 評論 (0)編輯 收藏

    在ORACLE存儲過程中創建臨時表

    存儲過程里不能直接使用DDL語句,所以只能使用動態SQL語句來執行

    --ON COMMIT DELETE ROWS 說明臨時表是事務指定,每次提交后ORACLE將截斷表(刪除全部行)
    --ON COMMIT PRESERVE ROWS 說明臨時表是會話指定,當中斷會話時ORACLE將截斷表。


    CREATE OR REPLACE PROCEDURE temptest
    (p_searchDate IN DATE)
    IS
    v_count INT;
    str varchar2(300);
    BEGIN
    v_count := 0;
    str:='drop table SETT_DAILYTEST';
    execute immediate str;
    str:='CREATE GLOBAL TEMPORARY TABLE SETT_DAILYTEST (
    NACCOUNTID NUMBER not null,
    NSUBACCOUNTID NUMBER not null)
    ON COMMIT PRESERVE ROWS';
    execute immediate str; ----使用動態SQL語句來執行
    str:='insert into SETT_DAILYTEST (select naccountid,nsubaccountid from sett_dailyaccountbalance)';
    execute immediate str;
    END temptest;

    上面建立一個臨時表的存儲過程

    下面是執行一些操作,向臨時表寫數據。

    CREATE OR REPLACE PROCEDURE PR_DAILYCHECK
    (
    p_Date IN DATE,
    p_Office IN INTEGER,
    p_Currency IN INTEGER,
    P_Check IN INTEGER,
    p_countNum OUT INTEGER)
    IS
    v_count INT;
    BEGIN
    v_count := 0;
    IF p_Date IS NULL THEN
    dbms_output.put_line('日期不能為空');
    ELSE
    IF P_Check = 1 THEN
    insert into SETT_DAILYTEST (select naccountid,nsubaccountid from sett_dailyaccountbalance
    where dtdate = p_Date);

    select
    count(sd.naccountid) into v_count
    from sett_subaccount ss,sett_account sa,sett_dailytest sd
    where sd.naccountid = sa.id and sd.nsubaccountid = ss.id and sa.id = ss.naccountid
    AND sa.nofficeid = p_Office AND sa.ncurrencyid = p_Currency
    and rownum < 2;
    COMMIT;
    p_countNum := v_count;
    dbms_output.put_line(p_countNum);
    END IF;
    IF P_Check = 2 THEN
    insert into SETT_DAILYTEST (select naccountid,nsubaccountid from sett_dailyaccountbalance
    where dtdate = p_Date);

    select
    count(sd.naccountid) into v_count
    from sett_cfsubaccount ss,sett_account sa,sett_dailytest sd
    where sd.naccountid = sa.id and sd.nsubaccountid = ss.id and sa.id = ss.naccountid
    AND sa.nofficeid = p_Office AND sa.ncurrencyid = p_Currency
    and rownum < 2;
    COMMIT;
    p_countNum := v_count;
    dbms_output.put_line(p_countNum);
    END IF;
    END IF;
    END PR_DAILYCHECK;

    posted @ 2009-01-13 21:23 依然Fantasy 閱讀(17356) | 評論 (0)編輯 收藏

    Oracle本身沒數組的概念,但是通過Oracle的Collections和Records類型可以模仿出單維數組和多維數組。

    請參考<<Oracle PL/SQL Programming>> Chapter 11、Chapter 12。


    ---------------------- 單維數組 ------------------------
    DECLARE
    TYPE emp_ssn_array IS TABLE OF NUMBER INDEX BY BINARY_INTEGER; ----注:聲明一個Collection

    best_employees emp_ssn_array;
    worst_employees emp_ssn_array;

    BEGIN
    best_employees(1) := '123456';
    best_employees(2) := '888888';

    worst_employees(1) := '222222';
    worst_employees(2) := '666666';

    FOR i IN 1..best_employees.count LOOP
    DBMS_OUTPUT.PUT_LINE('i='|| i || ', best_employees= ' ||best_employees(i)
    || ', worst_employees= ' ||worst_employees(i));
    END LOOP;

    END;



    ---------------------- 多維數組 ------------------------

    DECLARE

    TYPE emp_type IS RECORD ---------注:聲明一個Record類型 emp_type
    ( emp_id employee_table.emp_id%TYPE,           ----Record類型中的成員...
    emp_name employee_table.emp_name%TYPE,
    emp_gender employee_table.emp_gender%TYPE );

    TYPE emp_type_array IS TABLE OF ----注:聲明一個Collection類型 emp_type_array ,其中元素為emp_type類型
    emp_type INDEX BY BINARY_INTEGER;

    emp_rec_array emp_type_array;
    emp_rec emp_type;

    BEGIN
    emp_rec.emp_id := 300000000;
    emp_rec.emp_name := 'Barbara';
    emp_rec.emp_gender := 'Female';

    emp_rec_array(1) := emp_rec;

    emp_rec.emp_id := 300000008;
    emp_rec.emp_name := 'Rick';
    emp_rec.emp_gender := 'Male';

    emp_rec_array(2) := emp_rec;

    FOR i IN 1..emp_rec_array.count LOOP
    DBMS_OUTPUT.PUT_LINE('i='||i
    ||', emp_id ='||emp_rec_array(i).emp_id
    ||', emp_name ='||emp_rec_array(i).emp_name
    ||', emp_gender = '||emp_rec_array(i).emp_gender);
    END LOOP;

    END;
    -------------- Result --------------
    i=1, emp_id =300000000, emp_name =Barbara, emp_gender = Female
    i=2, emp_id =300000008, emp_name =Rick, emp_gender = Male

    posted @ 2009-01-13 21:07 依然Fantasy 閱讀(452) | 評論 (0)編輯 收藏
    主站蜘蛛池模板: 免费在线看v网址| 在免费jizzjizz在线播| 国产男女性潮高清免费网站| 亚洲精品一卡2卡3卡三卡四卡| 国产精品99精品久久免费| 久久久久亚洲精品无码系列| 中文字幕无码日韩专区免费| 亚洲av丰满熟妇在线播放| 99热免费在线观看| 亚洲制服丝袜精品久久| 成人AV免费网址在线观看| 亚洲日韩一中文字暮| 国产精品酒店视频免费看| 一区二区免费国产在线观看| 亚洲中文久久精品无码| 鲁大师在线影院免费观看 | 亚洲成年网站在线观看| 成年女人18级毛片毛片免费| 国产精品久久亚洲一区二区| 亚洲电影日韩精品 | 亚洲人成色4444在线观看| 国产男女猛烈无遮挡免费视频网站 | 亚洲一区在线免费观看| 四虎成人免费大片在线| 边摸边吃奶边做爽免费视频网站 | 亚洲成Av人片乱码色午夜| 最刺激黄a大片免费网站| 中文字幕亚洲码在线| 亚洲人成网站18禁止一区| 久草免费手机视频| 亚洲中文精品久久久久久不卡| 免费观看亚洲人成网站| a国产成人免费视频| 97se亚洲国产综合自在线| 亚洲精品动漫人成3d在线| 三年片在线观看免费大全电影| 亚洲欧洲专线一区| 亚洲精品亚洲人成人网| 青苹果乐园免费高清在线| 一级毛片在线播放免费| 亚洲精品宾馆在线精品酒店|