| |||||||||
日 | 一 | 二 | 三 | 四 | 五 | 六 | |||
---|---|---|---|---|---|---|---|---|---|
25 | 26 | 27 | 28 | 29 | 30 | 31 | |||
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 | 1 | 2 | 3 | 4 | 5 |
(文章本人原創,若轉載請注明出處)
下面看一下一些具體的實現,先看一下Sender接口的commitData方法的MySql實現,即SenderMySqlImp類:
很簡單吧,其實就是用Stream來做,另外在網上可以找到有關Oracle上傳blob的實現,一般都是先insert一條記錄,blob字段用empty_blob()函數插入一個空數據,然后再取出這個blob字段,最后按字節寫入blob,具體參考SenderOracleImp類吧。個人感覺還是在mysql的這個效率高些并且看起來簡單了很多。
然后來看看使用線程池的ProcessMulti類:
(文章本人原創,若轉載請注明出處)
在實際當中的情況是系統數據庫中需要上傳大量照片到數據庫中,數據量比較大,且不能在界面中通過操作逐個上傳,要批量自動進行。其實起來也比較簡單直接利用線程池將照片數據讀取成流再存入BLOB字段即可。但是在實現后些功能后又進入了一些改造,實現了線程池、單線程、是否使用用連接池、不同數據庫等不同的配置,這樣在不同配置下可以觀察到程序性能的不同。并且經過設計切換這些配置不需要修改程序。
使用DbAccess接口的getConnect()取得數據庫連接,DbImp和DbPoolingImp實現了不使用連接池和使用連接池的兩個版本。Sender接口的commitData()用來把BLOB數據寫到數據庫中,因為不同數據庫可能寫法有點不同所以這里SenderMySqlImp和SenderOracleImp分別是Mysql和Oracle的實現。Process接口的doProcess()是開始進行處理的方法,無論是單線程還是多線程。因此ProcessMulti和ProcessSingle是分別使用線程池以及單線程處理的類。ConfigMgr用于取得config.properties文件內配置信息,Logger是日志類,Helper中匯集了一些共用的靜態方法。最后DataSender是主程序的類:)
(文章本人原創,若轉載請注明出處)
在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文檔。至此控制線程池運作的幾個參數都從構建器中傳入了。
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;
在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;
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
Oracle PL/SQL中如何使用%TYPE和%ROWTYPE (轉載)
1. 使用%TYPE
在許多情況下,PL/SQL
DECLARE
v_FirstName VARCHAR2(20);
但是如果first_name列的定義改變了會發生什么(比如說表改變了,first_name現在的類型變為VARCHAR2(25))?那就會導致所有使用這個列的PL/SQL代碼都必須進行修改。如果你有很多的PL/SQL代碼,這種處理可能是十分耗時和容易出錯的。
這時,你可以使用"%TYPE"屬性而不是將變量類型硬性編碼。
例如:
DECLARE
v_FirstName students.first_name%TYPE;
通過使用%TYPE,v_FirstName變量將同students表的first_name列的類型相同(可以理解為將兩者邦定起來)。
每次匿名塊或命名塊運行該語句塊以及編譯存儲對象(過程、
使用%TYPE是非常好的編程風格,因為它使得PL/SQL更加靈活,更加適應于
2. 使用%ROWTYPE
2.1 PL/SQL記錄
PL/SQL記錄類型類似于C語言中的結構,是一種復合類型,是用戶
記錄提供了一種處理獨立的但又作為一個整體單元相關的變量的機制。請看:
DECLARE
v_StudentID NUMBER(5);
v_FirstName VARCHAR2(20);
v_LastName VARCHAR2(20);
這3個變量在邏輯上是相互關聯的,因為他們指向students表中不同的
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語句向記錄賦值,這將會從數據庫中檢索數據并將該
SELECT studentID,firstName,lastName
into v_StudentInfo
from students where studentID=32;
2.3 使用%ROWTYPE
在PL/SQL中將一個記錄聲明為具有相同類型的數據庫行的作法是很常見的。PL/SQL提供了%ROWTYPE
例如:
DECLARE
v_RoomRecord rooms%ROWTYPE;
將定義一個記錄,該記錄中的字段將與rooms表中的列相對應。
周5手機不幸被盜,可惡的小偷,偷我的手機你就斷手斷腳吧。明天準備聯系索愛和移動客服看是否能通過手機串碼把手機屏蔽,據說從技術角度講是可以行的通的,問題就是這種事手機運營商愿不愿意給做了。英國已經有這種服務可以使被盜手機不能再被使用,不知道特色中國啥時能有這種真正特色的服務呢。
我的索愛W810聽音樂音質超好,入耳式耳機也很棒,感覺比專業的魅族MP3還高一籌(主要魅族帶的耳機太爛,而且魅族音質風格有點假,特別配上自帶耳機后聽音樂塑料感極強)。w810音質風格基本上就是SONY早年CDWalkMan那種日系風格,加上入耳式耳機低音很強。另外FM收音功能也很不錯,信號很好,這個我也是和魅族的MP3對比過的,同樣環境下FM收音信號也強一些,相對由于信號弱造成的背景噪音小一些,加上聲音渲染修飾的好,不會有由于信號不好造成的刺耳聲。W810的拍照功能也不錯,拍的照片,特別是白天光線好時,拍出來的照片基本上可以冒充數碼相機的了。總之,用了一年,感覺W810最大缺點就是短信有容量限制,我基本上半個月就得清一回收件箱。個人認為w810作為手機來用是比不上NOKIA的好用,但是隨身聽、拍照功能的確很好,估計索愛的W系列基本也都是這樣。哎可惜現在連個尸體都沒留下..懷念呀.....
w810
平時忙沒時間逛商店,周6到濱江道溜達了一圈,據賣手機的服務員說,天語手機銷量已經能和NOKIA有的一拼了,想想一年多前還是名不見經傳,世界變化快呀。由于之前在淘寶上看過價格了,所以無論哪款手機門店里的價格基本上沒法接受了。現在消費觀念已不同從前了(有可能被全球經濟危機嚇得呵呵~),基本上2000元以上的手機就不看了,找了幾款什么索愛M600i、880i以及夏新E78...最后還是回發現干麻不買個NOKIA智能機的呢,我在W810前就是用的NOKIA6630呀,當時感覺智能機很強大很DIY。最后發現淘寶上N72行貨價格已經掉到1300左右(剛出時得有三四千了),還給開發票和全國聯保,OMG超值,就是它了.....
沒想到那個賣家別看信用值不高,東西相對便宜,服務態度到是超好,基本上算是送了個1GB卡,周日拍周一晚上就收到貨了,一看包裝寫著是空運...東西也不錯,開封后機器沒有任何問題,還有正規發票。有的信用值不高的賣家估計是想薄利多銷招攬客戶吧,不像有的幾個鉆或者是大皇冠的賣家,買個東西好像還不是很熱情的樣子,也有可能是客戶多忙不過來了。
說說N72,基實和我在w810之前用過的6630沒啥太多區別,都是NOKIA S60系統,就是外形小了一點,薄了一點點,內存大了些,這回是1GB存儲卡、攝像頭由130萬變成200萬,多了FM收音功能,操作系統版本新了些。我基本上當它是新版6630用,呵呵~
值得一提的是,NOKIA的耳機一般音質像地攤貨,這回的也一樣,打開包裝原配的耳機就扔到了一邊,我用NOKIA的AD-15轉換器(一種NOKIA專用耳機轉接器,外加功率放大功能的小東西)接上我的森海塞耳PX200,呵呵~~音質超爽,幾乎已超越了W810的音質,但是另一種風格不像是日系隨身聽低音很悶的那種。但是很奇怪如果接SonyE888音質就不怎么地,費解中..。自此以后又可以下載S60各種應用軟件、游戲、MP3播放軟件....重回NOKIA的智能DIY世界......也許哪天花幾百搞個藍牙GPS定位器,裝個地圖軟件,就可以實現手機GPS定位了。
n72 6630
用一個已不寫程序的朋友的話說,現在Java世界里真是讓人眼花繚亂,不僅對于新手,就算是過去熟悉Servlet、JSP,EJB的programmer,估計要完全搞明白現在的‘新生態架構’也不是很容易。從N多年前的‘一次編譯到處運行’到后來的EJB,再到現在的Spring、Hibernate、Webwork、JSF等諸多表現層、數據層,以及支持MVC、AOP的框架,再加上JDK1.5后加入的泛型等新功能,如果是一直以Servlet,JSP、JDBC或是EJB開發的話,現在突然接觸到這些東西真是要學習一陣了。最近在看《越獄》,想起一個并不恰當的比喻,好似一個服刑30年的老家伙,有一天終于刑滿釋放,結果出來后卻發現外面的世界早已不是他所想的那樣了。。。
還好我們對于這些變化早有準備,最快的學習方法莫過于直接針對一個系統進行源碼分析、學習、剝離出其中用到的技術方面,然后嘗試用于我們自已的項目或產品中去。用google、baidu很快就把焦點定位在了一個開源的網上社區http://www.laoer.com/?即天乙社區,我們關心的是技術架構,它用的是Struts+Spring+Hibernate,struts1.x版本雖然比起JSF、Tapestry、Webwork以及Webwork和Struts合并的Struts2.x,strtus1.x并不是很先進,但這套源碼的成熟度和這個架構的使用率一定很高,N多項目都在用這種架構,況且3者結合其中必有玄機,還是有的學了:)
粗看了一下這套系統的架構以及源碼,大約理了一下思路,打算根據源碼中用到的技術,按幾個方面去研究,圍繞社區系統中的應用,再寫幾篇文章就當是一種成果吧。
????????主要有以下幾方面:
Struts與Spring集成應用
?????????Hibernate與Spring的集成應用
????????OSCache的應用(這里主要用于緩存POJO)
??????? Intecepter即攔截器的應用
??????? Ajax的應用以及Prototype
??????? 。。。。
???????