2010年9月11日 星期六

Servlet Life Cycle and TOMCAT (multi-threaded server)

http://www.iam.ubc.ca/guides/javatut99/servlets/lifecycle/index.html

Each servlet has the same life cycle:

  • A server loads and initializes the servlet
  • The servlet handles zero or more client requests
  • The server removes the servlet
    (some servers do this step only when they shut down)



Initializing a Servlet:

When a server loads a servlet, the server runs the servlet's init method. Initialization completes before client requests are handled and before the servlet is destroyed.

Even though most servlets are run in multi-threaded servers, servlets have no concurrency issues during servlet initialization. The server calls the init method once, when the server loads the servlet, and will not call the init method again unless the server is reloading the servlet. The server can not reload a servlet until after the server has destroyed the servlet by calling the destroy method.


Interacting with Clients:

After initialization, the servlet is able to handle client requests.

Destroying a Servlet:

Servlets run until the server are destroys them, for example, at the request of a system administrator. When a server destroys a servlet, the server runs the servlet's destroy method. The method is run once; the server will not run that servlet again until after the server reloads and reinitializes the servlet.

=================

Tomcat is a multi-threaded servlet container

this means that each request needs to be executed by some thread. Prior to Tomcat 3.2, the default was to create a new thread to serve each request that arrives. This behavior is problematic for loaded sites because:

  • Starting and stopping a thread for every request puts a needless burden on the operating system and the JVM.
  • It is hard to limit the resource consumption. If 300 requests arrive concurrently Tomcat will open 300 threads to serve them and allocate all the resources needed to serve all the 300 requests at the same time. This causes Tomcat to allocate much more resources (CPU, Memory, Descriptors...) than it should and it can lead to low performance and even crashes if resources are exhausted.

The solution for these problems is to use a thread pool, which is the default for Tomcat 3.2. Servlet containers that are using a thread pool relieve themselves from directly managing their threads. Instead of allocating new threads; whenever they need a thread they ask for it from the pool, and when they are done, the thread is returned to the pool. The thread pool can now be used to implement sophisticated thread management techniques, such as:

  1. Keeping threads "open" and reusing them over and over again. This saves the trouble associated with creating and destroying threads continuously.
    • Usually the administrator can instruct the pool not to keep too many idle threads, freeing them if needed.
  2. Setting an upper bound on the number of threads used concurrently. This prevents the resources allocation problem associated with unlimited thread allocation.
    • If the container maxed out to the threads upper limit, and a new request arrives, the new request will have to wait for some other (previous) request to finish and free the thread used to service it.

You can refine the techniques described above in various ways, but these are only refinements. The main contribution of thread pools is thread-reuse and having a concurrency upper bound that limits resource usage.

Using a thread pool in Tomcat is a simple move; all you need to do is to use a PoolTcpConnector in your configuration. For example the following server.xml fragment defines ajpv12, pooled Connector:


2010年9月10日 星期五

Cygwin bash_profile 的 path

方法 1:
=====================
export ALT_BOOTDIR=`cygpath -s -m "F:/Program Files/Java/jdk1.5.0_14"`
export ALT_BINARY_PLUGS_PATH=F:/JDKSource/jdk-6-ea-plug-b08-windows-i586-26_mar_2008/openjdk-binary-plugs
export ALT_MSVCRT_DLL_PATH=`cygpath -s -m "C:/WINDOWS/system32"`
export ALT_MSVCR71_DLL_PATH=C:/WINDOWS/system32

export DXSDK_DIR=`cygpath -s -m "H:/Program Files/Microsoft DirectX SDK (February 2007)"`
export ALT_COMPILER_PATH=`cygpath -s -m "H:\Program Files\Microsoft Visual Studio 8\VC\bin"`


方法 2:
====================

It seems to be a quoting problem. This is what I was doing:

$ ttt="$(cygpath -u "$JAVA_HOME")"

$ echo $ttt
/cygdrive/c/Program Files/Java/jdk1.5.0_10

$ cd $ttt
bash: cd: /cygdrive/c/Program: No such file or directory

$ cd "$ttt"

$pwd
/cygdrive/c/Program Files/Java/jdk1.5.0_10

