| |||||||||
日 | 一 | 二 | 三 | 四 | 五 | 六 | |||
---|---|---|---|---|---|---|---|---|---|
28 | 29 | 30 | 1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 | |||
12 | 13 | 14 | 15 | 16 | 17 | 18 | |||
19 | 20 | 21 | 22 | 23 | 24 | 25 | |||
26 | 27 | 28 | 29 | 30 | 31 | 1 | |||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
(文章本人原創(chuàng),若轉(zhuǎn)載請注明出處)
下面看一下一些具體的實(shí)現(xiàn),先看一下Sender接口的commitData方法的MySql實(shí)現(xiàn),即SenderMySqlImp類:
很簡單吧,其實(shí)就是用Stream來做,另外在網(wǎng)上可以找到有關(guān)Oracle上傳blob的實(shí)現(xiàn),一般都是先insert一條記錄,blob字段用empty_blob()函數(shù)插入一個(gè)空數(shù)據(jù),然后再取出這個(gè)blob字段,最后按字節(jié)寫入blob,具體參考SenderOracleImp類吧。個(gè)人感覺還是在mysql的這個(gè)效率高些并且看起來簡單了很多。
然后來看看使用線程池的ProcessMulti類:
(文章本人原創(chuàng),若轉(zhuǎn)載請注明出處)
在實(shí)際當(dāng)中的情況是系統(tǒng)數(shù)據(jù)庫中需要上傳大量照片到數(shù)據(jù)庫中,數(shù)據(jù)量比較大,且不能在界面中通過操作逐個(gè)上傳,要批量自動進(jìn)行。其實(shí)起來也比較簡單直接利用線程池將照片數(shù)據(jù)讀取成流再存入BLOB字段即可。但是在實(shí)現(xiàn)后些功能后又進(jìn)入了一些改造,實(shí)現(xiàn)了線程池、單線程、是否使用用連接池、不同數(shù)據(jù)庫等不同的配置,這樣在不同配置下可以觀察到程序性能的不同。并且經(jīng)過設(shè)計(jì)切換這些配置不需要修改程序。
使用DbAccess接口的getConnect()取得數(shù)據(jù)庫連接,DbImp和DbPoolingImp實(shí)現(xiàn)了不使用連接池和使用連接池的兩個(gè)版本。Sender接口的commitData()用來把BLOB數(shù)據(jù)寫到數(shù)據(jù)庫中,因?yàn)椴煌瑪?shù)據(jù)庫可能寫法有點(diǎn)不同所以這里SenderMySqlImp和SenderOracleImp分別是Mysql和Oracle的實(shí)現(xiàn)。Process接口的doProcess()是開始進(jìn)行處理的方法,無論是單線程還是多線程。因此ProcessMulti和ProcessSingle是分別使用線程池以及單線程處理的類。ConfigMgr用于取得config.properties文件內(nèi)配置信息,Logger是日志類,Helper中匯集了一些共用的靜態(tài)方法。最后DataSender是主程序的類:)
(文章本人原創(chuàng),若轉(zhuǎn)載請注明出處)
在JDK1.5提供了一個(gè)線程池ThreadPoolExecutor,可以處理用戶提交過來的線程。如果把要處理的任務(wù)比作蓋一個(gè)大樓,那么每一個(gè)建筑工人就相當(dāng)于一個(gè)線程,那么這個(gè)ThreadPoolExecutor就好像包工頭,它來控制蓋這個(gè)大樓需要多少個(gè)工人,何時(shí)招進(jìn)新工人,何時(shí)辭退已經(jīng)長時(shí)間沒有事做的工人,等等此類事務(wù)。也就是說用戶程序不斷提交新的線程,ThreadPoolExecutor執(zhí)行提交線程的同時(shí)會控制目前總共同時(shí)執(zhí)行的線程數(shù),銷毀已執(zhí)行完閑置的線程等控制行為,保留最少閑置線程數(shù),并且可以配置不同的處理策略。
為什么要使用線程池呢,這與數(shù)據(jù)庫連接池的原理有點(diǎn)相仿,線程的創(chuàng)建是需要成本的,包括服務(wù)器CPU和內(nèi)存資源,由于多線程是并行運(yùn)行,程序運(yùn)行過程中可能有的線程已經(jīng)完成自身處理任務(wù),處于閑置狀態(tài),如果在這種情況下再不斷創(chuàng)建新任務(wù)就是在浪費(fèi)服務(wù)器資源,此時(shí)應(yīng)該盡量使用先前創(chuàng)建的好的并且是處理閑置狀態(tài)的線程來處理新任務(wù),而線程池就可以有效的對此進(jìn)行自動化管理,當(dāng)然這個(gè)管理是可以由用戶配置的。
ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
RejectedExecutionHandler handler)
這是線程池的構(gòu)建器,用戶程序通過這個(gè)構(gòu)建器傳參數(shù),corePoolSize是線程池中核心線程數(shù),運(yùn)行的線程數(shù)不能少于這個(gè)核心線程數(shù),否則就新建線程。maximumPoolSize是充許最大的線程數(shù)。keepAliveTime設(shè)置除核心線程外其它線程的空閑時(shí)間,超過這個(gè)時(shí)間線程就自動終止。unit是指的keepAliveTime的時(shí)間單位。BlockingQueue接口按生產(chǎn)則消費(fèi)者算法設(shè)計(jì)的一個(gè)線程池內(nèi)部處理線程隊(duì)列的接口,有三種實(shí)現(xiàn)SynchronousQueue、LinkedBlockingQueue和ArrayBlockingQueue,在實(shí)際運(yùn)行程序時(shí)可以根據(jù)這三種實(shí)現(xiàn)得到不同的性能,比如有的實(shí)現(xiàn)可能在有新任務(wù)來時(shí)不新建線程,而是將其加入等待隊(duì)列,等有線程運(yùn)行完時(shí)再分配給其使用。具體實(shí)現(xiàn)還是參看它們的JDK文檔吧,這里站在使用的角度它們是可以調(diào)整運(yùn)行性能的開關(guān)。當(dāng)最大線程和工作隊(duì)列容量都達(dá)到最大值時(shí),再提交給線程池新任務(wù)就會被拒絕,此時(shí)線程池會調(diào)用RejectedExecutionHandler 接口進(jìn)行處理,具體實(shí)現(xiàn)有四種策略。我們只需要選用其中一種在構(gòu)建ThreadPoolExecutor時(shí)傳入即可。具體四種實(shí)現(xiàn)還是參看JDK文檔吧。關(guān)于ThreadPoolExecutor的JDK文檔。至此控制線程池運(yùn)作的幾個(gè)參數(shù)都從構(gòu)建器中傳入了。
google了一篇不錯(cuò)的例子,加了點(diǎn)注解,這樣看起來更方便了:)
Oracle不像SQLServer那樣在存儲過程中用Select就可以返回結(jié)果集,而是通過Out型的參數(shù)進(jìn)行結(jié)果集返回的。實(shí)際上是利用REF CURSOR
--procedure返回記錄集:
----------------------聲明一個(gè)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(只有接口沒內(nèi)容)
END pkg_test;
--------------------------------------------------------
-----------------聲明Package Body,即上面Package中的內(nèi)容,包括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是個(gè)參數(shù),
--以下 p_rc是個(gè)REF CURSOR游標(biāo)類型,而且是OUT型參數(shù),即可返回一個(gè)記錄集了。USING p_id就是替換上面SQL中:w_id值拉:)
OPEN p_rc FOR sqlstr USING p_id;
END IF;
END get;
END pkg_test;
--function返回記錄集的例子,原理和上面相同,而是用function的return值來返回記錄集。
函數(shù)返回記錄集:
建立帶ref cursor定義的包和包體及函數(shù):
CREATE OR REPLACE
package pkg_test as
/* 定義ref cursor類型
不加return類型,為弱類型,允許動態(tài)sql查詢,
否則為強(qiáng)類型,無法使用動態(tài)sql查詢;
*/
type myrctype is ref cursor;
function get(intID number) return myrctype;
end pkg_test;
/
CREATE OR REPLACE
package body pkg_test as
--函數(shù)體
function get(intID number) return myrctype is
rc myrctype; --定義ref cursor變量
sqlstr varchar2(500);
begin
if intID=0 then
--靜態(tài)測試,直接用select語句直接返回結(jié)果
open rc for select id,name,sex,address,postcode,birthday from student;
else
--動態(tài)sql賦值,用:w_id來申明該變量從外部獲得
sqlstr := 'select id,name,sex,address,postcode,birthday from student where id=:w_id';
--動態(tài)測試,用sqlstr字符串返回結(jié)果,用using關(guān)鍵詞傳遞參數(shù)
open rc for sqlstr using intid;
end if;
return rc;
end get;
end pkg_test;
在ORACLE存儲過程中創(chuàng)建臨時(shí)表
存儲過程里不能直接使用DDL語句,所以只能使用動態(tài)SQL語句來執(zhí)行
--ON COMMIT DELETE ROWS 說明臨時(shí)表是事務(wù)指定,每次提交后ORACLE將截?cái)啾恚▌h除全部行)
--ON COMMIT PRESERVE ROWS 說明臨時(shí)表是會話指定,當(dāng)中斷會話時(shí)ORACLE將截?cái)啾怼?/p>
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; ----使用動態(tài)SQL語句來執(zhí)行
str:='insert into SETT_DAILYTEST (select naccountid,nsubaccountid from sett_dailyaccountbalance)';
execute immediate str;
END temptest;
上面建立一個(gè)臨時(shí)表的存儲過程
下面是執(zhí)行一些操作,向臨時(shí)表寫數(shù)據(jù)。
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;
Oracle本身沒數(shù)組的概念,但是通過Oracle的Collections和Records類型可以模仿出單維數(shù)組和多維數(shù)組。
請參考<<Oracle PL/SQL Programming>> Chapter 11、Chapter 12。
---------------------- 單維數(shù)組 ------------------------
DECLARE
TYPE emp_ssn_array IS TABLE OF NUMBER INDEX BY BINARY_INTEGER; ----注:聲明一個(gè)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;
---------------------- 多維數(shù)組 ------------------------
DECLARE
TYPE emp_type IS RECORD ---------注:聲明一個(gè)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 ----注:聲明一個(gè)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
Oracle PL/SQL中如何使用%TYPE和%ROWTYPE (轉(zhuǎn)載)
1. 使用%TYPE
在許多情況下,PL/SQL
DECLARE
v_FirstName VARCHAR2(20);
但是如果first_name列的定義改變了會發(fā)生什么(比如說表改變了,first_name現(xiàn)在的類型變?yōu)閂ARCHAR2(25))?那就會導(dǎo)致所有使用這個(gè)列的PL/SQL代碼都必須進(jìn)行修改。如果你有很多的PL/SQL代碼,這種處理可能是十分耗時(shí)和容易出錯(cuò)的。
這時(shí),你可以使用"%TYPE"屬性而不是將變量類型硬性編碼。
例如:
DECLARE
v_FirstName students.first_name%TYPE;
通過使用%TYPE,v_FirstName變量將同students表的first_name列的類型相同(可以理解為將兩者邦定起來)。
每次匿名塊或命名塊運(yùn)行該語句塊以及編譯存儲對象(過程、
使用%TYPE是非常好的編程風(fēng)格,因?yàn)樗沟肞L/SQL更加靈活,更加適應(yīng)于
2. 使用%ROWTYPE
2.1 PL/SQL記錄
PL/SQL記錄類型類似于C語言中的結(jié)構(gòu),是一種復(fù)合類型,是用戶
記錄提供了一種處理獨(dú)立的但又作為一個(gè)整體單元相關(guān)的變量的機(jī)制。請看:
DECLARE
v_StudentID NUMBER(5);
v_FirstName VARCHAR2(20);
v_LastName VARCHAR2(20);
這3個(gè)變量在邏輯上是相互關(guān)聯(lián)的,因?yàn)樗麄冎赶騭tudents表中不同的
DECLARE
/*Define a record type to hold common student informationi*/
TYPE t_StudentRecord IS RECORD(
StudentID NUMBER(5),
FirstName VARCHAR2(20),
LastName VARCHAR2(20);
/*Declare a variable of this type.*/
v_StudentInfo t_StudentRecord;
2.2 記錄賦值
可以用SELECT語句向記錄賦值,這將會從數(shù)據(jù)庫中檢索數(shù)據(jù)并將該
SELECT studentID,firstName,lastName
into v_StudentInfo
from students where studentID=32;
2.3 使用%ROWTYPE
在PL/SQL中將一個(gè)記錄聲明為具有相同類型的數(shù)據(jù)庫行的作法是很常見的。PL/SQL提供了%ROWTYPE
例如:
DECLARE
v_RoomRecord rooms%ROWTYPE;
將定義一個(gè)記錄,該記錄中的字段將與rooms表中的列相對應(yīng)。
周5手機(jī)不幸被盜,可惡的小偷,偷我的手機(jī)你就斷手?jǐn)嗄_吧。明天準(zhǔn)備聯(lián)系索愛和移動客服看是否能通過手機(jī)串碼把手機(jī)屏蔽,據(jù)說從技術(shù)角度講是可以行的通的,問題就是這種事手機(jī)運(yùn)營商愿不愿意給做了。英國已經(jīng)有這種服務(wù)可以使被盜手機(jī)不能再被使用,不知道特色中國啥時(shí)能有這種真正特色的服務(wù)呢。
我的索愛W810聽音樂音質(zhì)超好,入耳式耳機(jī)也很棒,感覺比專業(yè)的魅族MP3還高一籌(主要魅族帶的耳機(jī)太爛,而且魅族音質(zhì)風(fēng)格有點(diǎn)假,特別配上自帶耳機(jī)后聽音樂塑料感極強(qiáng))。w810音質(zhì)風(fēng)格基本上就是SONY早年CDWalkMan那種日系風(fēng)格,加上入耳式耳機(jī)低音很強(qiáng)。另外FM收音功能也很不錯(cuò),信號很好,這個(gè)我也是和魅族的MP3對比過的,同樣環(huán)境下FM收音信號也強(qiáng)一些,相對由于信號弱造成的背景噪音小一些,加上聲音渲染修飾的好,不會有由于信號不好造成的刺耳聲。W810的拍照功能也不錯(cuò),拍的照片,特別是白天光線好時(shí),拍出來的照片基本上可以冒充數(shù)碼相機(jī)的了。總之,用了一年,感覺W810最大缺點(diǎn)就是短信有容量限制,我基本上半個(gè)月就得清一回收件箱。個(gè)人認(rèn)為w810作為手機(jī)來用是比不上NOKIA的好用,但是隨身聽、拍照功能的確很好,估計(jì)索愛的W系列基本也都是這樣。哎可惜現(xiàn)在連個(gè)尸體都沒留下..懷念呀.....
w810
平時(shí)忙沒時(shí)間逛商店,周6到濱江道溜達(dá)了一圈,據(jù)賣手機(jī)的服務(wù)員說,天語手機(jī)銷量已經(jīng)能和NOKIA有的一拼了,想想一年多前還是名不見經(jīng)傳,世界變化快呀。由于之前在淘寶上看過價(jià)格了,所以無論哪款手機(jī)門店里的價(jià)格基本上沒法接受了。現(xiàn)在消費(fèi)觀念已不同從前了(有可能被全球經(jīng)濟(jì)危機(jī)嚇得呵呵~),基本上2000元以上的手機(jī)就不看了,找了幾款什么索愛M600i、880i以及夏新E78...最后還是回發(fā)現(xiàn)干麻不買個(gè)NOKIA智能機(jī)的呢,我在W810前就是用的NOKIA6630呀,當(dāng)時(shí)感覺智能機(jī)很強(qiáng)大很DIY。最后發(fā)現(xiàn)淘寶上N72行貨價(jià)格已經(jīng)掉到1300左右(剛出時(shí)得有三四千了),還給開發(fā)票和全國聯(lián)保,OMG超值,就是它了.....
沒想到那個(gè)賣家別看信用值不高,東西相對便宜,服務(wù)態(tài)度到是超好,基本上算是送了個(gè)1GB卡,周日拍周一晚上就收到貨了,一看包裝寫著是空運(yùn)...東西也不錯(cuò),開封后機(jī)器沒有任何問題,還有正規(guī)發(fā)票。有的信用值不高的賣家估計(jì)是想薄利多銷招攬客戶吧,不像有的幾個(gè)鉆或者是大皇冠的賣家,買個(gè)東西好像還不是很熱情的樣子,也有可能是客戶多忙不過來了。
說說N72,基實(shí)和我在w810之前用過的6630沒啥太多區(qū)別,都是NOKIA S60系統(tǒng),就是外形小了一點(diǎn),薄了一點(diǎn)點(diǎn),內(nèi)存大了些,這回是1GB存儲卡、攝像頭由130萬變成200萬,多了FM收音功能,操作系統(tǒng)版本新了些。我基本上當(dāng)它是新版6630用,呵呵~
值得一提的是,NOKIA的耳機(jī)一般音質(zhì)像地?cái)傌洠@回的也一樣,打開包裝原配的耳機(jī)就扔到了一邊,我用NOKIA的AD-15轉(zhuǎn)換器(一種NOKIA專用耳機(jī)轉(zhuǎn)接器,外加功率放大功能的小東西)接上我的森海塞耳PX200,呵呵~~音質(zhì)超爽,幾乎已超越了W810的音質(zhì),但是另一種風(fēng)格不像是日系隨身聽低音很悶的那種。但是很奇怪如果接SonyE888音質(zhì)就不怎么地,費(fèi)解中..。自此以后又可以下載S60各種應(yīng)用軟件、游戲、MP3播放軟件....重回NOKIA的智能DIY世界......也許哪天花幾百搞個(gè)藍(lán)牙GPS定位器,裝個(gè)地圖軟件,就可以實(shí)現(xiàn)手機(jī)GPS定位了。
n72 6630