2011年7月27日 星期三

原來java的修飾關鍵字是沒有順序的...!!

public class test123{
 static final private String s1 = "abc";
 private static final String s2 = "def";
 public static void main(String args[]){
  System.out.println(s1);
  System.out.println(s2);
 }
}

印出:
abc
def

一直以為java的修飾關鍵字是要照順序的
但是今天才發現
原來是不用的!
修飾關鍵字照順序應該是個習慣
但並不是文法上的要求!!

用jsp確認Server上的jvm版本

我最近用jdk 1.5版本編譯檔案
丟到遠方的AP Server上
可以執行

所以知道這台Server上的jvm版本
必定>=1.5
因為沒有向上相容這件事
舉例而言
也就是1.4無法跑1.5編譯出來的class
否則會出現java.lang.UnsupportedClassVersionError
但是詢問Server管理員
跟我說這台Server上的jvm版本是1.4
這與我的認知衝突

所以到底是幾版呢?
可以用以下jsp驗證
<%@ page import="java.util.*"%>
<%
out.println("The version of current JVM is: " + System.getProperties().getProperty("java.version"));
%>
把這支jsp丟到Server上
得到結果是1.5
證明我是對的...哦ㄝ

這裡是相關討論

表單上的type=sumbit和type=button的按鈕

表單上有兩個按鈕
一個是<input type=submit />
一個是<input type=button />
這兩個的差別
在於type=submit在預設上
會引發表單的onSubmit事件
而type=button什麼事件都不會發生!

可以看以下例子:
test.html:
<script>
function doChk(){
 alert("No way!");
 return;
}

function doChk2(){
 alert("No send!");
 return;
}
</script>

<form action="test1.jsp" onSubmit="doChk2();">
<input type=submit value="Send?" onClick="doChk();" />
</form>


test1.jsp:
<%
out.println("You send....");
%>



在瀏覽器看到的結果是:

跳出視窗:No Way!
跳出視窗:No Send!
新畫面:You send....

所以可以知道幾件事:
1.type=submit的按鈕, 會先觸發按鈕自己的onClick事件, 再觸發表單的onSubmit事件
2.無論onSubmit事件的處理函式如何寫, 最後一定會將表單送出, 無法阻止表單送出的發生

2011年7月14日 星期四

java版本的向下相容

jre是向下相容的!
這向下相容有兩個面向

1.低版本編譯好的class, 能在高版本直接執行:
你以1.4版編譯好的class
能在1.6版的jre上直接執行, 不需做任何修改
換句話說
所以1.6版的jre能夠直接地
吃下比它低版本的class

2.高版本編譯好的class, 能在低版本執行:
咦?
這樣有下向相容嗎?
在1.6的jdk直接編譯: javac hello.java
這樣你拿去1.4版jre執行
會得到以下結果:
Exception in thread "main" java.lang.UnsupportedClassVersionError: test (Unsuppo
rted major.minor version 50.0)

(拿高版本jdk編譯的java去低版本jre執行->當然不行, 因為沒有向上相容這件事)

你必須要加上兩個參數:-source和-target
-source: 要用java幾版, 來檢查程式內容, 是否合乎java文法
-target: 於前項檢查文法ok後, 編譯後產生的class檔將以何種java版本輸出

這裡要特別注意幾點:
a.-target的預設值 = -source的值
例如-source=1.4, 如果不加以設定-target
則此時-target=預設值=1.4
(但-source=1.2或1.3時, -target的值都等於1.4)

b.-target的值必須大於等於-source的值
比如-source=1.4
則-target可以等於1.5
若-target=1.3
執行javac後將會得到以下結果
javac: source release 1.4 requires target release 1.4

為-target做個實驗
用jdk 1.6寫一個簡單的java
執行:javac test.java
再拿到jre 1.4上去執行
結果是:
Exception in thread "main" java.lang.UnsupportedClassVersionError: test (Unsuppo
rted major.minor version 50.0)
若執行的是:javac test.java -target 1.5
再拿到jre 1.4上去執行
結果是:
Exception in thread "main" java.lang.UnsupportedClassVersionError: test (Unsuppo
rted major.minor version 49.0)
可以觀察到-target的值不同,
所產生出來的class檔的版本真的不一樣

這裡有個疑問
會有需要將-source和-target設定成不一樣的時候嗎
例如javac hello.java -source 1.4 -target  1.5

答案是, 需要視你要佈署的環境而定
舉個例子你本機是高版本的1.6
欲佈署在遠方的機器是低版本的1.5
然後你程式碼中有用到1.4才提供的功能
這個時候就相當適合使用:javac hello.java -source 1.4 -target  1.5

但記得前面我提過
高版本的jre能直接吃下低版本的class
所以, 結論是
你使用javac hello.java -source 1.4 -target  1.5最完美
但使用javac hello.java -source 1.4 -target  1.4也沒差, 是相同意思
可是使用javac hello.java -source 1.4 -target  1.3 <-錯誤!
因為-target的值必須大於等於-source的值

最後
提醒大家
雖然
高版本的jre能直接吃下低版本的class
但是程式總有需要修改的時候
所以在修改以前的程式後
有必要重新編譯時
必須要注要你所使用的 -source值

請看下面兩張圖, 分別是j2se1.4和j2se 5的api
其中String這個類別的api
圖一 j2se1.4的String API
圖二 j2se1.5的String API

可以注意到從1.4跨到1.5之後
本來在1.4中的方法compareTo(Object o)
已經消失了....也就是1.5把這個方法取消

可以寫個簡單類別來測試:
public class test{
 public static void main(String[] args){
  String a = "p";
  Object b = new String("p");
  if(a.compareTo(b)==0){
   System.out.println("They are equal!");
  }
 }
}

執行指令如下,
可以看到用-source 1.4編譯沒有錯誤
若用-source 1.5就會說你應該參數用String而不是Object
參照圖二, 就可以知道這是因為, j2se 1.5中已刪除 compareTo(Object o)的關係