Is is possible to setup the variable to not require the double quotes?
Since my other method doesn't require the double quotes, it would
make the scripting much easier. I wouldn't need to keep track of which
variables I had to double quote.

$ tttt="$(cygpath -u "$(cygpath -m -s "$JAVA_HOME")")"

$ echo $tttt
/cygdrive/c/PROGRA~1/Java

$ cd $tttt

$ pwd
/cygdrive/c/PROGRA~1/Java

Notice that I can use $tttt directly without have to use the double quote.

int 和 Integer 的差別

所謂的 int 是像上位前輩所說的~
int 是所謂的 premitive type 就是所謂的原紿資料型態~
而 Integer 是 Java 的內建類別型態~

int a = 5; == int a;
a =5;

只是說有個變數名稱是 a ,定義為 int 的型態~有給值 5 給到a~

Integer a=new Integer(5);
裡面的 Integer 是個類別名稱~
而 new Integer(5) 是說建立一個 Integer 類別的實體 a ~
而實體內是個 int 型態的值 5~

所以意思就是說~一個是定義變數的原紿資料型態~
而另一個是建立了一個 Java 的內建類別的實體~
如果你使用了 Integer 類別的話~
()<=裡面的值就”必需”是要為 int or String 的資料型態~如果想看詳細一點~
可以查看 Java 官方網站的 Doucumaentaion ~裡面有很詳細的介紹~
不知道我這樣講會不會讓你更不了解了~^^"

2010年8月2日 星期一

Framework: Hibernate

Java Hibernate程式的過程中,我們可以粗分四大步驟(1~4) 與二大檔案(5、6),依序是 :

1. Configuration:

1.1. 透過 Configuration File (hibernate.cfg.xml) 設定與 Database 連線的方式與設定要匯入哪些 Mapping File。

1.2 (JavaEE 環境) 透過 JNDI Service 來註冊 org.hibernate.SessionFactory 成為 Global 物件。

1.3 (JavaEE 環境) 設定 AP Server 所提供的 Transaction 的功能。

1.4. 透過 org.hibernate.cfg.Configuration 的 configure() mathod 來讀取 Configuration File。

1.5 透過 org.hibernate.cfg.Configuration 的 buildSessionFactory() 來產生 下一步驟要用到的 org.hibernate.SessionFactory 。

2. SessionFactory:

2.1 一個 org.hibernate.SessionFactory 只對應到一個 Database

2.2 必須在程式要使用之前就必須建立好 SessionFactory,因為需要一點時間才能建立,所以最好是在網站或程式初始化時就去建立,至少必須在程式開始接觸 Database 之前就要建立。

2.3 必須放在所有程式都可以取用到地方 ( 有 JNDI 就註冊到 JNDI 中, 如果沒有 JNDI, 且是Web Apps, 也可以註冊在 ServletContext)。

2.4 org.hibernate.SessionFactory 會 catch 執行 Hibernate 所產生的 SQL statement 和 Database 的 metadata。

2.5 org.hibernate.SessionFactory 是 thread-safe 物件,會自己處理 multi-thread。

2.6 透過 org.hibernate.SessionFactory 的 openSession() 或是 getSession() 來 產生/取得 下一步驟要用到的 org.hibernate.Session。

3. Session:

3.1 org.hibernate.Session 包含了 JDBC 的 Connection object。

3.2 所以可以視為 Hibernate 與 Database 之間溝通的橋樑、過程。

3.3 org.hibernate.Session 可以提供 org.hibernate.Transaction object

3.4 所以存取 Persistent Class 都需要透過 org.hibernate.Session 。

4. Transaction:

4.1 org.hibernate.Transaction 將真正在底層執行 Transaction service包裝起來,

在 J2EE 中使用 JTA 的 UserTransaction 服務多個 Database (ex: 轉帳);或利用 J2SE 中 JDBC 的 Transaction 來服務一個 Databae。

4.2 在 Hibernate 3.x 中,存取 Persistent Class 的動作一定要包在 org.hibernate.Transaction 的可視範圍之中。

例如:

Transaction transaction = session.beginTransaction();

存取 Persistent Class ...
......

transaction.commit();

5. Persistance Class:

5.1 最好是 JavaBeans 的架構。

5.2 使用 Hibernate 來處理的 Table 一定要有 primary key,且對應到 Java Class 中的 欄位與 setter,為了避免誤改,所以都應該宣告為 private 屬性。primary key 是獨一無二的 id,所以在選定時最好避免與目前專案相關性太高的欄位,應儘量使用流水號。

5.3 不要使用 final。Hibernte 會自動為每個 Persistent Class 產生各自的 proxy,但 proxy 會繼承 Persistent Class,所以一旦設為 final,將會限制 proxy 所提供的功能。

5.4 要小心處理 Persistent Class 的三種狀態:
transient : 尚未跟 Persistent Context 接觸。( 與 Session 沒有關係的狀態 )
persistent : 正在跟 Persistent Context 接觸。
detached : 以前曾經跟 Persistent Context 接觸,但現在分開了。

6. Hibernate Mapping File:

6.1 每一個 Persistent Class 都會有自己的 Mapping File,以維護 Table 與 Persistent Class 的對應關係。

6.2 Mapping File 的副檔名為 .hbm.xml。

6.3 Mapping File 的存放位置必須跟所對應的 Persistent Class 的目錄相同。

6.4 在使用 Mapping File 之前必須註冊到 Configuration file 中,通常使用靜態的方法,直接寫入 hibernate.cfg.xml 中。

Singleton

獨體模式 Singleton

確保一個類別只有一個實體,並給它一個存取的全域點(global point)。


有些物件只需要一個實體,如果有多個實體同時存在,反而會造成問題,如 memory pool、garbage collector... 等。

全域物件

最簡單的作法可以採用一個全域物件。但這需要透過程式員之間的約定並嚴格遵守才能達成;並且,這個全域物件在程式開始執行時就建立好了,如果一直都沒用到,反而造成資源無謂地浪費。

物件的出生

物件產生 Q&A:

Q: 一個物件如何產生?
A: 對於 C++ 而言,有兩種方式。一種是直接宣告變數式的 Object obj,一種是動態產生 Object* obj = new Object();而對於 Java 而言,只有一種:new Object()。無論哪種方式,都會配置記憶體,然後以 constructor 來初始化物件。

Q: 如何限制人們建立物件?
A: 將 constructors 宣告為 private,如此一來外部無人可以呼叫 constructors。

Q: 那有誰可以建立物件?
A: 物件自己(物件本身的其他方法可以呼叫 constructors)。

Q: 要如何取得一個這樣的物件實體?
A: 物件提供一個方法,稱為 getInstance(),這個方法會初始化一個物件並回傳。

Q: 如果這個實體是一個 static 變數,會怎麼樣?
A: 那所有人都會存取到同一份實體。

獨體模式

獨體模式 Singleton就是可以確保某個類別只有一個實體的方法。將一個類別的 constructors 宣告為 private,並提供一個方法 getInstance() 讓外部取得物件的唯一實體。這個實體是一個 static 物件,若第一次呼叫時這個唯一實體沒有被初始化,則以 private constructor 來為它初始化。如果已經初始化完成了,就直接回傳這個 static 實體。這種在需要時才建立物件的技術,稱為 lazy instantiate。

Java 版本程式碼:

JAVA:
  1. public class Singleton
  2. {
  3. private static Singleton uniqueInstance;
  4. private Singleton() {} //private ctor

  5. public static Singleton getInstance() {
  6. if(uniqueInstance == null) {
  7. uniqueInstance = new Singleton();
  8. }
  9. return uniqueInstance;
  10. }
  11. }

C++版本:

C++:
  1. class Singleton
  2. {
  3. Singleton() {} //private ctor

  4. public:
  5. static Singleton& getInstance() {
  6. static Singleton uniqueInstance;
  7. return uniqueInstance;
  8. }
  9. };

這是獨體模式非常簡單的類別圖:
獨體模式

多緒環境的獨體模式

但是上述的獨體模式實踐,在多緒環境下會有 race condition 問題。

如 Java 版本第 9 行的判斷式,如果第一個執行緒判定條件成立並進入 if-block,但在產生實體前,就切換到第二個執行緒。則第二個執行緒也會判定條件成立並進入 if-block,造成兩個執行緒各執有一份實體,破壞 Singleton 的唯一性。