C:\jpractice>javac test.java -source 1.4
C:\jpractice>javac test.java -source 1.5
test.java:5: compareTo(java.lang.String) in java.lang.String cannot be applied t
o (java.lang.Object)
                if(a.compareTo(b)==0){
                    ^
1 error
C:\jpractice>

編譯的時候
要注意使用哪個版本的java來檢查程式文法
但是只要一編譯好
以上例而言
以javac test.java -source 1.4編譯完成
拿到jre 1.6去執行時
雖然test.java裡使用了1.4版才有的String.compareTo()功能
但是因為高版本的jre能直接吃下低版本的class
所以能執行執行沒有問題
只不過編譯時要比較麻煩
加個-source參數
當然你應該不會想替專案裡的少數幾支java特別加上-source參數
專案裡所有的程式應該都是以同樣版本的java去編譯的
這樣才好維護
所以有發現有使用到已被高版本取消的方法時
還是趁早修改比較理想

2011年7月5日 星期二

jquery選擇器的問題

選擇html畫面上的dom物件進行操作
以往都是要用getElementById(), getElementsByName()等來操作
但有了jquery之後
使用他的選擇器
就可以方便地選取畫面上的元件了

選擇器長這樣: $()
一個錢字號, 後面帶一個小括號
詳細用法可以參考這裡

今天碰上一個jquery選擇器的問題
$('input[name=test]:checked').each(function() {//處理的程式碼});
上面這個意思是說
選取所有input標籤, 其name屬性為test, 且被選取(checked)的元件.
然後逐一將這些元件, 交付function(){//處理的程式碼}去處理

乍看之下沒問題
問題是我程式裡本來是這樣寫的
$('input[name=test][checked]).each(function() {//處理的程式碼});
他用[], 而不是:
妙的是, 經過測試, 
這樣的句子在IE8較低版本(我同事的電腦, IE8版本< 8.0.7601.17514, 確切版本數記不住)可以選到東西
但在較高版本(我的電腦, IE8版本8.0.7601.17514)卻連個鬼都選不到

WHY?

本來我對jquery的處理器雖有概念
但對語法並不熟悉
看了這一頁後,
恍然大悟可能是出在[checked]的關係
應該改為:checked才對
修改後果真可以在IE8版本8.0.7601.17514運行

結論:
要選擇被選取的元件
要用冒號:checked
而不是中括弧[checked]
但無法解是為何在較低版本的IE8,
中括弧[checked]也可以運行??

關於:checked的用法
亦可參考這裡



eclipse無法建置?

今天替專案加了旗標flag
為了觀察程式執行的流程與參數值

加了旗標就是改了程式
所以要重新編譯
疑?
為什麼選擇專案->建置專案
看起來是順利完成
可是跑去專案的classes資料夾一看
都還是舊的東西

一氣之下選擇專案->清除
打算乾脆全部都重新建置算了
沒想到連一個class都沒編譯出來
情況更糟.....

我後來知道原因了!
那是因為該專案的建置路徑裡
我本來有加一些外部jar
可是這些外部jar後來被我移除所以專案就無法參考到
而會一直出現紅色驚嘆號



 (
為什麼我知道紅色驚嘆號的意義?
答:從eclipse documentation中查到的, 如下




)


將這些已經移除的外部jar
從建置路徑中移除
則紅色驚嘆號就會消失
再選擇一次專案->建置專案
已經可以的classes資料夾看到編譯後的.class檔了

總結:
eclipse中, 只要專案建置路徑有一個錯誤, 就無法再建置任何東西!

20110728補充:

今天幫同事測專案時
專案裡面會用到spring+hibernate
然後hibernate所需連線
會寫在一個設定檔裡面

專案啟動時
spring會根據此設定檔內容
去讀取db相關設定
然後試著去new出一個org.springframework.jdbc.datasource.DriverManagerDataSource
但是此設定檔帳號密碼設定錯誤
所以拋出Exception
然後此專案就"起不來"
AP Server(在此例中是Tomcat)會跳過此一專案
繼續啟動其他專案...

所以
除了建置路徑中有不存在的jar, 會導致專案啟動失敗外
如果建置中有任何Exception,
或是任何錯誤
都會導致專案怎樣都無法啟動

eclipse裡icon的意義

eclipse是一個好用IDE的工具
可以拿來開發JAVA, C++, PHP等

IDE工具就是視覺化的工具
但是上面有很多ICON,
不知道是什麼意思.....??
看看這份eclipse documentation

2011年6月30日 星期四

辨識SQL SERVER版本

我不清楚連的SQL Server版本
所以我在SSMS上
選擇連線的Server
按右鍵選擇屬性
出現了下圖的伺服器屬性畫面










上圖看到版本的屬性
其值是9.00.4035.00
阿咧~這是三小朋友
本來預期會看到SQL Server 2005 SP3這樣的東西
結果看到這一串數字
反而覺得更疑惑??????

搜尋到微軟的這一篇文章
哈哈~所有問題都解決啦!!

以INSERT INTO方式匯出資料

看同事寄的文稿裡面
有一個.sql檔案
裡面以INSERT INTO TABLE VALUES
的方式把TABLE備分起來
這引起了我的興趣
因為據我所知
SQL SERVER 2008 Management Studio並沒有這樣功能
他頂多只能匯出該TABLE的SCHEMA, 如下圖














然後目前我知道最新版的SQL SERVER是2008 R2
據說是2010.04開始開放下載Express版本
SQL SERVER 2005, SQL SERVER 2008, SQL SERVER 2008 R2 都有Express版本
然後Express版本還可以分為 Express with Tools 與 Express Advanced Services版本
所謂Express(快捷版)就是不用錢
with Tools就是把SSMS(SQL Server Management Studio)也包在裡面
Advanced Services又比with Tools包含一些報告的功能??
據我所知2008和2008 R2才有出with Tools版本

Express版本讓一般程式學習使用者
或者想先試試產品功能的人
能夠免費取得並試用產品
其內容跟正式版大致一樣
不過功能少了一些
對於機器的支援也較有限制
比如支援CPU有幾顆
記憶體多大等....
唉呀參考一下維基百科吧!

題外話扯多了
今天要講DB備份的方式
對於SQL Server而言
以前都是用SQL Server匯入和匯出精靈
來幫我從.txt檔(以適當的delimiter(定義符號)分開欄位, 如逗號或空白字元)
匯入資料到TABLE
或從TABLE匯出資料到.txt檔
所以看到這樣用INSERT語法完成的備份檔
覺得很新奇也很好用

搜尋了一下
主要有三種方式可以達成以INSERT句子
完成備份資料表的資料

1.Toad for SQL Server
2.一個外國人寫好的神奇SP(預存程序)
3.一個小小的軟體SQL Server Dumper 參考點2

我是利用SQL Server Dumper做的
該軟體所佔空間很小
畫面又相當直覺
算是相當好上手的軟體!!

2011年6月29日 星期三

INSERT多筆資料

INSERT INTO SAMPLE_TABLE
VALUES('AMY','TAIPEI'),('JOHN','NEW YORK')

上面的語法可以新增多筆資料
之前公司用IBM DB2可以執行無誤
可是在SQL SERVER 2005上始終都無法執行
查了資料1資料2
原來要一直到SQL SERVER 2008才有支援......

圖 MSDN文件庫中, SQL SERVER 2005與2008的INSERT語法差異

所以
如果無法用最上面的語法
新增多筆資料
那麼你有兩種選擇:
1.用INSERT新增一筆, 然後好幾次
2.用INSERT INTO SELECT FROM UNION SELECT FROM UNION....方法
詳情請參考這裡

Oracle SQL Loader

有個需求要把Excel裡的東西
匯到Oracle裡面的資料表

以前在操作IBM DB2時
要先把.xls轉換成.csv或.txt
然後下import指令
詳細內容忘記了
大概是: import from 'unit_contrast.txt' of del replace into UNIT_CONTRAST
這樣一行就可以搞定

可是換到Oracle
變得稍為複雜的一些
必須將命令寫近文稿裡
然後執行此文稿

unit_contrast.ctl :
load data
infile "unit_contrast.txt"
badfile "bad.log"
discardfile "discard.log"
into table unit_contrast
fields terminated by ',' optionally enclosed by '"'
trailing nullcols
( unit_id ,
unit_name
)

然後用TOAD的SQL Loader Wizard選擇此控制檔
或者在命令列底下執行:
sqlldr 帳號/密碼 control=unit_contrast.ctl

參考網站:
網站1
網站2
網站3

2011年6月28日 星期二

java的數字

一.
System.out.println(1-0.8);

上一句的輸出是:

0.19999999999999996

前公司業務跟錢有關
所以在處理小數有關的東西
一律都是用BigDecimal類別

System.out.println((new BigDecimal("1").subtract(new BigDecimal("0.8"))));

上一句的輸出是:

0.2

二.
System.out.println(365*(1+1000000000000000));

上一句的輸出是:

integer number too large: 1000000000000000

要解決這個問題很簡單
只要加個L就解決了
System.out.println(365*(1+1000000000000000L));

這其中的奧妙
就在於JAVA
作四則運算時
會把運算子旁邊的兩個運算元
都提升到較大運算元的型別後
再開始計算
這個叫作Promotion
(
註:Promotion指由小型別換到大型別
這會自動發生
Cast則指由大型別換到小型別
這就要由程式員特別指定


還有
JAVA基本型別的大小
可以參這篇文章
byte<short<int<long<float<double
浮點數型別的double和float都比整數型別的long還要大
這是因為這float和double
主要用來儲存小數數值,也可以用來儲存範圍更大的整數 
)

以本例而言
1+1000000000000000L
在JAVA中所有整數都預設為int
而所有小數都預設為double
但是加了個L
就把該整數提升為long型別

所以
1000000000000000先變成了long
->1+1000000000000000L = int + long = long + long = long
接著365*long = int * long = long * long = long = 365000000000000365
轉成long型別後就能裝下 365000000000000365 這麼大的數字了

2011年6月27日 星期一

2011年6月23日 星期四

心得:測試時, 還是選同樣的Web Container測試吧

有中文亂碼問題
在Tomcat上測試可以的程式碼
佈署到WebSphere就是不行....

為什麼不行?
答:我也不知道...

可能原因很多
跟web container如何實作有關
或者跟server所用的作業系統也有關...

目的是要能在最終機台上正常顯示
所以要測試時
請盡可能找和最終機台環境最相似的測試環境
進行測試
才能確保測試結果萬無一失!

sql server 2005 management studio express沒有匯出匯入精靈

sql server 2005 management studio express沒有匯出匯入精靈
sql server 2008 management studio express才有
如下圖
在資料庫按右鍵->工作->匯入資料/匯出資料


java io的flush

舉凡使用java做io時
必須要使用flush()
才能將資料輸出到輸出裝置
輸出裝置可能是: 螢幕或檔案等...

以下這個範例
FileWriter要寫出一個String
但是十秒後才會flush
所以執行時
你會看到先建立sample.txt
但是打開一看
裡面空無一物
過了十秒後
再次打開sample.txt
會發現裡面多了一行Today is a good day

import java.io.*;
import java.util.*;

public class Test_IO{

 public static void main(String args[]){
  try{
   String content= "Today is a good day.";
   FileWriter fo = new FileWriter("sample.txt");     
   fo.write(content);

   long curr = System.currentTimeMillis();
   while(true){
   long result = System.currentTimeMillis()-curr;
    if(result/10000 == 1){
     //10秒後flush
     fo.flush();
     System.out.println("Flushed!");    
     break;
    }
   }
   fo.close();  
  }catch(Exception e){
   e.printStackTrace();
  }
 }//end main
}//end class


你或許會問
常常用的System.out.println()
也是個io輸出
為什麼不用打System.out.flush()
就可以直接看到結果

這是因為有些io類可以設定auto flush(自動)
System的out是個PrintStrem物件
在api說明中有寫道:

Optionally, a PrintStream can be created so as to flush automatically; this means that the flush method is automatically invoked after a byte array is written, one of the println methods is invoked, or a newline character or byte ('\n') is written.

所以上完廁所
如果沒有自動沖水裝置
別忘了要自己手動沖水(flush!)

2011年6月22日 星期三

測試時的怪事

利用ECLIPSE當IDE
TOMCAT當WEB CONTAINER

要在本機測試一個JSP網頁是否正常
用FIRE FOX去連
怎樣就是會出錯
而且我有再該JSP裡插旗子
照理說旗子應該會顯示
可就是沒有

然後改用IE去連
好一點會出現旗子了
可是還是無法正常登入

然後我沒有做任何事
再用IE連一次
就正常
接著用FIRE FOX連
也是正常

WHY?
我什麼事都沒做
就自己好了??
這樣的例子我遇過四, 五次了
明明看起來就對
可是出來結果就不是這樣
最後一樣沒做任何事
他就自己好了....

怪事
我想這應該是
在ECLIPSE裡
去建立一個WEB CONTAINER執行環境
才會碰到的問題

2011年6月21日 星期二

base64

什麼是base64 <-我一直很疑惑
今天上網查了一下
有以下幾點

1.是一種編碼方式. 將輸入的字串或位元, 以3個bytes換成4個6bits方式編碼.
編譯成純文字的碼. 會叫base64, 是因為編碼結果只會有a-z, A-Z, 0-9外加兩個字元.
編譯出的每一個代碼, 只會在這64個字元裡面,  故名base64.(以上是我猜的...)
編碼詳情可以上google或維基百科查詢.
例如:I am a good man.
以base64編碼方式加以編碼後的結果:SSBhbSBhIGdvb2QgbWFuLg==
2.因為是一種編碼方式, 所以多少有加密的功能. 可是這種加密不安全, 只能防君子. 因為不是很安全地加密, 所以編碼速度很快.
3.為什麼會有base64的出生?..........是因為有些網路傳輸協定, 只允許以ASCII當做內文, 來傳遞資料. 如果你有個檔案, 比如說美女照片, 想要用電子郵件寄給別人, 那就是走SMTP協定, 此協定只能用ASCII來傳遞, 所以必須先將該照片的位元組, 例如010101010100101010101....編碼成純文字, 變成:AAaGBdGHE130.....這是舉例. 才能用SMTP傳出去.
4.網路上有提供base64編碼與解碼的網站
5.那麼HTTP也是純文字傳遞嗎? 我以前都認為是, 可後來看到這篇文章, 才知道原來HTTP也可直接傳位元組哩~所以在http上傳檔, 不一定非得先將二進位檔進行base64編碼才行. 但如果情況是, 你利用http傳給別人一份xml文件, 且想要在該份xml文件中, "夾帶"檔案, 就非得先將檔案以base64編碼後, 再將編碼後的結果, 貼到xml文件裡. 比如以下xml文件:
<傳送資料>
    <檔案內容>
    PGgxPrS/pHCzvaxPpGqr0630sNUhPC9oMT4=
    </檔案內容>
</傳送資料>

6.經過base64編碼後, 輸出的東西會比輸入的東西大上35%, 約莫三分之一左右. 這也是為什麼, 你要記東西給別人, 上傳6MB但上傳完卻顯示為8MB. 會稍微大一點.

總結:base64是一種編碼方式, 可以將二進位或文字資料, 轉變成文字的資料.(你或許會疑惑, 將文字資料轉成文字資料? 沒有錯, 看看維基百科的例子, Man編碼後, 會變成TWFu. 他本來就是文字, 本來就可以用SMTP等協定傳輸, 編碼後只是變成另一個文字. 答:可以做點不是很安全的加密功能囉, 例如這個網站舉例你要傳情書的話...起碼被情敵攔截會看不懂..). base64的編碼原理不複雜, 所以編碼速度快, 安全性低. base64的誕生是為了在純文字協定(如SMTP)下, 仍能傳輸檔案(如一個美女照片, 就說是Hebe好了, 如何?)

在html中顯示xml

最近有個需求
需要在html中顯示xml的標籤
例如<element></element>

可是瀏覽器會自動把.html裡面
所有<>都解釋為標籤
然後會因為看不懂該標籤函意
而什麼都不顯示

有幾種方法
1.跳脫字元:將<換成&lt, >換成&gt.
範例:按右鍵看看本頁面的原始檔, 就是利用跳脫字元顯示<.
2.用innerText屬性.
例如:
<body>
<span id="abc">
</span>
</body>
<script>
var abc = document.getElementById("abc");
abc.innerText="<element>Hello!</element>";
</script>
innerText屬性值將不會被看瀏覽器解譯

(另一個innerHTML就會被瀏覽器解譯)
3.表單的文字輸入方框<textarea></textarea>之中的文字, 也不會被瀏覽器解譯.

2011年6月13日 星期一

js的onSumbit事件

我很少用到onSumbit事件
一般來說, 表單按下送出按鈕後
會引發onClick事件,
然後把事情都在這處理完

如果說有需要用到onSumbit事件
那事件發生順序如何呢?
用以下jsp測試:

<html>
<body>
<%
if(request.getParameter("name")!=null && !request.getParameter("name").equals("")){
%>
<script>
alert("The form has been submitted!");
</script>
<%
}
%>
<script>
function doIt(){
 alert("Sumbit!");
}
</script>
<form method="post" onSubmit="doIt()">
<input type="submit" onClick="alert('Click!')" value="Test">
<input type="hidden" value="abc" name="name">
</form>
</body>
</html>


結果如下:
Click!
Sumbit!
The form has been submitted!

2011年6月10日 星期五

Tomcat中欲更動webapps目錄底下的war檔時, 請先停止Tomcat

Tomcat安裝目錄\webapps
是Web Application放置的地方
你可以放war檔(其實就是zip檔)在這,
Tomcat啟動時,
會自動解壓縮成一個資料夾,
此資料夾名稱, 就是war檔的檔名
或者
也可以直接在webapps底下放沒有壓縮的整個資料夾
兩種方式都可以在Tomcat安裝你的Web Application

當Tomcat啟動時
你可以更動Web Application資料夾底下的檔案
比如jsp,
結果會馬上反映出來
因為Web Container在使用者要求此一jsp時
會發現該檔已被更新過
從頭開始把jsp轉成servlet->編譯->載入->初始->開始服務
但是如果是web.xml等設定檔
你一定要重啟Tomcat才會有動作
這點在Apache Tomcat的Document裡有提到

那如果是war檔呢
要更動war檔前
最好先停止Tomcat
看看這篇

2011年6月9日 星期四

eclipse: 一個case就一個工作區

今天想到
如果手上有兩個以上的case在做
最好一個case就一個工作區
(一個case底下可能會有一至多個web application)

將不同case都放在同一個工作區
除了會造成資料混亂外
還有就是啟動Tomcat時
會多載入其它不必要的web application
造成啟動速度緩慢...

2011年6月8日 星期三

java的Package觀念

以前讀過某本java教科書上說
package觀念對於初學者而言不容易懂
今天想試試看以下例子:

有兩個class, Flight和Boeing:

package Test123;
public class Flight{
 public static void main(String[] args){
  Boeing b = new Boeing();
 }
}


package Test123;
class Boeing{
}


這兩個class都位於Test123這個package底下.
目錄結構如下:
c:\jpractice\Test123\
以下測試各種情況, 看如何能順利編譯:

a.在c:\jpractice\Test123\執行javac Flight.java
結果:失敗..
Flight.java:5: cannot find symbol
symbol  : class Boeing
location: class Test123.Flight
                Boeing b = new Boeing();
                ^
Flight.java:5: cannot find symbol
symbol  : class Boeing
location: class Test123.Flight
                Boeing b = new Boeing();
                               ^
2 errors

出現以上錯誤訊息
這是因為在class Flight中,
沒有特別指定要import任何其它package
所以預設就是跟Flight一樣的package->Test123!
但此時因為javac的執行起始點是在c:\jpractice\Test123\
所以javac會嘗試從當前目錄
再一次尋找Test123
但是這個目錄c:\jpractice\Test123\Test123並不存在
所以丟出找不到class Boeing的錯誤

b.在c:\jpractice 執行javac ./Test123/Flight.java
結果: 成功!
把javac的執行目錄往上提了一層
所以會從c:\jpracitce開始去尋找 Test123.Boeing
c:\jpractice\Test123\Boeing.java <-真的有這個檔

總結:
1.尋找class的方式, 預設從本支程式的package開始找, 再從import宣告處的package由上往下找. 所以如果需要用到的其它類別, 跟目前程式在同一package, 可以偷懶不加import.
2.預設的尋找起點, 是從javac的執行目錄開始.

Report problems as you type

eclipse這類IDE編輯器
好處在於你一邊打程式碼
一邊它就會幫你檢查對不對
這是超級方便的功能
讓你可以隨時做修正
下圖就是它的作用
類別System誤寫成system
不用編譯
IDE會自己抓出錯誤







要不然用一般的文字編輯器的話
可能你一股腦兒地寫了1000行的程式
你自信滿滿認為一定不會錯
最後很高興要用javac指令去編譯
結果卻令人沮喪地出現了一堆錯誤

這個"邊打邊檢查"的功能, 就叫它: Report problems as you type 吧!
在eclipse中預設為開啟
如果你想把它關掉
或者哪天發現怎麼不會自己檢查
請按照下面兩張圖
去把它關閉或開啟

















2011年6月6日 星期一

Oracle資料庫的ROW_ID欄位

Oracle資料庫
和Microsoft SQL Server資料庫
或IBM DB2資料庫
在資料表上多了一個預設的欄位
叫作ROWID

在TOAD for Oracle的產品中
預設是看不到這個欄位
必須要勾選開啟, 如下圖的紅框標示處所示

















據某本Oracle參考書上說,
這是為了方便管理資料
可是他沒有講實際方便管理的例子

ROWID長得像是這樣
AAA9soAAJAAABc4AAA
每新增一筆資料
就自動獲得一個惟一的ROWID

我在目前維護的程式中
看到有人是將ROWID當作刪除或更新的主鍵
這樣真的還滿方便
它的作法是查詢資料時一併查詢ROWID
然後將ROWID寫進HTML中
送出表單時只要送出ROWID
則Server端就知道要砍哪一筆資料

要不就必須送出該資料的全部主鍵
然後Server端再一個個加以設定
在單筆資料情況下還好, 就直接取表單的值
如果是多筆資料的情況
還多了 一個動作:
判別欲異動的資料是第幾筆
接著在表單參數的陣列中
取出該筆資料的值
例如:
String[] names = request.getParameterValues();
String name = names[欲異動資料的index];

而如果有了ROWID幫忙
在多筆資料情況下
也是只要送出ROWID即可解決問題

由以上例子可以看出
ROWID可以方便資料的存取

但是我會想打這篇文章
是因為有一次為了測試
我砍了Oracle資料庫中的一筆資料
然後同事說不能這樣做
因為它有ROWID
可能會影響到其它資料??

真的會嗎?

於是我去看目前維護的程式中
資料庫裡, 沒有人用ROWID當做外鍵
程式中, 也沒有人把ROWID的值寫死在程式裡
也沒有這樣的SQL句子: SELECT * FROM EXAMPLE_TABLE WHERE ROWID = ?

所以我砍了一筆資料
並不會害資料表的關聯性消失
也不會造成查不到資料的情況
可以安心刪除, 再新增回來
就好像什麼事都沒發生過一樣

總結:
1.ROWID可以方便資料表存取, 即當作UPDATE或DELETE句子的條件
2.ROWID不可以用來當做外鍵, 亦不可寫死在程式中. 因為你總不能期待資料永遠會在同個位置等你, 它可能會被刪除, 然後再新增.
3.ROWID還是可以當作SELECT句子的條件, 只要你是先用其它主鍵查過一遍, 想要再查一次比較詳細的資料時, 因為你懶不想打太多主鍵, 就可以用ROWID. 我以為這不是好的作法, 因為可能你在前一次查詢後, 資料表做了某些異動, 資料還是在, 可是ROWID卻換了一個. 接著第二次查詢就會失敗.

總結後的總結:
1.請把ROWID只拿來當作UPDATE或DELETE句子的條件.
2.不要將ROWID寫死在任何地方, 比如其他資料表, 或者程式裡面. ROWID應該永遠是取用來自SELECT查詢所得的結果.

2011年5月31日 星期二

TortoiseSVN的圖示

TortoiseSVN是一套結合在Windows作業系統
右鍵選單中的SVN Client軟體
它對於SVN版本控制的各種狀態有相對應的圖示(icons)

下圖是從說明手冊中截取的各圖示意義











這裡則是TortoiseSVN的說明手冊頁
共有18種語言版本可以選擇

版本控制

工作之前
程式的檔案就是放在一個資料夾
自己修修改改
有時發現這樣的思考架構不對
想要回到前前前一次的版本
只能靠文字編輯器的還原功能來達成

工作之後
一分程式每個人都可能會改到
所以你會想把程式移到大家都可以存取的地方
可能是一台與網路連接且獨立機器
然後大家連到那台機器上存取程式碼

接著你想到要回復程式版本
還要慢慢還原
真是太蠢的方法
如果那台獨立的機器
可以提供記錄版本的功能
以供我們隨時存取各版本
那就是太美妙了

所以版本控制的概念就由此而生
我自己以為他出生的原因
是因為以下兩個需求
1.程式放在大家都可以存取的地方
2.能夠記錄程式的版本, 以備還原或查閱需要

之前公司用Rational ClearCase
現在用Subversion(前身為CVS)
這兩套在操作上與指令意義上略有不同
例如
ClearCase:
執行"Update"下載檔案到本機,  以後要更新本機檔案也是執行"Update". 下載後, 檔案是上鎖住狀態, 且本機的檔案在下載後都是唯讀, 必須再執行"Check-Out"才能將該程式解鎖, 並且將本機檔案變成可讀寫狀態, 進行編寫. 編寫完檔案後, 再將檔案做"Check-In"將檔案上傳到版本控制的Server, 並且上鎖, 從而將本機檔案又恢復成唯讀. 版本控制的Server裡的檔案, 一開始時先上鎖, 且本機的複本檔案是唯讀. 使用者要編寫時, 再執行Check-Out, 可以同時做解鎖與恢復讀寫. 編寫完成後, 再執行Check-In. 同時做上鎖與恢復唯讀.
Subversion:
執行"Check-Out"下載檔案到本機, 以後要更新本機檔案變成執行"Update". 下載後, 檔案是未鎖住狀態, 且本機的檔案在下載後都是可讀寫狀態. 使用者可以直接編寫檔案. 編寫完檔案後, 再將檔案做"Update"將檔案上傳到版本控制的Server. 版本控制的Server裡的檔案從未上鎖, 而本機的複本檔案也從未變成唯讀.

個人認為ClearCase的運作模式較佳
因為一開始強制上鎖
待有修改需要才由個人去解鎖以"借出"做修改
可以確保同一時間, 只有將程式借走的人可以修改該程式
而Subversion沒有強制上鎖
可能會發生你改我也改同一版本的程式
造成後來上程式的人, 會把前一個人修改地方蓋掉的風險.

阿~沒想到題外話說了這麼多
其實我是想要說
最近電腦換成64位元,
很多本來在32位元作業系統上, 安裝與操作都很順利的應用程式,
卻變成坎坷難行....要一直去找他64位元的版本.

阿然後我在eclipse裡用的svn client是Subclipse(有另一個相似的叫Subversive)
在64位元電腦上一直使用失敗
出現"unable to load default svn client"的訊息
Google了一下
應該是出在Subclipse所使用的svn client有問題
推估也是不支援x64吧
這個解決方法是
1.安裝64位元的JavaHL
2.安裝SVNKit

我採用2.去解決
結果沒反應
改採1.去解決
去下載安裝Silk SVN
(我猜他底層也是用JavaHL, 且提供的是64位元版本)
然後把eclipse關掉重開
結果就成功不會有錯誤訊息啦~哈哈

我逛了一下Silk SVN網站
發現他是一家提供SVN Repository的廠商
免費的使用者可以有100MB的空間來放你的程式
如果想要1000MB, 就要付出一個月4.95歐元(約台幣205元)的代價
最大的是10000MB, 一個月足足要19.95歐元(約台幣825元)呢!!

2011年5月30日 星期一

EL裡面是否可以再使用JSP expression?

今天有個JSP如下:

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "
http://www.w3.org/TR/html4/loose.dtd">
<html>

<body>
<%
String a = "Apple";
%>
<c:out value="${'Apple'}"/>
<br/>
<c:out value="<%=a%>" />
<br/>
</body>
</html>


它的結果會是:
Apple
Apple

因此知道要在JSTL中表達literal
可以用
1.EL表示: ${'Apple'}
2.JSP expression元素: <%=a%>

那可不可以用EL+JSP expression咧?
像是這樣:
<c:out value="${<%=a%>}"/>
答案是:.
.
..
...
不行, 你會得到這樣的一個例外:
org.apache.jasper.JasperException: /A.jsp(13,0) "${<%=a%>}" contains invalid expression(s): javax.el.ELException: Error Parsing: ${<%=a%>}--
結論:
1.JSTL裡面的literal可以用JSP expression或EL來表示
2.EL中不要再使用JSP expression, 否則會出現錯誤.

2011年5月29日 星期日

Tomcat 7中設立目錄列表和錯誤處理頁面

如果你在瀏覽器輸入一個網址
例如http://localhost:8081/Apple/
你並沒有再指定任何特定的資源名稱
例如一個servelt url pattern
或真實檔名的jsp, html, jpg等
那這時web container會如何反應?

答案是會先找有無welcome-file-list
再找有無開放directory listings
如果以上兩者都沒有
瀏覽器會顯示HTTP Status 404

這兩個設定值
都可以在下列檔案進行設定:
Tomcat 7的安裝目錄/conf/web.xml
該檔定義了該Tomcat安裝版本底下
所有web應用程式共用的初始參數

1.welcome-file-list
在該檔中, 尋找下列標籤
    <welcome-file-list>
        <welcome-file>index.html</welcome-file>
        <welcome-file>index.htm</welcome-file>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>
這是預設的歡迎頁面
只要在各應用程式的根目錄中
有這些檔案
則在沒有特別指定資源名稱的情況下
就會導到這些指定的歡迎頁面

如果, 你又在應用程式自己的WEB-INF/web.xml中
再次設定了welcome-file-list
則就會置換掉Tomcat 7的安裝目錄/conf/web.xml
裡面指定的welcome-file-list版本

2.directory listing
在該檔中
尋找下列標籤
    <servlet>
        <servlet-name>default</servlet-name>
        <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
        <init-param>
            <param-name>debug</param-name>
            <param-value>0</param-value>
        </init-param>
        <init-param>
            <param-name>listings</param-name>
            <param-value>false</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
這是一隻"預設"(名稱是default ^_^)的servlet
可以讓web container列出目錄下的所有檔案
如下圖所示















不過, 不建議這樣做
原因如下:
1.會浪費server資源去產生這份list
2.應用程式中可能有些機敏資料, 你不想被看光光, 並被直接存取.

--
如果瀏覽器指定了url卻沒有指定資源名稱
並且沒有設定welcome-file-list
也沒有開放directory listing
那就只能義無反顧地顯示HTTP Status 404了

上圖為Tomcat的預設404畫面
其實我們可以加以客製化
透露出更多的訊息

只要在應用程式的WEB-INF/web.xml中
加入以下標籤
<error-page>
<error-code>404</error-code>
<location>/NotFound.html</location>
</error-page>
就可以指定發生HTTP 404時
web container要回傳的頁面
可以是html也可以是jsp
上例中/NotFound.html是說
請在該應用程式的根目錄底下
尋找NotFound.html這檔案
根據網路上的資料
斜線 / 不可缺少

網路上搜尋到這個網站
裡面就有一些有趣的客製化HTTP 404網頁
還教你如何製作出一個好的HTTP 404頁面
並且還引當你遇到404頁面時
應該如何做, 才能找到你想要的東西
很值得一看哦!!







2011年5月27日 星期五

在win7 x64上使用VPN

自從公司電腦從win7 x86換成了win7 x64後
本來在使用的 cisco vpn client 就無法安裝
雖然聽說64位元的作業系統, 依然可以安裝32位元的應用程式
例如win7 x64版本裡, 在系統碟除了原本的Program Files資料夾外
還多了一個Program Files (x86)資料夾

所以看來應該是只有部分的32位元應用程式
可以在x64的機器上跑

對了, 這裡說的 x86 = 32位元
而 x64 = 64位元
x86或x64應該都是指Intel的CPU型號
(其中x64亦可稱為x86-64)

於是我直接去CISCO的網站上下載
發現真的有for win7 x64的版本ㄝ
超高興
可是他下面有說, 必須是付費的使用者
才可以下載
冏!!

後來找到這篇文章
對岸有人找到檔案下載的連結
我下載測試後
真的可以在win7 x64上運作無誤
文章中也提到cisco網站不提供給我們這些草民下載
唉~有錢的是老大咩~

或者你因此看不起cisco的財大勢大
也可以用其他的vpn client端軟體
來嘗試連接到原本使用cisco vpn client連線的網路
我沒有試過
據說也可以連線成功
不過好像要從本來的cisco vpn client去匯入一些檔之類的
像是這篇文章中提到的Shrew Soft 的 VPN Client ,  NCP Secure Entry Client
還有其他人提到的OpenVPN

2011年5月25日 星期三

用java.net.URL建立連線注意事項

java.net.URL是java內建的類別
能幫助程式去取得網路上的資源
以http封包發送request封包給站台
再從站台收到response

今天在測試時
發現你使用此類別建立連線
URL的openConnection()會回傳一個URLConnection物件
該物件一直都不會送出request封包
直到你呼叫他的getHeaderField()或getInputStream()等getter方法
才會送出request封包

我嚐試如果都不用getter方法
用connect()方法也是不行
可能是因為該方法是抽象的abstract
然後URL的openConnection()方法所回傳的URLConnection實作物件
(呼叫該物件的.getClass().getName方法, 得知是個HttpURLConnection類別的物件)
又沒有覆寫該方法所致

所以我剛去看了一下JAVA API
發現URLConnection本身是個abstract class
abstract class的意思是有些方法可以沒有身體
(interface的話就全部都不能有身體)
而繼承他的HttpURLConnection也是個abstract class
並且真的沒有加以定義connect()

所以要是你想要用java.net.URL
讓你的程式和網路上的資源取得連線
呼叫connect()方法是沒用的, 他目前還是個空殼
(或許以後版本的java會為他填一些內容)
記得要呼叫URLConnection類別的getter方法
這樣才會真的把request封包送出去!!

2011年5月23日 星期一

以HTTP下載WORD文件會卡住

近來碰到一個怪狀況
有個WORD文件放在HTTP伺服器上
我連結到那邊去
比如說 HTTP://站台1號/A.DOC
就會下載A.DOC

瀏覽器提示訊息
問我要存在哪裡
選好地方後按確定
可是大概1MB大小的WORD文件
下載進度是卡住狀態
如果是IE
你看它下載進度列
一直都是0
大概要五分鐘後
才瞬間下載完成

有趣的是,
如果我把該檔案
放到HTTP://站台2號/A.DOC
站台1和2號是不同台的機器
則A.DOC馬上就可以下載完成

不論是站台1號或2號
下載的檔案都是同一份
也可以順利正常地開啟編輯
差別在1號站台會先卡住一段時間才能下載

上網搜索有無案例
可惜無所獲
解決之道:
我將此WORD文件內容全選並複製
新增一個空白的WORD文件
把複製的內容貼上
再存檔, 檔名也一樣
然後位置存在其它本機的目錄下

發現存檔完成後的檔案大小
竟然比原始檔案要小上49KB
但是兩者內容完全一樣
我還印出來比對 沒有缺少什麼文字或圖檔

但是它就是小了一些,
看來是有一些肉眼無法看建的物件在搗亂呀~
將此新檔再上傳到站台1號
原先下載會卡住的狀況
就從此消失了

結論:
會發生下載檔案時
卡住很久才可始的狀況
跟檔案的建立的方式有關
可能當初建立時, 產生了些異常物件
這些物件並不影響WORD文件內容
卻會與某些站台的軟硬體架構相沖
造成下載時卡住
或者產生: HTTP Error 502 Bad gateway

解決方式
就是全選->複製
將文件內容轉貼到一個新的檔案
以消除此一不明物件

2011年5月19日 星期四

從資料庫一次取太多筆會造成AP SERVER記憶體空間不夠

記得以前在金融公司資訊部上班時
金融業都很講求效率
比如在資料庫下SQL, 不能執行太久,
否則DB的效能都被你吃完, 別人就吃得少或吃不到了
所以每個星期會公布SQL COST前五名的SQL
以茲獎....哦不, 是以茲改進
改進的方式是改變SQL的本身
通常都是條件下得不夠漂亮
或者真的資料量爆大
必須要增加INDEX
或者是根本沒有條件
造成他一次取回資料表的全部資料
這也是今天的主題

如果一次取回的資料太多筆
則不但DB會效能低落
連AP SERVER也是
那時如果一次取十萬筆資料回來
AP SERVER會發出OUT OF MEMORY的錯誤訊息
因為你取資料回來時
是以RESULTSET的型式放在AP SERVER上
取回的東西多, RESULTSET就越大到記憶體空間不足

在DB層面也是
操作DBMS時, 比如TOAD
對一個有龐大資料的資料表
如果直接下SQL不加任何條件
那它顯示查詢結果畫面的時間
就會處理得很久
你可以想像從一家滿滿的麵包店拿十個麵包
跟掃光全店的所有麵包
哪個時間會花得比較久?

所以我們知道不能"一次"取"太多筆"資料回來
否則會造成AP SERVER和DB這兩層TIER
處理速度變慢且記憶體不夠用

但是有時真的有這個需求, 怎辦
我就是有取大量資料的需求
這時可以透過JDBC裡定義的executeBatch()
它先將所有要執行的語句用addBatch()加入容器中
最後executeBatch()時就一次送出全部的句子

之前上課聽老師說
有人執行大量的資料庫異動
用傳統的execute()花了一個星期還沒好
使用了executeBatch(), 十個小時就好了

但是這個executeBatch()可以拿來做批次異動
卻好像不適用於select語法??
之前公司有個套件
你可以設定每次要取回的資料筆數
它會自動當你分成一批一批地取回
也避免了一次取大量資料的問題
只是不知道JDBC有無對應的現成方法?

2011年5月18日 星期三

web Application的session中斷

因為http協定是stateless
stateless的意思指它不記得狀態
因使你在逛下一頁時
它沒有辦法知道你上一頁在幹嘛

因此
我們需要session機制來輔助
它的作用原理是client(一般情況下, 指的是瀏覽器)
向server(指web container, 如tomcat)
發送請求封包後
web container端便會檢查該封包是否有cookie資訊
再檢查裡面是否帶有JSESSIONID這樣的參數
如果有
則取回原session
沒有的話
web container會給null或新的session
這要視你程式寫法而定
servlet可以選擇要null或新的session
但是jsp一定是新的session

建立了session之後
使用者資訊都被存在裡面
直到session中斷

session中斷有兩個方式:
1.使用者關掉瀏覽器, 使得client端"忘了"它的JSESSIONID.
2.server端web container的session timeout. 以tomcat為例, 預設是30分鐘.
但是各專案可以自己設定, 在web.xml中加入以下標籤
<session-config>
<session-timeout>10</session-timeout>
</session-config>
就會將時間設為10"分鐘"
亦可以每個專案底下的session都設定不同timeout時間
setMaxInactiveInterval(int interval)
(注意這裡interval的時間單位是"秒", 和web.xml裡設定的"分鐘"不一樣!)

還記得小時後去超市
都要在櫃台寄放包包
它會給你一個號碼牌
購物完出來再憑此號碼排拿包

可以用這個拿包來比喻session中斷情況:

:包包(session)依然在櫃台(指server), 但client端沒有了號碼牌, 所以無法提取, 等於沒有包包.
分析: 這樣的狀況會在server端留下無用的seesion資料, 因為再也沒辦法被存取到.
(除非有心人士去改了他本機cookie裡面的JSESSIONID資訊.)
因為沒辦法被存取到, 等於留了很多垃圾, 很佔記憶體空間. 有時你會在櫃台看到上次你來就有的包擺在那, 佔了一個儲存格空間.
:client端依然有號碼牌, 但是購物逛太久, 超過預設保管時間30分鐘沒來拿, 所以櫃台自動把包包銷毀.......
分析:server端不會留垃圾下來, 還可以接受.

:client端沒有號碼牌, 櫃台也已銷毀包包
分析:很好大家都沒遺憾了~

一般認為只要瀏覽器關掉
session就結束
其實只是JSESSIONID不見了
但是session資料仍然留在server端佔空間

為了替server著想
建議大家下次逛網站時
如果該網站有登入機制
記得好心一點按登出
這樣可以幫網站減少一點負擔哦!

Toad for Oracle的Import Utility Wizard, 有個畫面寫錯啦~

以前公司的資料庫是用IBM DB2
那時我們裝的DBMS就是Toad
然後現在使用是Oracle
再去逛Toad發現原來Toad有為各DB推出對應的DBMS
Toad在網路上搜尋一下
名聲還滿高的
所以這次就使用了Toad for Oracle

我們知道SQL語法各家DB廠商都略有不同
所以如果你用ORM框架
例如知名的Hibernate, 它會自動幫你將操作物件的動作
轉成各DB適用的SQL
所以這大概也是這類ORM框架受歡迎的原因之一
不過這是題外話

這次工作上有需要將遠端A資料庫下甲使用者所有TABLE的資料
備份到本機B資料庫
所以研究了一下Oracle的匯出匯入指令
在電腦有安裝Oracle DB的情況下
像我是安裝Oracle Database 10g Express Edition Release 10.2.0.1.0
就可以在命令列輸入exp或imp
然後它自動會引導你完成後續動作
滿方便的
像是命令列精靈一樣

接著再研究到Toad for Oracle
嗯嗯~它也有匯出匯入功能
而且是視覺化精靈
一步一步引導你完成步驟
比命令列好用許多

我執行備份的步驟
1.在Toad for Oracle
先選擇A資料庫的連線
工具列->Database->Export->Export Utility Wizard,
然後選擇匯出TABLE
照著精靈指示操作後
最後會得到*.DMP檔案
(我猜DMP的全名是 DATA DUMP)
2.再選擇B資料庫的連線
工具列->Database->Import->Import Utility Wizard,
一樣選擇匯入TABLE
(其實它的選項還有匯入User, 匯入Tablespace等.
不過既然當初匯出Table, 這裡當然就是選匯入Table啦!)
然後選擇要匯入的檔案, 接著就開始執行
--由於我的B資料庫原本空無一物
所以匯入時, 會順便建立 TABLE
以及TABLE的資料
(如果欲匯入的TABLE已存在於B資料庫了,
會發生什麼事?
答:還沒研究到那....
20110610更新:資料會附加在既有資料後面
如果有一模一樣的, 則該筆資料會匯入失敗
例如以下錯誤訊息:
. 正在將 TESTLA 的物件匯入 TESTLA 中
. . 正在匯入表格                       "TESTLA1"
IMP-00019: 資料列遭拒由於發生 ORACLE 錯誤 1
IMP-00003: ORACLE 錯誤 1 發生
ORA-00001: 違反必須為唯一的限制條件 (TESTLA.TESTLA1_PK)
資料欄 1 Steven
資料欄 2 Jay      

匯入了                                                             0 列
已順利終止匯入作業, 但含有警告.

後來google到有人說這種匯入方式是用sql的insert句子執行的
所以效率慢且無法選擇你要replace還是append等匯入模式

但oracle 10g後多了另外一種匯入匯出的功能: Data Pump
可以提升匯入匯出的速度
並且可以自行選擇要匯入的選項, 有
skip: 如已存在就跳過處理下一筆
append: 附加在現有資料後面
replace: 如已存在取代現有資料
truncate : 如已存在則砍掉現有資料再新增
參考來源: 這裡那裡

所以做個總結吧!
Import/Export Utility Wizard ->用傳統的insert語句達成, 速度較慢, 無法選擇匯入方式, 參數較少較簡單
Data Pump Import/Export Wizard ->用某種神秘的技術加速匯入匯出速度, 可以選擇四種匯入方式, 參數較多較複雜, 執行的使用者最好需具備DBA的權限, 因為過程中會建立資料夾之類的
)

今天的標題是:
Import Utility Wizard, 有個畫面寫錯啦~

就是在選擇匯入檔案時
它老兄給我出現下列這個圖















紅框處它竟然寫Export file name
害我覺得很疑惑
阿現在是說, 他會自動從A資料庫匯出一個檔
然後再自動將此檔匯入到B資料庫
所以現在是要我選擇匯出的檔案名稱嗎?
(功能這麼強大?)

可是當我看到另一個紅框處標示的"Open",
我就釋懷了
這的的確確是要我選擇Import file name.
所以畫面上的Export file name完全是筆誤

2011年5月15日 星期日

web.xml中的load-on-startup標籤

在寫WEB應用程式時
web.xml這個檔很重要
他記載了該應用程式所需要被使用到的資源

例如: Servelet, Filterk 和 Listener等
你光有程式還不行
必須還要再web.xml中加以登記
Web Container, 例如Apache Tomcat, IBM WebSphere, 在啟動時
才會找到該類別

這裡我只有講"找到", 但是並沒有講"載入"
是因為載入的時機有兩個
一個是Web Container啟動時
另一個就是該Servlet第一次被使用時
Web Container會自己選擇該怎樣載入
但無論如何
該Servlet的instance一定會在被使用前就準備好
(準備好後並不是會一直在那
例如空間不夠用時
Web Container可能會把一些已建立好的instance砍掉
但Web Container保證一定會在下一次該Servlet被使用前
先把它的instance準備好
)

於是如果今天想要強迫Web Container啟動時
1.就要載入特定的Servlet
2.並且指定載入的順序
那麼就需要<load-on-startup>標籤了

他的使用方式
是夾在<servlet>之間
例如:

<servlet>

<servlet-name>abc<servlet-name>

<servlet-class>my.abc</servlet-class>

<load-on-startup>1</load-on-startup>

</servlet>
 
至於<load-on-startup>的內容, 是一個整數. 可以正, 可以負, 也可以是0,
在網路上人家說J2EE Specilization 裡面有這一段
介紹這個標籤的用法
:(但是我找不到原文出處)
 
The load-on-startup element indicates that this servlet should be loaded (instantiated and have its init() called) on the startup of the web application. The optional contents of these element must be an integer indicating the order in which the servlet should be loaded. If the value is a negative integer, or the element is not present, the container is free to load the servlet whenever it chooses. If the value is a positive integer or 0, the container must load and initialize the servlet as the application is deployed. The container must guarantee that servlets marked with lower integers are loaded before servlets marked with higher integers. The container may choose the order of loading of servlets with the same load-on-start-up value.


上面這段內容說
1.如果<load-on-startup>的內容是0或正的整數, Web Container會依由小到大的順序, 來載入並初始話該Servlet. 於是載入順序就是: 0->1->2->3
2.如果<load-on-startup>的內容是負的整數, 或是沒有內容. 那Web Container就會自行選擇載入時機.

但是如果有兩個Servlet都是標示為2,
那順序是誰先誰後呢?

經過我的測試
是每次都不一樣.
因為我有兩個Servlet, 姑且稱為A和B
A是proxool連接池, 用來載入連接池設定檔的Servlet
然後B會利用 DriverManager.getConnection("proxool.example")來獲取資料庫連線
想當然爾
A必須要先載入->初始
然後B才能利用proxool.example這樣的別名
去取得連線,
否則會出現找不到對應的Driver訊息.

我試了幾次
有幾次B連線成功
有幾次連線失敗

後來把B的<load-on-startup>改為3
則無論試了N次都能連線成功

所以結論就是:
如果兩個Servlet的載入有相依關係
務必讓它們的<load-on-startup>值改為一前一後