這種情況在 Java 有三種解決方式。

將 getInstance() 宣告為 synchronized 方法:

JAVA:
  1. public class Singleton
  2. {
  3. private static Singleton uniqueInstance;
  4. private Singleton() {} //private ctor

  5. public static synchoronized Singleton getInstance() { //加上 synchronized 關鍵字
  6. if(uniqueInstance == null) {
  7. uniqueInstance = new Singleton();
  8. }
  9. return uniqueInstance;
  10. }
  11. }

synchronized 關鍵字可以「同步化」一個方法 —— 同時只有一個執行緒可以進入此方法執行。在此執行緒結束之前,其他執行緒只得等待。缺點:每一次呼叫 getInstance() 都得同步化執行(事實上只有第一次需要),效能較差。

「率先」建立實體:

JAVA:
  1. public class Singleton
  2. {
  3. private static Singleton uniqueInstance = new Singleton();

  4. private Singleton() {}

  5. public static Singleton getInstance() {
  6. return uniqueInstance;
  7. }
  8. }

以 static initializer 來建立 uniqueInstance 物件(而不使用 lazy instantiate)。這麼一來 uniqueInstance 在 JVM 載入此類別時就會被建立,無 race condition 問題。缺點:一開始就得建立實體,若不使用則徒然浪費資源。

Double-checked lock:

JAVA:
  1. public class Singleton
  2. {
  3. private volatile static Singleton uniqueInstance; //加上 volatile 關鍵字

  4. private Singleton() {}

  5. public static Singleton getInstance() {
  6. if(uniqueInstance == null) { //如果實體不存在,才會進入下面的同步區塊
  7. // ---- synchronized block ---- 同步區塊會 atomic 執行
  8. synchronized(Singleton.class) {
  9. if(uniqueInstance == null) { //再做一次檢查,怕在進入前有其他執行緒趁隙將實體建立
  10. uniqueInstance = new Singleton();
  11. }
  12. }
  13. // ---- synchronized block ----
  14. }
  15. return uniqueInstance;
  16. }
  17. }

以 volatile 關鍵字 uniqueInstance 宣告為多工處理的共用變數,並以 synchronized block 讓檢查與建立的步驟 atomic 進行。但是加上一個 if 來讓此區塊只有「第一次」才會進入,兼顧了效能。這是效能最好的方案,但較複雜,且 Java 1.4 以前版本不適用。



From~http://notes.xamous.net/archives/139

2010年8月1日 星期日

DAO/Repository/Hibernate/JDBC

Repository in Action

10:30上午 二月 17, 2006 in category Java by ingramchen

我朋友最近正在讀 POJOs in Action 這本書。Repository/DAO/Hibernate/JDBC 之間的關係搞的他一頭渾水,下面我嘗試就我所知的,提供一些解釋:

Repository 是 domain 中,有關 儲存 這種觀念的具現。當你在 model domain 時,你會觀察到有些物件在建立完成後,需要被留下來,並且 儲存在某個地方。然後下次要用時再把它取出,然後繼續工作。下面是物件的 life cycle 的流程:

   new object --> object working... --> persistent and store object
--> query stored object --> object continue working --> ....

當你觀察到這些行為後,你可以將這個觀念抽象化,並且設計一個專職的 物件來管理。在 Domain Driven Design 這本書中,作者命名這樣的物件為 Repository 。從上面的流程也可以看出,建立一個新的物件其實也算是物件生命週期的一環,所以 Repository 有時也會負責物件的建立。當然 如果建立的過程很複雜,可以採另一個 pattern: Factory 來輔助。

Repository 和 DAO 雖然同樣是處理資料,但是 Repository 著眼點和 DAO 並不一樣。DAO 只知道存取資料這種事,不會從物件的生命週期去思考。而物件的生命週期 和 business logic 是習習相關的,所以在設計上,Repository 是 domain 的一環,也會包含一些 business logic。比方說 AccountRepository 可能會 throw DuplicateAccountException 這種 business exception。如果是純 DAO 的話, 就不該寫這種東西了。

整理 DAO/Repository/Hibernate/JDBC 等之間的關係:

  • Pattern:
    • Repository -- 專職管理 Object 生命週期的物件。
    • DAO -- 專職處理資料的物件
  • Tools and Framework:
    • JDBC -- Java 處理 RDBMS 的工具
    • Hibernate -- Java 處理 Object 與 RDBMS mapping 的工具

Repository 和 DAO 都只是 pattern 的一種,可以應用在各種領域。 沒人規定 DAO 只能用在 JDBC,如果要處理 xml 資料,也可以套用 DAO 這個 pattern 來輔助。同理 Repository 也是一樣,跟 JDBC/Hibernate...這些工具一 點關係也沒有。再者 Design pattern 也跟 Java 也沒什麼關係,想在 C# 裡套用 Repository, DAO 也行。

把 Hibernate 和 Respository 綁在一起只是 POJOs in Action 作者的做法而已。 他覺得這兩個是完美的組合,所以他才寫書推廣他的理念。事實上也是如此,因為 Hibernate 提供很多方便管理 Object 生命週期的功能,所以寫起 Repository 變的很簡單。如果未來 Respository 真的很多人採用了,那麼 Hibernate 的功 勞可不小啊。

不過 Repository 這一詞在整個程式界裡不是很多人採用,有時候明明大家 寫的是 repository,卻也叫 DAO。所以大多數的時候只會看到 DAO 這個詞 。用 Repository 一詞的只有 Domain Driven Design 和 POJOs in Action 這兩本 書而已。

我個人是採用折衷的方式:我都管它們叫 DAO,而不是 Repository,一來 DAO 大家比較看的懂,二來 DAO 只要三個字母,比 Repository 短很多。 不過我的 DAO 也會兼差做些 Repository 的事就是了,但是比例很少,因為我不希望存取資料庫的程式碼混合 business logic,而且這樣 Unit Test 也不大好寫。

SQL:: JOIN


SQL Join語法

Join有兩種屬性:
INNER
OUTER

1.INNER
只顯示匹配的行.

2.OUTER
不論是否匹配,都顯示行.
LEFT, RIGHT, FULL 都帶有OUTER屬性

Join共有六種:
Inner Join
Natural Join
Left Outer Join
Right Outer Join
Full Outer Join
Cross Join

1.Inner Join
Inner Join其實等同於多個Where條件式的連結,
像
FROM a, b WHERE a.id = b.id AND b.val > 5
FROM a INNER JOIN b ON (a.id = b.id) WHERE b.val > 5
是一樣的

2.Natural Join
Natural Join只是自動的匹配兩個表之間相同的欄位,
像
FROM a, b WHERE a.id = b.id AND b.val > 5
FROM a NATURAL JOIN b WHERE b.val > 5
是一樣的.
可用在任何一種Inner 或 Outer Join.
Natural 與 USING 也是很相像的,只是Natural
只會讓兩個表的相同欄位出現一次.

3.Left Outer Join
4.Right Outer Join
其實這兩個幾乎是一樣的,只是方向性的不同.
以Left Outer Join來說,左邊顯示所有左表的值,而右邊顯示右表匹配的值.
如果沒有匹配的右表表,則放空值.
Right Outer Join則左右方向相反.

5.Full Outer Join
左右表都顯示,匹配的則顯示,沒有匹配的放空值.
好比把 Left Outer Join 和 Right Outer Join作聯集.

6.Cross Join
交叉連結,會得到兩個表的所有乘積組合.

From~ http://www.wretch.cc/blog/sky4s/2250385


[SQL]Join的觀念

前言

在位置上很常聽到人家討論SQL的時候,Join來Join去,害我每次都會回頭(因為聽起來實在很像在叫我的名字)。

小的自認為DB與SQL的功力,一向很薄弱。
而training新人時,第一個要解釋table與table之間關係,通常也是會講到join。

我雖然大概知道join是怎麼一回事,不過有時候解釋起來,看新人一臉疑惑的表情,也是讓我頗受傷的。

所以,上次看了呂老師書上的一張圖,
真的深深覺得一張圖加兩張table的範例資料,勝過千言萬語啊。

What is join?

Join,通常稱做交集,而交集是什麼呢?望文生義,看圖說故事,各位看官就會瞭解了。

這張圖,解釋了兩張表之間的關係。

兩張table,我們分別定義為Left table跟Right table。Left就是被交集的table (要稱做資料集合也可以),Right就是拿來交集的table。
就像A x B = C,我們稱A為被乘數,B為乘數,一樣的意思。

比較常看到的,Left table,就是Select * from [table1] ,這個from的table。
Right table,則是被join的那一張table,
例如

Select * from [table1]
Left join [table2] on [table1].fk=[table2].pk


在這例子,table2就是圖裡面的Right table。

而兩張table join的條件,也就是他們是靠什麼來做交集的,就是on後面的 [table1].fk=[table2].pk。
交集的條件不一定只有一個,Left table與Right table的交集後的結果,也有可能是空集合,也就是無符合的資料。

好,接著我們來給兩張表一些資料。

Table1:

PK FK
1 a1
2 a2
3 a3


Table2:

PK Description
a2 a2很棒
a3 a3很棒
a4 a4很棒

當我們現在join的條件是Table1.FK與Table2.PK。

  1. Inner Join,就代表Table1與Table2兩者,完全符合交集條件的資料集合。
    也就是上面圖裡面,兩個圈圈共同圈起來的那個部分,
    SQL的範例,通常inner join我們會直接寫
    • Select * from table1, table2
      Where table1.FK=table2.PK

      Inner Join代表的是兩個table共同的部分才要篩選出來,所以誰是Left,誰是Right其實沒有多大分別。

      於是,以我們的範例資料來說,這個例子會撈出
    • Table1_PK Table1_FK Table2_Description
      2 a2 a2很棒
      3 a3 a3很棒
  2. 除了Inner以外,當然就是Outer了。
    Outer又分兩種,一種是左邊的Outer,一種是右邊的Outer。
    什麼叫做左邊的Outer,在我們的圖裡面,就是左邊的圈圈全都要出來,而符合交集條件的右邊圈圈,資料也要帶出來。
    • Left join的SQL如下:
      Select * from table1
      Left outer join table2 on table1.FK = table2.PK

      在這例子,代表了table1就是我們的Left table,所以Left outer join後,table1所有資料都應該顯示出來,
      而符合table1.FK = table2.PK條件的資料,應該會帶出Table2的相關欄位資料。
    • Table1_PK Table1_FK Table2_Description
      1 null null
      2 a2 a2很棒
      3 a3 a3很棒

    • Right join的SQL如下:
      Select * from table1
      Right outer join table2 on table1.FK = table2.PK

      在這例子,table2代表我們的Right table,所以Table2所有資料應該顯示出來,並且符合交集條件的資料,應該有table1的欄位資料。
    • Table1_PK Table2_PK Table2_Description
      2 a2 a2很棒
      3 a3 a3很棒
      null a4 a4很棒

另外要提醒的,outer是可以省略的。而在Join裡面,Where條件扮演著什麼角色?
其實Where的條件,是用來限制Left table與Right table的Scope的。

所以where與join可以說毫無關係,因為是用來分別定義table的篩選條件,而非交集的條件。

希望不會在有朋友搞不清楚,到底什麼條件要放在join的on裡面,
什麼條件該放在where裡面。

用這張圖去思考一下,會幫您釐清許多的問題。

結論

  1. 上述的所有table,只是一種資料集合。也就是代表,它可以是另外一個子查詢後的結果。
  2. Left與Right的定義,則是被乘數與乘數的分別。
  3. Where只是篩選條件,拿來限制Left table與Right table的Scope。
  4. Inner Join沒有左右的差異,所以可以直接用兩張表的一個where 條件來表示,當然您要寫成inner join的表示法也會更符合這張圖的意義喔。
  5. Outer Join的Outer可以省略,但Left或Right則不能省略。

複雜或多層的Join,只是像寫程式剝洋蔥或穿衣服一樣,可以想像一行一行的join下來,每次都只有一個被乘數和乘數在做交集而已。
就像
a1 x a2 x a3 x a4,您會先計算a1 x a2後,再 x a3,之後的結果再 x a4一樣。