亚洲国产一区在线观看 ,亚洲免费中文字幕,在线亚洲精品福利网址导航http://m.tkk7.com/dyerac/category/13363.htmldyerac 的天天天藍zh-cnSun, 19 Aug 2007 07:43:59 GMTSun, 19 Aug 2007 07:43:59 GMT60JFreeChart Study Resourceshttp://m.tkk7.com/dyerac/articles/137511.htmldyerac in java...dyerac in java...Fri, 17 Aug 2007 05:03:00 GMThttp://m.tkk7.com/dyerac/articles/137511.html閱讀全文

dyerac in java... 2007-08-17 13:03 發表評論
]]>
(zt)亂碼解決之道http://m.tkk7.com/dyerac/articles/136482.htmldyerac in java...dyerac in java...Mon, 13 Aug 2007 10:58:00 GMThttp://m.tkk7.com/dyerac/articles/136482.html為什么說亂碼是中國程序員無法避免的話題呢?這個首先要從編碼機制上說起,大家都是中文和英文的編碼格式不是一樣,解碼也是不一樣的!如果中國的程序員不會遇到亂碼,那么只有使用漢語編程。漢語編程是怎么回事我也不大清楚,應該是前年吧,我一朋友給我介紹漢語編程,怎么不錯不錯?當時因為學習忙沒去關注這個,等我閑了,那個朋友不弄這個,問他他也不說不大清楚,最后自己對這個學習也不了了之了。
    今天我寫這個不是講解中英文之間的差距,解碼等,我是將我在這幾年工作遇到各種各樣的亂碼的解決方法,總結一樣,也希望大家能把自己暈倒解決亂碼的方法都說出來,咱們弄一個解決亂碼的“葵花寶典”。

對于Java由于默認的編碼方式是 UNICODE,所以用中文也易出問題,常見的解決是
String s2 = new String(s1.getBytes(“ISO-8859-1”),”GBK”);


1、utf8解決JSP中文亂碼問題
一般說來在每個頁面的開始處,加入:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>

<%
 request.setCharacterEncoding("UTF-8");
%>

charset=UTF-8  的作用是指定JSP向客戶端輸出的編碼方式為“UTF-8”

pageEncoding="UTF-8"  為了讓JSP引擎能正確地解碼含有中文字符的JSP頁面,這在LINUX中很有效

 request.setCharacterEncoding("UTF-8"); 是對請求進行了中文編碼

有時,這樣仍不能解決問題,還需要這樣處理一下:

String msg = request.getParameter("message");
 String str=new String(msg.getBytes("ISO-8859-1"),"UTF-8");
 out.println(st);

2、Tomcat 5.5 中文亂碼

)只要把%TOMCAT安裝目錄%/   webapps\servlets-examples\WEB-INF\classes\filters\SetCharacterEncodingFilter.class文件拷到你的webapp目錄/filters下,如果沒有filters目錄,就創建一個。  
  2)在你的web.xml里加入如下幾行:   <filter>  
  <filter-name>Set   Character   Encoding</filter-name>  
  <filter-class>filters.SetCharacterEncodingFilter</filter-class>  
  <init-param>  
  <param-name>encoding</param-name>  
  <param-value>GBK</param-value>  
  </init-param>  
  </filter>  
      <filter-mapping>  
  <filter-name>Set   Character   Encoding</filter-name>  
  <url-pattern>/*</url-pattern>  
  </filter-mapping>  
   
   
   
  3)完成.  
  2   get方式的解決辦法  
  1)   打開tomcat的server.xml文件,找到區塊,加入如下一行:  
  URIEncoding=”GBK”  
  完整的應如下:  
  <Connector    
  port="80"   maxThreads="150"   minSpareThreads="25"   maxSpareThreads="75"  
  enableLookups="false"   redirectPort="8443"   acceptCount="100"  
  debug="0"   connectionTimeout="20000"    
  disableUploadTimeout="true"    
  URIEncoding="GBK"  
  />     
   
  2)重啟tomcat,一切OK。

3、xmlHttpRequest中文問題

頁面jsp用的GBK編碼


代碼
<%@ page contentType="text/html; charset=GBK"%> 


javascript部分

代碼
function addFracasReport() {  
    var url="controler?actionId=0_06_03_01&actionFlag=0010";  
    var urlmsg="&reportId="+fracasReport1.textReportId.value;  //故障報告表編號  
          
    var xmlHttp=Common.createXMLHttpRequest();  
    xmlHttp.onreadystatechange = Common.getReadyStateHandler(xmlHttp, eval("turnAnalyPage"));  
    xmlHttp.open("POST",url,true);  
    xmlHttp.setRequestHeader( " Content-Type " , " application/x-www-form-urlencoded);  
    xmlHttp.send(urlmsg);  
      


后臺java中獲得的reportId是亂碼,不知道該怎么轉,主要是不知道xmlHttp.send(urlmsg);以后是什么編碼?在后面用java來轉,試了幾種,都沒有成功,其中有:


代碼
public static String UTF_8ToGBK(String str) {  
        try {  
            return new String(str.getBytes("UTF-8"), "GBK");  
        } catch (Exception ex) {  
            return null;  
        }  
    }  
      
    public static String UTF8ToGBK(String str) {  
        try {  
            return new String(str.getBytes("UTF-16BE"), "GBK");  
        } catch (Exception ex) {  
            return null;  
        }  
    }  
      
    public static String GBK(String str) {  
        try {  
            return new String(str.getBytes("GBK"),"GBK");  
        } catch (Exception ex) {  
            return null;  
        }  
    }  
         public static String getStr(String str) {  
        try {  
            String temp_p = str;  
            String temp = new String(temp_p.getBytes("ISO8859_1"), "GBK");  
            temp = sqlStrchop(temp);  
            return temp;  
        } catch (Exception e) {  
            return null;  
        }  
    } 

4、JDBC ODBC Bridge的Bug及其解決方法

在編寫一數據庫管理程序時,發現JDBC-ODBC Bridge存在不易發現的Bug。在向數據表插入數據時,如果為英文字符,存儲內容完全正確,如果存入中文字符,部分數據庫只能存儲前七八個中文字符,其他內容被截去,導致存儲內容的不完整(有些數據庫不存在這個問題,如Sybase SQL Anywhere 5.0。JDBC-ODBC Bridge還存在無法建表的Bug)。

  對于廣大需要存儲中文信息的Java程序員來說,這可是一個不好的消息。要么改用其他語言編程,要么選擇其他價格昂貴的數據庫產品。“一次編寫,到處運行”的目標,也大打折扣。能不能采用變通的方法,將中文信息進行處理后再存儲來解決這個問題呢?答案是肯定的。

  解決問題的具體思路、方法
  Java采用Unicode碼編碼方式,中英文字符均采用16bit存儲。既然存儲英文信息是正確的,根據一定規則,將中文信息轉換成英文信息后存儲,自然不會出現截尾現象。讀取信息時再進行逆向操作,將英文信息還原成中文信息即可。由GB2312編碼規則可知,漢字一般為二個高位為1的ASCII碼,在轉換時將一個漢字的二個高位1去掉,還原時再將二個高位1加上。為了處理含有英文字符的中文字串,對英文字符則需要加上一個Byte 0標記。以下提供的兩個公用靜態方法,可加入任何一個類中使用。

  將中英文字串轉換成純英文字串
  public static String toTureAsciiStr(String str){

  StringBuffer sb = new StringBuffer();

  byte[] bt = str.getBytes();

  for(int i =0 ;i〈bt.length;i++){

  if(bt[i]〈0){

  //是漢字去高位1

  sb.append((char)(bt[i]&&0x7f));

   }else{//是英文字符 補0作記錄

  sb.append((char)0);

  sb.append((char)bt[i]);

   }

   }

  return sb.toString();

  }

  將經轉換的字串還原
  public static String unToTrueAsciiStr(String str){

   byte[] bt = str.getBytes();

   int i,l=0,length = bt.length,j=0;

   for(i = 0;i〈length;i++){

   if(bt[i] == 0){

   l++;

   }

   }

   byte []bt2 = new byte[length-l];

   for(i =0 ;i〈length;i++){

   if(bt[i] == 0){

   i++;

   bt2[j] = bt[i];

   }else{

   bt2[j] = (byte)(bt[i]|0x80);

   }

   j++;

   }

  String tt = new String(bt2);

  return tt;

  }

  上例在實際編程中效果很好,只是存儲的中文信息需要經過同樣處理,才能被其他系統使用。而且如果中文字串出現英文字符,實際上增加了額外的存儲空間。

5、Solaris下Servlet編程的中文問題及解決辦法
在使用Java開發Internet上的一個應用系統時,發現在Windows下調試完全正常的Servlet,上傳到Solaris 服務器上,運行卻出現故障——返回的網頁不能顯示中文,應為中文的信息全為亂碼;用中文信息做關鍵字,不能正確檢索數據庫。后來采用加入檢查代碼等方法探知故障原因如下:

  顯示亂碼主要是因為通過類 HttpServletResponse提供的方法setContentType 無法改變返回給客戶的數據的編碼方式,正確的編碼方式應為GB2312或者GBK,而事實上為缺省的ISO8859-1。無法檢索中文信息則是因為,客戶提交的中文信息經瀏覽器編碼到達服務器后,Servlet無法將其正確解碼。

  舉例說明顯示亂碼解決方法
  Servlet 一般通常做法如下:

  public class ZldTestServlet extends HttpServlet {

  public void doGet (HttpServletRequest request,HttpServletResponse response)throws ServletException, IOException{

  //在使用 Writer向瀏覽器返回數據前,設置 content-type header ,在這里設置相應的字符集gb2312

  response.setContentType("text/html;charset=gb2312");

  PrintWriter out = response.getWriter(); //*

  // 正式返回數據

  out.println("〈html〉〈head〉〈title〉Servlet test〈/title〉〈/head〉" );

  out.println("這是一個測試頁!");

  out.println("〈/body〉〈/html〉");

  out.close();

  }

   ...

  }

  解決頁面顯示亂碼問題,需將*處代碼換成如下內容:

  PrintWriter out = new PrintWriter(new OutputStreamWriter(response.getOutputStream(),"gb2312"));

  Solaris中文信息檢索問題的解決
  瀏覽器利用表單向服務器提交信息時,一般采用x-www-form-urlencoded 的MIME格式對數據進行編碼。如果使用get方法,參數名稱和參數值經編碼后附加在URL后,在Java中稱作查詢串(query string)。

  在Servlet程序中,如果采用ServletRequest的方法getParameter取得參數值,在Solaris環境下,對漢字卻不能正確解碼。因而無法正確檢索數據庫。

  在Java 1.2的包——java.net中提供了URLEncode和URLDecode類。類URLEncode提供了按x-www-form-urlencoded格式對給定串進行轉換的方法。類URLEncode則提供了逆方法。

6、Common Mail亂碼問題
common mail是一個小而方便的mail包,他實現了對Java Mail的封裝,使用起來十分的方便,但是我在使用他的時候發現,使用純文本的內容發送,結果是亂碼,代碼如下:
public class TestCommonMail {
public static void main(String[] args) throws EmailException, MessagingException {
SimpleEmail email = new SimpleEmail();
email.setCharset("GB2312");
email.setHostName("smtp.163.com");
email.setSubject("test");
email.addTo("test@163.com");
email.setFrom("test@163.com");
email.setMsg("我的測試");
email.setAuthentication("test", "test");
email.send();
}
}

分析了一下commons mail的源碼找到了原因。源碼如下:
public class SimpleEmail extends Email
{
public Email setMsg(String msg) throws EmailException, MessagingException
{
if (EmailUtils.isEmpty(msg))
{
throw new EmailException("Invalid message supplied");
}

setContent(msg, TEXT_PLAIN);
return this;
}
}

Email代碼片段
public void setContent(Object aObject, String aContentType)
{
this.content = aObject;
if (EmailUtils.isEmpty(aContentType))
{
this.contentType = null;
}
else
{
// set the content type
this.contentType = aContentType;

// set the charset if the input was properly formed
String strMarker = "; charset=";
int charsetPos = aContentType.toLowerCase().indexOf(strMarker);
if (charsetPos != -1)
{
// find the next space (after the marker)
charsetPos += strMarker.length();
int intCharsetEnd =
aContentType.toLowerCase().indexOf(" ", charsetPos);

if (intCharsetEnd != -1)
{
this.charset =
aContentType.substring(charsetPos, intCharsetEnd);
}
else
{
this.charset = aContentType.substring(charsetPos);
}
}
}
}

email.send();的send方法將調用
public void buildMimeMessage() throws EmailException
{
try
{
this.getMailSession();
this.message = new MimeMessage(this.session);

if (EmailUtils.isNotEmpty(this.subject))
{
if (EmailUtils.isNotEmpty(this.charset))
{
this.message.setSubject(this.subject, this.charset);
}
else
{
this.message.setSubject(this.subject);
}
}

// ========================================================
// Start of replacement code
if (this.content != null)
{
this.message.setContent(this.content, this.contentType);
}
// end of replacement code
// ========================================================
else if (this.emailBody != null)
{
this.message.setContent(this.emailBody);
}
else
{
this.message.setContent("", Email.TEXT_PLAIN);
}

if (this.fromAddress != null)
{
this.message.setFrom(this.fromAddress);
}
else
{
throw new EmailException("Sender address required");
}

if (this.toList.size() + this.ccList.size() + this.bccList.size() == 0)
{
throw new EmailException(
"At least one receiver address required");
}

if (this.toList.size() > 0)
{
this.message.setRecipients(
Message.RecipientType.TO,
this.toInternetAddressArray(this.toList));
}

if (this.ccList.size() > 0)
{
this.message.setRecipients(
Message.RecipientType.CC,
this.toInternetAddressArray(this.ccList));
}

if (this.bccList.size() > 0)
{
this.message.setRecipients(
Message.RecipientType.BCC,
this.toInternetAddressArray(this.bccList));
}

if (this.replyList.size() > 0)
{
this.message.setReplyTo(
this.toInternetAddressArray(this.replyList));
}

if (this.headers.size() > 0)
{
Iterator iterHeaderKeys = this.headers.keySet().iterator();
while (iterHeaderKeys.hasNext())
{
String name = (String) iterHeaderKeys.next();
String value = (String) headers.get(name);
this.message.addHeader(name, value);
}
}

if (this.message.getSentDate() == null)
{
this.message.setSentDate(getSentDate());
}

if (this.popBeforeSmtp)
{
Store store = session.getStore("pop3");
store.connect(this.popHost, this.popUsername, this.popPassword);
}
}
catch (MessagingException me)
{
throw new EmailException(me);
}
}
由代碼可以知道純文本方式最終調用了Java Mail的
message.setContent(this.content, this.contentType);
content是內容
contentType是類型,如text/plain,
(我們可以試試直接用Java mail發郵件,設置文本內容不使用setText方法,也使用setContent("測試", "text/plain")方式,你可以看到內容也是亂碼)
關鍵就在于text/plain,我們改成text/plain;charset=gb2312,ok亂碼解決了。在commons mail我們看SimpleEmail 類中setMsg方法調用的就是 setContent(msg, TEXT_PLAIN);我們只需要將Email類中的常量TEXT_PLAIN修改一下加入 charset=你的字符集 ,重新打包jar,這樣就可以了

7、toad的字符集的設置與oracle的安裝
oracle數據庫服務器的安裝一般是中文字符集,有時安裝在不同的平臺下,設置為ISO編碼,toad是oracle開發的最好工具,不是我說的,可是中文環境下安裝的toad,打開英文字符的oracle時,中文全是亂碼。必須進行設置

環境變量---〉系統變量

  NLS_lANG=SIMPLIFIED CHINESE_CHINA.ZHS16GBK
  或
  NLS_lANG=AMERICAN_AMERICA.WE8ISO8859P1

AMERICAN_AMERICA.WE8MSWIN1252
 
 或者

 打開注冊表,點擊HKEY_LOCAL_MATHINE
再點擊Software,再點擊ORACLE
在點擊HOME(ORACLE所在目錄)
在注冊表的右半面有NLS_LANG,
雙擊它,將你想要的覆蓋掉原來的就可以了
最好記下舊的,以便可以改回來。


connect sys/chang_on_install
update props$
set value$='ZHS16CGB231280'
where name='NLS_CHARACTERSET';
commit;
 這樣就OK了

 
8、如何解決GWT(google web toolkit)中文的問題
GWT 中文亂碼解決方法

1.把你要顯示的中文“測試字符串”輸入到一個文件,如:1.txt
2.進入命令行,進入1.txt所在的目錄,敲入以下命令:native2ascii.exe 1.txt 2.txt 回車。這樣就生成了另外一個文件2.txt。
3.2.txt的內容如下:\u6d4b\u8bd5\u5b57\u7b26\u4e32
4.然后用上面的編碼,在gwt中使用,就可以了.

9、xmlHttp得到的網頁怎么是亂碼?
(1)在服務器端使用WebRequest而不是xmlHttp
(2) 將

StreamReader sr = new StreamReader(stream);


對于簡體中文改成:

StreamReader sr = new StreamReader(stream , Encoding.Default );
對于utf-8改成:


StreamReader sr = new StreamReader(stream , Encoding.UTF8 );
當然,Encoding枚舉還有很多其他的成員,對于不同的編碼content-type可以有選擇的應用

(3)后來我發現無論是content-type是gb2312還是utf-8,用


StreamReader sr = new StreamReader(stream , Encoding.Default );

都可以返回正常的漢字,所以統一的改成Encoding.Default

 


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

最后,在服務器端從一個url獲得網頁的源代碼的代碼如下:

 

/// <summary>
/// post一個指定的url,獲得網頁的源代碼(用WebRequest實現)
/// </summary>
/// <param name="url"></param>
/// <returns>
/// 如果請求失敗,返回null
/// 如果請求成功,返回網頁的源代碼
/// </returns>
public static string GetContentFromUrl2( string url )
{
    //變量定義
    string respstr;

    WebRequest myWebRequest=WebRequest.Create(url);
    //            myWebRequest.PreAuthenticate=true;
    //            NetworkCredential networkCredential=new NetworkCredential( username , password , domain );
    //            myWebRequest.Credentials=networkCredential;

    // Assign the response object of 'WebRequest' to a 'WebResponse' variable.
    WebResponse myWebResponse=myWebRequest.GetResponse();
    System.IO.Stream stream = myWebResponse.GetResponseStream();
    StreamReader sr = new StreamReader(stream , Encoding.Default );
    //以字符串形式讀取數據流
    respstr = sr.ReadToEnd();
    sr.Close();
   
    return respstr;
       
}



dyerac in java... 2007-08-13 18:58 發表評論
]]>
JDK1.6.0新特性詳解與代碼示例http://m.tkk7.com/dyerac/articles/131761.htmldyerac in java...dyerac in java...Sun, 22 Jul 2007 14:44:00 GMThttp://m.tkk7.com/dyerac/articles/131761.htmlhttp://m.tkk7.com/dyerac/comments/131761.htmlhttp://m.tkk7.com/dyerac/articles/131761.html#Feedback0http://m.tkk7.com/dyerac/comments/commentRss/131761.htmlhttp://m.tkk7.com/dyerac/services/trackbacks/131761.html閱讀全文

dyerac in java... 2007-07-22 22:44 發表評論
]]>
考慮將 SQLJ 用于 DB2 V8 Java 應用程序http://m.tkk7.com/dyerac/articles/129147.htmldyerac in java...dyerac in java...Mon, 09 Jul 2007 13:54:00 GMThttp://m.tkk7.com/dyerac/articles/129147.htmlhttp://m.tkk7.com/dyerac/comments/129147.htmlhttp://m.tkk7.com/dyerac/articles/129147.html#Feedback0http://m.tkk7.com/dyerac/comments/commentRss/129147.htmlhttp://m.tkk7.com/dyerac/services/trackbacks/129147.html

考慮將 SQLJ 用于 DB2 V8 Java 應用程序

developerWorks
文檔選項
將此頁作為電子郵件發送

將此頁作為電子郵件發送

未顯示需要 JavaScript 的文檔選項



級別: 初級

Connie Tsui, DB2 解決方案集成團隊, IBM 多倫多實驗室

2003 年 2 月 01 日

了解為什么 SQLJ 是注重安全性、性能和簡單性的開發人員所選擇的語言。其中還包含了代碼樣本。

簡介

使用 Java? 訪問關系數據的標準方法有兩種:SQLJ 和 JDBC?。對于 IBM® DB2® Universal Database?(UDB)應用程序,為什么應該考慮 SQLJ 呢?這是因為當應用程序員要考慮安全性、性能和簡單性時,往往會選擇 SQLJ 這樣的語言。本文向您介紹了有關 SQLJ 的一些背景,討論了相對于 JDBC,SQLJ 所具有的優勢,還特別指出了 DB2 UDB V8.1 所提供的一些新增和改進的 SQLJ 特性。





回頁首


SQLJ 的背景

1997 年 4 月,一個由數據庫供應商組成的非正式和開放小組開始定期開會,交流有關如何在 Java 編程語言中使用靜態 SQL 語句和構造的想法。主要參與者包括 IBM、Oracle、Compaq、Informix®、Sybase、Cloudscape 和 Sun Microsystems。該小組把他們正制定的規范命名為 JSQL。但他們發現術語 JSQL 是一個注冊商標,因此就將 JSQL 重命名為 SQLJ。1997 年 12 月,Oracle 向其它成員提供了一個 Java 中嵌入式 SQL 的參考實現。這個參考實現可以在任何支持 JDK 1.1 的平臺上運行,并且它與供應商無關。1998 年 12 月,完成了 Java 中嵌入式 SQL 規范的整個開發工作,并被接納為 ANSI 標準 Database Language - SQL, Part 10 Object Language Bindings (SQL/OLB)ANSI x3.135.10-1998。這個規范一般稱為 SQLJ 規范的第 0 部分。現在它被稱為 SQL/OLB(對象語言綁定,Object Language Binding)。

SQLJ 規范目前由兩部分組成:

  • SQL/OLB:Java 中的嵌入式 SQL
    這部分標準規定了在 Java 方法中嵌入 SQL 的語法和語義,還規定了一些機制來確保生成的 SQLJ 應用程序的二進制可移植性。這正是本文要闡述的主題。
  • SQL/JRT:使用 Java 編程語言的 SQL 例程和類型
    這部分標準包含以下內容:
    • 將 Java 靜態方法作為 SQL 存儲過程和用戶定義的函數來調用的規范。它定義了 SQL 擴展,用于在 SQL 系統中安裝 Java 類,在 SQL 中以 SQL 函數和存儲過程方式調用 Java 類的靜態方法,獲取指定的參數輸出值以及返回 SQL 結果集。
    • 將 Java 類用作 SQL 用戶定義的數據類型的規范。它定義了 SQL 擴展,用于將 Java 類用作 SQL 中的數據類型。

術語:當我們在本文其余部分使用術語 SQLJ 時,僅指 SQL/OLB。





回頁首


SQLJ 編程環境

SQLJ 環境由兩個階段組成:開發和運行時。本節向您介紹每個階段所涉及到的組件以及各組件間的關系。

開發 SQLJ 應用程序

使用 SQLJ 開發應用程序需要三個組件:轉換程序、概要文件定制程序和概要文件綁定程序。有三個實用程序提供了支持這三個組件的功能,它們分別是: sqlj、db2sqljcustomizedb2sqljbind。這里對 圖 1中演示的過程作一個概述:

  1. 首先,調用 SQLJ 轉換程序(sqlj)以讀取 SQLJ 源文件并檢查該程序中 SQLJ 語法的正確性。轉換程序生成一個 Java 源文件,可能不生成 SQLJ 概要文件或生成多個 SQLJ 概要文件,并且如果所生成的 Java 源文件中沒有錯誤,那么它還可以選擇將該源文件編譯成字節碼(缺省情況)。生成的 Java 源文件將嵌入式 SQL 替代為對執行 SQL 操作的 SQLJ 運行時的調用。
  2. 接著,調用 SQLJ 概要文件定制程序(db2sqljcustomize)來為生成的序列化概要文件創建 DB2 定制。該定制程序可以選擇(缺省情況下) 聯機檢查能夠動態編譯的 SQL 語句。聯機檢查執行語法、語義和模式驗證。也可以選擇(缺省情況下)調用 SQLJ 概要文件綁定程序以綁定 DB2 包。
  3. 如果選擇在概要文件定制期間不執行自動綁定,那么可以單獨調用 SQLJ 概要文件綁定程序(db2sqljbind),以將先前定制的 SQLJ 概要文件綁定到數據庫。
  4. 不管概要文件是否被定制,要查看其內容,可以使用 SQLJ 概要文件打印程序(db2sqljprint)以文本格式打印出概要文件的內容。


圖 1. SQLJ 開發環境
SQLJ 開發環境

執行 SQLJ 應用程序

為訪問數據庫,SQLJ 運行時要依靠 JDBC 驅動程序來獲取數據庫連接。未定制的 SQLJ 應用程序可以與任何 JDBC 2.0 驅動程序一起運行。在開發期間,為了測試,只需運行未定制應用程序。要運行定制的 SQLJ 應用程序,可以使用 V8 基于 CLI 的 JDBC 類型 2 驅動程序 - 通用 JDBC 驅動程序(類型 2 或類型 4)來建立數據庫連接。本節中,我們只描述用于定制的 SQLJ 應用程序的運行時環境。

當您運行 SQLJ 應用程序時,SQLJ 運行時從定制的概要文件中讀取有關 SQL 操作的信息,并執行與存儲在定制中的包關鍵信息(包名、包一致性標記和集合名)相符的 DB2 包中的語句。



圖 2. SQLJ 運行時環境
SQLJ 運行時環境




回頁首


SQLJ 相對于 JDBC 的優勢

SQLJ 規范和 JDBC 規范都描述了如何使用 Java 來訪問關系數據庫。本節從以下幾個方面討論它們之間的差異:

表 1匯總了我們在本節中所描述的 SQLJ 和 JDBC 之間的差異。

標準和 SQL 規范級別

SQLJ 是 ISO/IEC 9075-10:2000 Information technology -- Database languages -- SQL -- Part 10: Object Language Bindings (SQL/OLB)的實現。SQLJ 不屬于 J2EE 平臺。

JDBC 是 J2SE 1.4 和 J2EE 1.4 平臺規范的一個必不可少的組件。它自 Java 軟件開發工具箱(Java Software Development Kit,JDK)V1.1 之后已成為其核心部件。它包含在 java.sql 包中。JDBC 驅動程序必須至少支持 Entry SQL-92 語句,在該規范中還定義了一些擴展。

安全性

SQLJ 中實現的安全性權限模型是用戶考慮使用 SQLJ 的一個主要原因。使用靜態 SQL,安全性特權就被指派給了包創建者,并被存儲在 DB2 包中。

使用定制的 DB2 SQLJ,靜態地執行 SQL;因此使用包所有者的特權來執行 SQL 語句。任何運行 SQLJ 應用程序的其他用戶都必須被授予具有該包的 EXECUTE 特權。即,被授權可以運行程序的用戶未必有權對該程序所查詢或正在修改的同一表或視圖執行 SELECT、UPDATE、DELETE 或 INSERT 操作,除非顯式地授予該用戶相應的特權。

擁有連接到數據庫并執行 JDBC 應用程序特權的人可以執行這些應用程序中的 SQL 語句。因此,用戶必須獲得訪問表的特權。

性能

SQLJ 允許在 Java 程序中嵌入 SQL 語句,這類似于 SQL-92 允許 SQL 語句嵌入到 C、COBOL、FORTRAN 以及其它編程語言中的方式。但是,根據 SQLJ 概要文件是否被定制,可以決定 SQLJ 應用程序是動態還是靜態地運行。當將包存儲在 DB2 數據庫中時,就會預編譯 SQLJ 應用程序并優化 SQL 語句的路徑長度。靜態執行的 SQLJ 應用程序的性能會優于 JDBC 的性能。

如果想利用靜態執行(我們建議這樣做),必須使用 SQLJ 概要文件定制程序來定制概要文件。

JDBC 提供了 SQL 語句的動態執行。如果這些語句中存在語法或語義錯誤,那么在該應用程序運行時任何此類異常都會產生。

使用 DB2 UDB 監視器可以驗證靜態或動態的 SQL 語句處理。監控方法有兩種:快照監控和事件監控。快照監視器提供有關數據庫在某個特定時間點的活動信息。事件監視器記錄了 DB2 UDB 事件發生的特定位置。下面的 清單 1 摘自從 JDBC 程序生成的事件監視器的樣本輸出。“Type: Dynamic”告訴您動態執行了 SELECT job FROM staff WHERE name = ? 語句。

清單 1. 從 JDBC 程序生成的事件監視器的樣本輸出
10) Statement Event ...
                        Appl Handle: 23
                        Appl Id: G91AA377.G576.00F306261BF2
                        Appl Seq number: 0001
                        Record is the result of a flush: FALSE
                        -------------------------------------------
                        Type     :
                        
                                    Dynamic
                        
                        Operation: Prepare
                        Section  : 1
                        Creator  : NULLID
                        Package  : SYSSH200
                        Consistency Token  : SYSLVL01
                        Package Version ID  :
                        Cursor   : SQL_CURSH200C1
                        Cursor was blocking: FALSE
                        Text     : SELECT job FROM staff WHERE name = ?
                        

清單 2摘自從 SQLJ 程序生成的事件監視器的樣本輸出。輸出中的“Type: Static”和“Package: SRQT402”告訴您,對 SRQT402 包靜態執行了該語句。

清單 2. 從 SQLJ 程序生成的事件監視器的樣本輸出
10) Statement Event ...
                        Appl Handle: 12
                        Appl Id: G91ABD18.G47D.00F306C01D63
                        Appl Seq number: 0001
                        Record is the result of a flush: FALSE
                        -------------------------------------------
                        Type     :
                        
                                    Static
                        
                        Operation: Execute
                        Section  : 1
                        Creator  : NULLID
                        Package  :
                        
                                    SRQT402
                        
                        Consistency Token  : SARoQCAp
                        Package Version ID  :
                        Cursor   :
                        Cursor was blocking: FALSE
                        

注:有些語句對于定制的 SQLJ 程序會正確執行,但對于未定制的 SQLJ 程序就不會正確執行。可滾動游標的 UPDATE/DELETE WHERE CURRENT OF 就是這樣一個示例。一般而言,如果底層 JDBC 驅動程序不支持某個功能,那么未定制的 SQLJ 程序也不會支持該功能。

性能技巧:
對于單個 select 查詢,與盲目地對龐大的 JDBC ResultSets 執行操作相比,可以通過使用由 SQLJ 提供的 SELECT INTO 語法來減少網絡活動。

圖 3比較了用于單個 select 查詢的 SQLJ 和 JDBC 語法。

圖 3. 使用 SQLJ 和 JDBC 檢索一個行

SQLJ 語法:

#sql [conCtx] { SELECT job INTO :job FROM staff WHERE name = :name };

JDBC 語法:

PreparedStatement pstmt = con.prepareStatement(
                                    "SELECT job FROM staff WHERE name = ? FETCH FIRST 1 ROW ONLY" );
                                    ResultSet rs = pstmt.executeQuery();
                                    if ( rs.next() )
                                    job = rs.getString(1);
                                    else
                                    job = null;
                                    pstmt.close();
                                    

語法

圖 3表明 SQLJ 語法在簡單性方面優于 JDBC。SQLJ 的簡單性受到了許多 Java 開發人員的歡迎。編寫 SQLJ 模塊通常要比 JDBC 模塊簡潔且容易。這暗示著 SQLJ 可以使開發周期縮短并減少開發和維護成本。 圖 4向您顯示了 SQLJ 可以多么簡單地向數據庫插入一行數據。如果您已有了用其它語言(如 C 或 COBOL)編寫的嵌入式 SQL 應用程序,那么就可以使用 SQLJ 輕松地將應用程序遷移到 Java。

圖 4. 使用 SQLJ vs. JDBC 插入一個行

SQLJ 語法:

sql [conCtx] { INSERT INTO sales VALUES(:date, :salesperson, :region, :sales) };

JDBC 語法:

PreparedStatement pstmt = con.prepareStatement( "INSERT INTO sales VALUES (?, ?, ?, ?)" );
                        // set input parameter
                        pstmt.setObject(1, date);
                        pstmt.setString(2, salesperson);
                        pstmt.setString(3, region);
                        pstmt.setInteger(4, sales);
                        pstmt.executeUpdate();
                        pstmt.close();
                        

SQLJ 和 JDBC 互操作性

SQLJ 語言允許您在 SQLJ 應用程序中使用 JDBC 語句。要使 JDBC 和 SQLJ 之間便于交互,SQLJ 提供了一種方法以便在同一應用程序內共享 SQLJ 連接和 JDBC 連接,這種方法還可以從 SQLJ 迭代器中獲取 JDBC 結果集,或從 JDBC 迭代器中獲取 SQLJ 結果集。

何時需要在 SQLJ 應用程序中使用 JDBC?
您需要將 JDBC 用于動態操作時;即,在編寫程序時不清楚 SQL 操作的時候。 清單 3演示了在 SQLJ 程序內用 JDBC 來執行動態查詢(WHERE 子句中的名稱在開發時是未知的),以及如何將 JDBC 結果集轉換到 SQLJ 迭代器。

與 SQLJ 不同的是,JDBC 不能識別 SQLJ 語法,而且 SQL 語句不能嵌入到 JDBC 應用程序。

清單 3. 將 JDBC 結果集轉換到 SQLJ 迭代器
Public class ResultSetInterop
                                    {
                                    #sql public static iterator Employees (String name, double salary);
                                    public static void main(String[] argv) throws SQLException
                                    {
                                    // the code for creating the SQLJ connection context (conCtx) and
                                    // the Connection object (con) is omitted
                                    // create a JDBC statement object to execute a dynamic query
                                    Statement stmt = con.createStatement();
                                    String query = "SELECT name, salary FROM staff WHERE ";
                                    query += argv[0];
                                    ResultSet rs = stmt.executeQuery(query);
                                    Employees SalReport;
                                    // turn a JDBC result set to an SQLJ interator using the CAST statement
                                    #sql [conCtx] SalReport = {
                                    CAST :rs };
                                    while (SalReport.next()) {
                                    System.out.println( SalReport.name() + " earns " + SalReport.salary() );
                                    }
                                    SalReport.close();
                                    stmt.close();
                                    }
                                    }
                                    

類型和模式檢查

SQLJ 與 Java 類似的一點是,它也是強類型的。在將 SQLJ 源文件轉換成 Java 源文件時,SQLJ 轉換程序會檢查 SQLJ 語法。這類似于其它 DB2 預編譯器。而且,在轉換階段的 Java 編譯期間執行迭代器數據類型的轉換。例如,在禁止使用雙精度的迭代器列(如雇員工資)中,Java 編譯器就會阻止該列使用雙精度類型。因此, String hv = employees.salary(); 這樣的賦值在編譯時就會生成一個錯誤。另外,在概要文件定制期間也執行聯機檢查,以便可以較早地捕獲編程錯誤。

JDBC 不能在運行時之前進行語法或語義檢查。如果存在語法或語義錯誤,那么在應用程序運行時任何此類異常都會產生。

注:

  • 在 V8.1 中,在概要文件定制期間執行聯機檢查,而在以前的發行版中這一操作是在轉換階段執行的。
  • 有些 SQLJ 錯誤只有在運行時才被捕獲到。另外,不能動態編譯的語句不會進行聯機檢查。




回頁首


差異匯總

表 1匯總了 SQLJ 和 JDBC 之間的差異。

表 1. 比較 SQLJ 和 JDBC
     SQLJ JDBC
標準 ISO/ANSI(不屬于 J2EE) Sun(屬于 J2EE)
SQL 規范級別 SQL-1999 N/A(必須至少支持 Entry Level SQL-92)
安全性 一般
性能 較快(在開發期間創建了靜態存取方案) 較慢(在應用程序執行期間創建了動態存取方案)
語法 高級(緊湊) 低級(繁瑣)
SQLJ 和 JDBC 互操作性 N/A
類型和模式檢查 強(在開發期間執行) 弱(在運行時期間執行)





回頁首


V8.1 中的新增功能

DB2 UDB V8.1 提供了新設計的 SQLJ 驅動程序,它有幾個新特性。新的 SQLJ 驅動程序基于一種稱為 Distributed Relational Database Architecture?(DRDA®)的開放分布式協議。基于 CLI 的 JDBC 驅動程序(類型 2 和類型 3)以及 V8.1 中引入的新的通用 JDBC 驅動程序(類型 2 和類型 4)都支持該協議。

SQLJ 的主要增強功能可以概括如下:

新的 SQLJ 實用程序和運行時

DB2 UDB V8.1 中的 SQLJ 實現了純 Java SQLJ 實用程序和運行時,并帶有一些新選項和可選的格式。新的運行時性能比 V7 的性能好得多。

在 V8.1 中,SQLJ 轉換程序 sqlj 在缺省情況下總是編譯所生成的 Java 源文件。在 V7 中,這個編譯選項不能與某些 JDK 一起使用,因此您必須手工編譯 Java 文件。

V8.1 中新的概要文件打印程序 db2sqljprint 不再需要您提供 URL,而且它提供了有關要執行的 SQL 語句的詳細信息,例如 DB2 語句的類型、節號以及 DB2 結果集元數據信息。

消除了特定于平臺的文件

V8.1 中的 SQLJ 概要文件定制程序包含新的序列化概要文件格式,它不必使用 DBRM 文件和綁定文件(.bnd 文件)。新格式完全可以移植到所有平臺。它包含所有 BIND 操作所需的所有信息,用戶不必在目標系統(UNIX®、Windows®、OS/390® 和 z/OS?)上重新定制序列化概要文件就可以部署在任何服務器平臺上。

V8 中的新特性

DB2 UDB V8.1 中添加的主要特性包括以下各項:

使用 DataSource 創建 SQLJ 連接上下文

有了 V8.1 SQLJ,您可以使用 JDBC DataSource 接口來創建 SQLJ 連接。而且,缺省連接上下文的實現也更改了。要獲得缺省連接上下文,SQLJ 運行時要執行 JNDI 查詢以獲得 jdbc/defaultDataSource。如果沒有注冊任何 jdbc/defaultDataSource,那么在驅動程序試圖訪問上下文時,就會拋出一個空上下文異常。因此,必須向 JNDI 注冊 jdbc/defaultDataSource,或者通過調用 DefaultContext.setDefaultContext(userctxt) 來設置缺省上下文。

建議:在 SQLJ 子句中使用顯式的連接上下文。

清單 4. 使用數據源創建 SQLJ 連接上下文
// Create connection context class Ctx with the new dataSource keyword
                                    #sql public static context Ctx with (dataSource="jdbc/sampledb");
                                    String userid, password;
                                    String empname;
                                    ?
                                    // Create connection context object conCtx for the connection to jdbc/sampledb
                                    Ctx conCtx = new Ctx(userid, password);
                                    #sql [conCtx] { SELECT lastname INTO :empname FROM emp WHERE empno = '000010' };
                                    ?
                                    conCtx.close();
                                    

可滾動的迭代器

可滾動的迭代器允許您向前移、向后移或移動到指定行。與 JDBC 中可滾動的游標相似,可滾動的迭代器可以是 不敏感的,也可以是 敏感的

  • 不敏感的迭代器意味著在迭代器打開后,它不能看到底層表中的更改。不敏感的迭代器是只讀的。
  • 敏感的迭代器意味著迭代器可以看到迭代器或其它處理對底層表所作的更改。例如, 清單 5中的代碼演示了如何使用指定的迭代器對雇員表的所有行以逆序方式檢索雇員號和雇員的姓氏。

清單 5. 使用可滾動的迭代器
//  Declare a scrollable iterator.
                                    #sql  iterator ScrollIter implements sqlj.runtime.Scrollable with (sensitivity = SENSITIVE)
                                    (String EmpNo, String LastName);
                                    {
                                    ScrollIter scrlIter;
                                    #sql [conCtx] scrlIter={ SELECT empno, lastname FROM emp };
                                    scrlIter.afterLast();
                                    while (scrlIter.previous())
                                    {
                                    System.out.println(scrlIter.EmpNo() + " " + scrlIter.LastName());
                                    }
                                    scrlIter.close();
                                    }
                                    

批處理更新

批處理更新允許將語句集中到一起,隨后將其以批處理方式發送到數據庫,一次執行完這些語句。您可以在批處理更新中包含以下幾種類型的語句:

  • 搜索到的 INSERT、UPDATE 或 DELETE 語句
  • CREATE、ALTER、DROP、GRANT 或 REVOKE 語句
  • 只帶輸入參數的 CALL 語句

與 JDBC 不同,SQLJ 允許異構批處理,這些批處理中包含帶有輸入參數或主機表達式的語句。因此在同一個 SQLJ 語句批處理中可以包含同一語句的實例、不同語句的實例、帶輸入參數或主機表達式的語句的實例以及不帶輸入參數或主機表達式的語句的實例等。

建議:在關閉批處理或在結束使用 ExecutionContext(會使批處理打開)之前,要顯式地調用 executeBatch()。這將確保執行經過批處理的所有語句。

清單 6中的代碼段向您顯示了如何以批處理方式執行更新操作來給所有管理人員加薪。

清單 6. 執行批處理更新
#sql iterator getMgr(String);
                        {
                        getMgr deptIter;
                        String mgrnum = null;
                        int raise = 400;
                        int currentSalary;
                        String url = null, username = null, password = null;
                        testContext conCtx = new testContext (url, username, password, false);
                        // Acquire execution context.
                        // All statements that execute in a batch must use this execution context.
                        ExecutionContext exeCtx = new ExecutionContext();
                        // Invoke ExecutionContext.setBatching (true) to create a batch.
                        exeCtx.setBatching(true);
                        #sql [conCtx] deptIter =  { SELECT mgrno FROM dept };
                        #sql {FETCH :deptIter INTO :mgrnum};
                        while (!deptIter.endFetch())
                        {
                        #sql [conCtx] {
                        SELECT SALARY INTO :currentSalary FROM emp WHERE empno = :mgrnum};
                        #sql [conCtx, exeCtx]
                        { UPDATE emp SET SALARY = :(currentSalary+raise) WHERE empno =:mgrnum };
                        #sql { FETCH :deptIter INTO :mgrnum };
                        }
                        exeCtx.executeBatch();
                        exeCtx.setBatching(false);
                        #sql [conCtx] {COMMIT};
                        deptIter.close();
                        exeCtx.close();
                        conCtx.close();
                        }
                        





回頁首


結束語

相對于 JDBC,SQLJ 的 DB2 實現具有明顯的優勢。在預編譯時 SQLJ 較簡單語法和類型以及模式檢查大大降低了開發成本。SQLJ 還具有在 SQLJ 應用程序中嵌入 JDBC 語句這樣的靈活性。這意味著一個應用程序可以同時利用 SQLJ 和 JDBC 的優點。當安全性和性能對 Java 應用程序至關重要時,SQLJ 是正確的選擇。





回頁首


更多信息



關于作者

照片:Connie Tsui

Connie Tsui是 IBM 多倫多實驗室 DB2 解決方案集成團隊的專職軟件分析師。她從多倫多大學(University of Toronto)獲得了計算機科學學士學位。她目前主要從事 DB2 和 WebSphere® 的集成。



dyerac in java... 2007-07-09 21:54 發表評論
]]>
使用 SQLJ 開發應用程序http://m.tkk7.com/dyerac/articles/129143.htmldyerac in java...dyerac in java...Mon, 09 Jul 2007 13:51:00 GMThttp://m.tkk7.com/dyerac/articles/129143.htmlhttp://m.tkk7.com/dyerac/comments/129143.htmlhttp://m.tkk7.com/dyerac/articles/129143.html#Feedback0http://m.tkk7.com/dyerac/comments/commentRss/129143.htmlhttp://m.tkk7.com/dyerac/services/trackbacks/129143.html使用 SQLJ 開發應用程序

用 DB2 UDB V8.1 和 Application Developer V5.1.2 創建使用 SQLJ 的 Java 和 J2EE 應用程序

文檔選項

將此頁作為電子郵件發送

未顯示需要 JavaScript 的文檔選項

樣例代碼

級別: 初級

Owen Cline (owenc@us.ibm.com), 認證的 IT 咨詢專家 - WebSphere 軟件服務, IBM

2005 年 2 月 01 日

這篇 "how-to" 文章將解釋如何在 Java™ 應用程序和 J2EE™ 應用程序中使用 SQLJ。文中將介紹 SQLJ 語法,使用 SQLJ 訪問數據源,建立 WebSphere® Application Developer 項目以支持 SQLJ,以及創建和調用 DB2® 存儲過程。

SQLJ 概述

SQL 語句包括查詢(SELECT)、插入(INSERT)、更改(UPDATE)、刪除(DELETE)語句以及其他對存儲在關系數據庫表中的數據進行操作的語句。SQLJ 是在 Java 中嵌入這些 SQL 語句的一種約定,它是以某種允許編程工具對 Java 中 SQL 進行編譯時分析的方式實現嵌入的,在編譯時會對 SQL 語句進行語法檢查以保證語法的正確性,進行類型檢查以確定 Java 和 SQL 之間交換的數據具有兼容的類型和適當的類型轉換,以及進行模式檢查以確保 SQL 結構在它們執行時所在的數據庫模式中是格式良好的、合法的。嵌入式 SQL 語句被稱為是 "靜態的(static)",因為這些語句在 Java 程序中一目了然,因而嵌入式 SQL 語句隨著包含它們的 Java 程序的編譯而編譯(通常的術語是"預編譯")。我們提議將 SQLJ 作為用于緊密集成 Java/SQL 程序的一種方便有效的標準。

SQLJ 簡史

正如 Connie Tsui 在她的文章(后面有引用)中解釋的那樣,一個非正式的、開放的數據庫供應商組織在 1997 年 4 月開始定期的會面,以便交換關于如何在 Java 編程語言中使用靜態 SQL 語句和結構的思想。主要參與者包括 IBM®、Oracle、Compaq、Informix®、Sybase、Cloudscape™ 和 Sun Microsystems。該組織將他們為之努力的規范命名為 JSQL。在發現 JSQL 已經是商標術語后,JSQL 被更名為 SQLJ。在 1997 年 12 月,Oracle 向其他成員提供了 Java 中嵌入式 SQL 的一個參考實現。該參考實現可以在任何支持 JDK 1.1 的平臺上運行,并且是與供應商無關的。在 1998 年 12 月,用于在 Java 中嵌入 SQL 的規范被完全開發出來,并且被接受為 ANSI 標準 Database Language —— SQL, Part 10 Object Language Bindings (SQL/OLB) ANSI x3.135.10-1998。該規范已經被當作 SQLJ 規范的 Part 0 供大家引用。如今它被稱作 SQL/OLB (Object Language Bindings)。

SQLJ 與 JDBC 的比較

SQLJ —— Java 數據庫應用程序的開門咒語

SQLJ 標準現在為 Java 應用程序提供了基于 SQL 的數據庫訪問。SQLJ —— Java 數據庫應用程序的開門咒語

下面是 SQLJ 相對于直接在 JDBC 中編寫代碼的優勢:

SQLJ 程序需要的代碼行數比 JDBC 程序更少。SQL 程序更簡短,因而更易于調試。SQLJ 可以通過在編譯時使用數據庫連接,對代碼執行語法和語義上的檢查。SQLJ 提供了對查詢結果及其他返回參數的強類型檢查,而 JDBC 值則是直接從 SQL 返回,在編譯時未進行任何檢查。

SQLJ 為處理 SQL 語句提供了一種簡化的方式。現在無需編寫不同的方法調用來綁定每個輸入參數和獲取每個選擇列表項,而只需編寫一條使用 Java 宿主變量的 SQL 語句。SQLJ 會替您完成綁定。

然而,JDBC 提供了對 SQL 語句的執行的細粒度控制,并提供了真正的動態 SQL 能力。如果應用程序需要動態能力(在運行時發現數據庫或實例元數據),那么應該使用 JDBC。

回頁首

為 SQLJ 建立 WebSphere Studio Application Developer 項目

如果您計劃將 SQLJ 代碼包括到所有 WebSphere Studio Application Developer (Application Developer) 項目中,那么需要使您的項目支持 SQLJ。為此,可以右擊項目并選擇 Add SQLJ Support。這將彈出 SQLJ 向導,如下所示。

圖 1. 使 Application Developer 項目支持 SQLJ

回頁首

SQLJ 和 Java 應用程序

從 Application Developer 主菜單中,選擇 File -> New -> Other ,然后選擇 Java Java Project。單擊 Next

圖 2. 創建 Java 項目

輸入項目名,單擊 Next

圖 3. 輸入 Java 項目名

選擇 Finish 創建該項目。

圖 4. 輸入 Java 項目設置

為了讓 Java 應用程序能夠成功運行,還需添加 DB2 JDBC 驅動程序 db2java.zip。右擊 Java 項目,選擇 Properties

圖 5. 編輯 Java 項目屬性

接下來,選擇 Java Build path,然后選擇 Libraries 標簽頁。然后選擇 Add External JARs

圖 6. 添加外部 JAR —— db2java.zip

完成這些設置后,庫路徑應該如下所示:

圖 7. 添加外部 JAR —— db2java.zip

接下來的步驟是創建有關 Java 類,用于容納主方法。為此,需要右擊 Java 項目,然后選擇 New -> Class。填入包名和類名。另外,確保勾選了關于創建主方法的復選框。單擊 Finish

圖 8. 創建 Java 主類

最后,需要創建 SQLJ 文件。從 Application Developer 主菜單中,選擇 File -> New -> Other,然后選擇 Data -> SQLJSQLJ File。最后單擊 Next。Application Developer 將保證 SQLJ 文件被轉換成一個 Java 文件。

圖 9. 選擇 SQLJ 文件向導

填入包名和文件名。然后單擊 Finish

圖 10. 創建 SQLJ 文件

至此,還需要將代碼添加到 Java 主方法中,另外必須創建一個 SQLJ 方法。首先讓我們明確要完成什么。我們將創建一個 SQLJ 方法,該方法從 DB2 SAMPLE 數據庫中根據給定的雇員號讀取一個雇員記錄。這個 SQLJ 方法以雇員號(一個 Java String)作為輸入,并將其作為參數傳遞給一條 SQLJ Select 語句。Java 主方法將調用這個 SQLJ 方法。

清單 1. 包含主方法的 Java 類

<![CDATA[
/*
* Created on Nov 27, 2004
*
*/
package com.ibm.sqlj.main;
import com.ibm.sqlj.Select;
/**
* @author Owen Cline
*
*/
public class SQLJJave {
public static void main(String[] args) {
Select select = new Select();
select.selectEmployee("000110");
}
}
]]>

清單 2. 包含 SQLJ 方法的 SQLJ 類

<![CDATA[
/*
* Created on Nov 27, 2004
*
*/
package com.ibm.sqlj;
import java.sql.*;
import sqlj.runtime.ref.*;
/**
* @author Owen Cline
*
*/
public class Select {
// First, load the JDBC driver
static
{ try
{ Class.forName ("COM.ibm.db2.jdbc.app.DB2Driver").newInstance ();
} catch (Exception e)
{ System.out.println ("\n Error loading DB2 Driver...\n");
System.out.println (e);
System.exit(1);
}
}
public void selectEmployee(String empNo) {
Connection con = null; DefaultContext ctx = null; try {
String firstName = null;
String lastName = null;
// use the DB2 SAMPLE database
String url = "jdbc:db2:SAMPLE";
// Get the connection
con = DriverManager.getConnection(url); // Set the default context
ctx = new DefaultContext(con); DefaultContext.setDefaultContext(ctx);
// Lookup the employee given the employee number
#sql { SELECT FIRSTNME, LASTNAME INTO :firstName, :lastName
FROM EMPLOYEE
WHERE EMPNO = :empNo } ;
System.out.println ("Employee " + firstName + " " + lastName);
ctx.close();
con.close();
}
catch( Exception e )
{
System.out.println (e);
}
}
}
]]>

現在便可以運行這個 Java 應用程序了。選中您的 Java 項目,然后從 Application Developer 主菜單中選擇 Run -> Run As -> Java Application。您應該可以看到在控制臺 "Employee VINCENZO LUCCHESSI" 中打印出如下消息。

回頁首

SQLJ 和 J2EE 應用程序

您可能想到,還可以在 J2EE 應用程序、servlet、會話 bean、BMP 實體 bean 和 MDB bean 中使用 SQLJ。現在我們要做的就是將我們創建的在 Java 應用程序中運行的上述代碼移植,使之在一個會話 bean 中運行。

首先,需要創建一個 EJB 項目。從 Application Developer 主菜單中,選擇 File- > New -> Project。 然后選擇 EJB and EJB Project。單擊 Next

圖 11. 創建 EJB Project

確保選擇了 Create 2.0 EJB Project ,然后單擊 Next

圖 12. 選擇一個 EJB 版本

現在,輸入 SQLJSession 作為 EJB 項目名。EAR 項目應該是 DefaultEAR。單擊 Next

圖 13. 輸入 EJB 項目名

在 Module Dependencies 對話框中,選擇 Finish 創建 EJB 項目和 EAR 項目。

圖 14. 輸入 EJB 模塊依賴

在這里,我們還想創建一個會話 Bean。 選擇 Application Developer 主菜單中的 File -> New -> Enterprise Bean。然后單擊 Next

圖 15. 創建一個會話 Bean —— 步驟 1

確保選擇了 Session bean 單選按鈕,并輸入了一個 Bean 名稱。然后單擊 Next

圖 16. 創建一個會話 Bean —— 步驟 2

確保選中 Local client view 復選框,以得到本地接口(如果 EJB 容器部署在本地,那么這樣做會更快一些),然后單擊 Finish 創建會話 Bean。

圖 17. 創建一個會話 Bean - 步驟 3

現在我們來創建一個 SQLJ 文件,該文件將包含我們的業務邏輯。右擊 EJB 項目 SQLJSession 并選擇 New -> Other,然后選擇 Data -> SQLJSQLJ File。最后單擊 Next

圖 18. 創建 SQLJ 文件 —— 步驟 1

輸入包名和文件名,然后選擇 Finish 創建 SQLJ 文件。還應注意的是,由于是在一個項目中創建這個 SQLJ 文件,而這個項目還沒有添加 SQLJ 支持,因此這一次需添加該支持。

接著,使用上述步驟創建第二個 SQLJ 文件,文件名為 SessionBeanSelectUsingDefaultDatasource,以便以后演示如何使用 defaultDataSource。現在,我們可以在創建的 SQLJ 文件中添加自己的業務邏輯,如下所示:

圖 19. 創建 SQLJ File —— 步驟 2

清單 3. SessionBeanSelect.sqlj

<![CDATA[
package com.ibm.sqlj;
import java.sql.*;
import sqlj.runtime.ref.*;
import javax.sql.DataSource;
/**
* @author Owen Cline
*
*/
public class SessionBeanSelect {
// Setup datasource to use. Notice that I am not using a global JNDI name // but instead using a Resource Reference which points to the global JNDI name. // This is a best practice.
#sql public static context Ctx with (dataSource="java:comp/env/sqljDS");
public void selectEmployee(String empNo) {
String firstName = null;
String lastName = null;
try {
// Create context
Ctx conCtx = new Ctx();
// Lookup the employee given the employee number
#sql [conCtx] { SELECT FIRSTNME, LASTNAME INTO :firstName, :lastName
FROM EMPLOYEE
WHERE EMPNO = :empNo } ;
System.out.println ("SessionBeanSelect-Employee " + firstName + " " + lastName);
conCtx.close();
} catch (Exception e) {
System.out.println(e);
}
}
}
]]>

清單 4. SessionBeanSelectUsingDefaultDatasource.sqlj

<![CDATA[
package com.ibm.sqlj;
import java.sql.*;
import sqlj.runtime.ref.*;
import javax.sql.DataSource;
/**
* @author Owen Cline
*
*/
public class SessionBeanSelectUsingDefaultDatasource {
public void selectEmployee(String empNo) {
String firstName = null;
String lastName = null;
try {
// Lookup the employee given the employee number
#sql { SELECT FIRSTNME, LASTNAME INTO :firstName, :lastName
FROM EMPLOYEE
WHERE EMPNO = :empNo } ;
System.out.println ("SessionBeanSelectUsingDefaultDatasource-Employee " + firstName + " " + lastName);
} catch (Exception e) {
System.out.println(e);
}
}
}
]]>

現在,我們要添加 bean 模塊,以便調用 SQLJ 文件中的業務邏輯。編輯 SQLJSessionBeanBean.java 文件,添加兩個方法:selectEmployee 和 selectEmployeeUsingDefaultDatasource,如以下清單所示。然后,別忘了使這兩個方法成為本地接口。最后,在進入下一步之前,確保生成了部署和 RMIC 代碼。

清單 4. SQLJSessionBeanBean.java

<![CDATA[
package com.ibm.sqlj.ejb.session;
import com.ibm.sqlj.SessionBeanSelect;
import com.ibm.sqlj.SessionBeanSelectUsingDefaultDatasource;
/**
* Bean implementation class for Enterprise Bean: SQLJSessionBean
*/
public class SQLJSessionBeanBean implements javax.ejb.SessionBean {
private javax.ejb.SessionContext mySessionCtx;
/**
* getSessionContext
*/
public javax.ejb.SessionContext getSessionContext() {
return mySessionCtx;
}
/**
* setSessionContext
*/
public void setSessionContext(javax.ejb.SessionContext ctx) {
mySessionCtx = ctx;
}
/**
* ejbCreate
*/
public void ejbCreate() throws javax.ejb.CreateException {
}
/**
* ejbActivate
*/
public void ejbActivate() {
}
/**
* ejbPassivate
*/
public void ejbPassivate() {
}
/**
* ejbRemove
*/
public void ejbRemove() {
}
/**
* selectEmployee
*/
public void selectEmployee(String empNo) {
SessionBeanSelect sbs = new SessionBeanSelect();
sbs.selectEmployee(empNo);
}
/**
* selectEmployee
*/
public void selectEmployeeUsingDefaultDatasource(String empNo) {
SessionBeanSelectUsingDefaultDatasource sbs = new SessionBeanSelectUsingDefaultDatasource();
sbs.selectEmployee(empNo);
}
}
]]>

為最終測試我們的會話 Bean,必須創建一個 Server Configuration。切換到 Server Perspective,并在 Server Configuration 視圖中單擊右鍵。選擇 New -> Server and Server Configuration。輸入服務器名 TestServer ,然后單擊 Finish 創建該服務器。

圖 20. 創建一個 Server Configuration

創建好服務器后,在服務器上單擊右鍵(同樣也是在 "Server Configuration" 視圖中),然后選擇 Add and Remove Projects。 在 "Add and Remove Projects" 對話框中(這里沒有顯示出來),添加 DefaultEAR 項目并單擊 Finish

最后要做的是創建我們的會話 Bean 將要使用的 DB2 數據源。在 Server Configuration 視圖中右擊 Test Server,這將彈出服務器配置編輯器。選擇 Security 標簽頁,然后選擇下面顯示的 JAAS Authentication Entries 對話框旁邊的 Add 按鈕。為該條目輸入一個名稱,然后輸入一個用于訪問數據庫的合法用戶名和密碼。最后單擊 OK

圖 21. 添加 JAAS 認證條目

現在,選擇 Data source 標簽頁。在 JDBC Provider 列表中選擇 Default DB2 JDBC Provider 條目。單擊在上面所選 JDBC 提供者中定義的數據源旁邊的 Add 按鈕。確保選中了 DB2 JDBC ProviderVersion 5.0 data source 單選按鈕。然后單擊 Next

圖 22. 選擇要創建的數據源的類型

輸入 sqljDS 作為數據源名稱,輸入 jdbc/sqljDS 作為 JNDI 名稱。對于 "Component-managed authentication alias" 和 "Container-managed authentication alias",都選擇前面創建的 JAAS Authentication Entry。然后單擊 Finish

圖 23. 輸入 sqljDS 的數據源參數

重復這些步驟,創建另一個名為 defaultDataSource 的數據源,數據源的 JNDI 名稱為 jdbc/defaultDataSource。最后,保存該服務器配置。

圖 24. 輸入 defaultDataSource 的數據源參數

現在,我們需要創建一個 Resource Reference,以便會話 bean 可以查找 sqljDS 數據源。因此,切換到 Application Developer 中的 J2EE Perspective。在 J2EE Hierarchy 視圖中,右擊 SQLJSession EJB 項目,以調用 EJB Deployment Descriptor 編輯器。選擇 References 標簽頁。選擇 SQLJSessionBean 并選擇 Add 按鈕。選擇 Resource Reference 單選按鈕,然后單擊 Next

圖 25. 創建資源引用

輸入 sqljDS 作為名稱。選擇 javax.sql.DataSource 作為類型。為 Authentication 選擇 Container 。 保留 Sharing Scope 為 Shareable。然后單擊 Finish

圖 26. 輸入資源引用參數

選中剛創建的資源引用,然后輸入 jdbc/sqljDS 作為 JNDI 名。保存該 EJB 部署描述文件。

圖 27. 輸入資源引用的 JNDI 名

至此,您應該可以測試會話 Bean 模塊了。首先,在 Server Perspective 中,通過在 Servers 視圖中右鍵單擊 TestServer 并選擇 Start 來啟動該服務器。接著,通過在 Servers 視圖中單擊右鍵并選擇 Run universal test client 調用 Universal Test Client。從這個 universal test client 中,選擇 JNDI Explorer 并展開 "jdbc" 菜單,以顯示出兩個數據源:sqljDS 和 defaultDataSource。接下來,完全展開 Local EJB beans 菜單,直到能夠選擇 SQLJSessionBeanLocalHome。在 EJB reference 菜單中完全展開菜單項,直到能夠選擇 SQLJSessionBeanLocal.create() 模塊,然后選擇 Invoke followed by the Work with Object 按鈕。

圖 28. 調用 SQLJSessionBeanLocal.create() 方法

現在,您將看到有兩個方法可供調用:selectEmployee 和 selectEmployeeUsingDefaultDatasource。選擇 selectEmployee 方法。輸入 000110 作為 empNo 值,并選擇 Invoke 按鈕。檢查控制臺窗口,以確信顯示了 "[11/28/04 16:56:05:176 PST] 6d2f338b SystemOut O SessionBeanSelect-Employee VINCENZO LUCCHESSI"。最后,您自己嘗試一下 selectEmployeeUsingDefaultDatasource 方法。

圖 29. 調用 selectEmployee() 方法

回頁首

結束語

總之,對于不需要動態 SQL 的 Java 和 J2EE 應用程序,SQLJ 是提供持久性框架的一種非常有用的方式。雖然本文沒有提到,但使用 SQLJ 開發存儲過程也是可行的。

回頁首

下載

描述 名字 大小 下載方法

code samples

SQLJArticle_sourcecode.zip

3443 KB

 

FTP

|

HTTP

關于下載方法的信息

Get Adobe® Reader®

參考資料

關于作者

Owen Cline 是位于加州圣地亞哥市的 IBM Software Services for Websphere 小組的一名成員。他有 20 多年軟件開發領域的開發經驗。他擁有 4 項軟件專利,編寫了大量 IBM 紅皮書,并曾多次出席各種技術會議。在過去的 5 年當中,Owen 專門從事 J2EE 架構、應用開發和部署,重點研究了 WebSphere 平臺。此外,這幾年來,他還參與了許多高知名度的 Web 站點的開發。

 

源文檔 <http://www.ibm.com/developerworks/cn/db2/library/techarticles/dm-0412cline/index.html>

 



dyerac in java... 2007-07-09 21:51 發表評論
]]>
Developing a UDR with Embedded SQLhttp://m.tkk7.com/dyerac/articles/129141.htmldyerac in java...dyerac in java...Mon, 09 Jul 2007 13:48:00 GMThttp://m.tkk7.com/dyerac/articles/129141.htmlhttp://m.tkk7.com/dyerac/comments/129141.htmlhttp://m.tkk7.com/dyerac/articles/129141.html#Feedback0http://m.tkk7.com/dyerac/comments/commentRss/129141.htmlhttp://m.tkk7.com/dyerac/services/trackbacks/129141.htmlDeveloping a UDR with Embedded SQL

This section will cover the nuts and bolts of developing a Java UDR with embedded SQL. Our topics will include:

 

Software Requirements

  1. To develop Java UDRs that employ embedded SQL, the first thing you'll need is version 9.21 or later of Informix Foundation. Foundation consists of the Informix database engine, plus a suite of supporting software that includes "Krakatoa", which permits Java routines to run inside the server. Note that 9.20 and earlier versions will not support embedded SQL.
  2. Next, you'll need the Informix JDBC Driver, version 2.1+ . The JDBC Driver can be downloaded free from the Informix download web site. Versions of the JDBC Driver prior to 2.1 will not support embedded SQL.


You'll need the latest version of the Java compiler, JDK 1.2.2 or later. This can be downloaded free from Sun's Java web site.

 

Server Configuration

Your Informix server configuration file (typically, $INFORMIXDIR/etc/onconfig on Unix, or %INFORMIXDIR%\etc\ONCONFIG.<servername> on NT) includes a number of parameters for setting the server's environment to support Krakatoa (a. k. a., "Java-in-the-server"). Most are pre-set in the default configuration file, and most of the information needed to set the rest can be found in the release notes for your platform.

One setting, which is specific to using embedded SQL in Java UDRs, may not be documented in your version of the server: JVPCLASSPATH must include the ifxsqlj.jar (or ifxsqlj-g.jar) file in your JDBC installation, and it must also include the full path to the directory where the .class file for your Java UDR will reside.

On NT, your Krakatoa-related ONCONFIG settings should look something like this:

VPCLASS      jvp,num=1                       # Number of JVPs to start with
            JVPJAVAHOME  D:\informix\extend\krakatoa\jre # JDK installation root directory
            JVPHOME      D:\informix\extend\krakatoa     # Krakatoa installation directory
            JVPLOGFILE   D:\informix\extend\krakatoa\jvp.log    # VP log file
            JVPPROPFILE  D:\informix\extend\krakatoa\.jvpprops  # JVP property file
            JDKVERSION   1.2                  # JDK version supported by this server
            JVMTHREAD    native               # Java VM thread type (green or native)
            # The path to the JRE libraries relative to JVPJAVAHOME
            JVPJAVALIB   \bin\
            # The JRE libraries to use for the Java VM
            JVPJAVAVM    hpi;jvm;java;net;math;zip;jpeg
            # Classpath to use upon Java VM start-up (use _g version for debugging)
            # IMPORTANT: In this sample, the line is broken to fit on a page. In a live
            # ONCONFIG file, your JVPCLASSPATH entry MUST be a single, unbroken line.
            JVPCLASSPATH d:/informix/extend/krakatoa/jdbc.jar;d:/informix/extend/krakatoa/
            krakatoa.jar;d:/java/jdbc211jc1/lib/ifxsqlj.jar;d:/informix/extend/SQLjDemo.1.0

Note that in this example, the Informix installation directory is D:\informix.

Most of the values here were inserted automatically when Foundation was installed. However, it's worth reiterating a couple of comments about JVPCLASSPATH:

  • In any installation where Krakatoa is enabled, JVPCLASSPATH will include the path to the jdbc.jar and krakatoa.jar (or their debugging equivalents) in $INFORMIXDIR/extend/krakatoa. If you are going to use embedded SQL, however, you must add the full path to the ifxsqlj.jar file in your JDBC installation.
  • SQLj standards call for your Java routines to be bundled in .jar files, and for those .jar files to be stored in the database by means of the install_jar() SQL routine. The corresponding SQL routine is then mapped to the stored .jar file.

    For any Java UDR, an alternative to this approach is to map your SQL routine directly to the .class file for your Java implementation, and enable the server to find your .class file by naming its directory in your server's JVPCLASSPATH variable.

    At the time of this writing, Java UDRs that include embedded SQL must use the latter method.
  • JVPCLASSPATH is (at the time of this writing) limited to 256 characters. If you include a large number of directories where .class files will be stored, then you may overrun this limit, and your UDR will fail at runtime.

    An alternative syntax allows you to specify JVPCLASSPATH as the name of a file, for instance:

    JVPCLASSPATH file:d:/informix/extend/krakatoa/classpath.txt

    The content of classpath.txt takes exactly the same format as the text in your server configuration file would: full pathnames separated by semicolons on NT, or colons on Unix, all on a single line. In this case, however, the length of the line is not limited to 256 characters.

Development Environment

Developing a Java UDR that uses embedded SQL is not much different from developing any other Java UDR:

  • You'll need access to JDK 1.2.x (1.2.x is compatible with the Java Runtime Environment (JRE) that is included with Krakatoa), so you'll need to set your PATH environment variable to include the "bin" directory of your JDK installation.
  • You'll want to have access to your Informix installation, so that you can test your UDR-in-progress. This means having INFORMIXDIR set to point to the root of your Informix installation, and including $INFORMIXDIR/bin in your PATH.

However, there's one additional requirement:

  • Set CLASSPATH to include each of the .jar files in the lib directory of your JDBC installation. You can use either the debug versions, whose names end with "-g.jar", or the optimized versions.

Runtime Environment

Other than configuring your server as described above, there are no special runtime requirements for using Java UDRs with embedded SQL.

Embedded SQL Syntax

This paper can present only the barest minimum of information about embedded SQL syntax, but it does seem appropriate to take a quick look at it here. Much more information about SQLj syntax can be found in the demo programs included with the Informix JDBC Driver distribution. Remember, however, when reviewing those demos, that they are client applications, and are not server-side Java routines.

In this section, we'll look at:




Filenames

As with other Java programs, the names of those using embedded SQL are case sensitive. The precompiler will generate a .java file with the same name prefix, and the compiler will generate a .class file with the same name prefix.

The filename extension used for Java embedded SQL programs is ".sqlj".

SQLj import files

Your "import" list must include:

  1. java.sql.* (Since you will be using SQL to access a database.)
  2. com.informix.jdbc.* (The precompiler translates your SQL statements into JDBC calls.)
  3. sqlj.runtime.* (To provide runtime support for sqlj.)
  4. sqlj.runtime.ref.DefaultContext (For access to the underlying routines that establish your database connection.)

 




Establishing a Database Connection

In a client application using Java embedded SQL, there are a lot of options for establishing database connections, including multiple concurrent connections to several databases or server installations. To support this flexibility, SQLj uses the concept of a "context" to extend the simpler idea of a "connection", and it provides a whole range of classes and methods for managing "contexts".

Since a UDR runs inside the server, it only needs a "DefaultContext". You get a DefaultContext from a database connection that is obtained by using the JDBC DriverManager.getConnection() call, and supplying a "direct connection" database URL:

public static Connection conn = null;
            public static String DRIVER = "com.informix.jdbc.IfxDriver";
            public static String DBURL = "jdbc:informix-direct";
            ...
            public static Connection newConnection() throws SQLException {
            // Load the JDBC driver
            try {
            Class.forName( DRIVER );
            }
            ...
            // Get a database connection
            try {
            conn = DriverManager.getConnection (DBURL);
            }
            ...
            // Use the connection to get a connection context
            DefaultContext ctx = DefaultContext.getDefaultContext();
            try {
            ctx = new DefaultContext(newConnection());
            }
            ...
            }   

Please refer to the downloadable demo for a complete example.

Embedded SQL syntax

Once you have established a database connection, and obtained a DefaultContext, accessing information stored in a database is simple. You'll need a program variable of the appropriate type to receive the data, and an SQL statement to retrieve it.

If you have a table like this:

          CREATE TABLE excuses (id integer, words lvarchar);
            INSERT INTO excuses VALUES (1, "Dog ate my homework");
            INSERT INTO excuses VALUES (2, "Missed the bus");
            INSERT INTO excuses VALUES (3, "I Forgot!"); 

Then you could retrieve the text of an excuse into a program variable like this:

          ...
            String excuse = new String();
            #sql {
            SELECT words
            INTO :excuse
            FROM excuses
            WHERE id = 3
            }; 

Note that the program variable "excuse" is preceeded by a colon when used in the SQL statement. It's important to note, too, the placement of the semicolon that terminates the SQL statement: It follows the closing bracket.

Complete information about mapping Informix data types to JDBC data types can be found in the Informix JDBC Driver Programmer's Guide, which is included with your JDBC distribution.

Compiling Embedded SQL Java Programs

Compiling a Java UDR containing embedded SQL is simple, and is identical to compiling a client application that contains embedded SQL. If your source file is "Foo.sqlj", then compile it like this:

java ifxsqlj Foo.sqlj

ifxsqlj will precompile Foo.sqlj into Foo.java, then will call javac to compile Foo.java into Foo.class.

Along the way, two additional files are generated:

  • Foo_SJProfile0.ser
  • Foo_SJProfileKeys.class

These files contain hooks for vendor-specific customizations, as provided by the SQLj standards. In this way, vendors can optimize the implementation of embedded SQL statements for their own database products, and still retain a vendor-neutral, portable compiled object.

Tip: In the current release of the SQLj package, ifxsqlj may hang and produce no feedback at all if it encounters certain syntax errors in your code. If this happens, break out with ^C, then try to compile the generated .java file manually: javac Foo.java . The javac compiler will flag the errors in the .java file, and you can trace them back to your .sqlj code.

All three of the files generated by a successful compile will need to be made available to the server at runtime, by placing them in a directory named in your server's JVPCLASSPATH entry.

Deploying a Java UDR That Uses Embedded SQL

The hard part is done now: You've written your UDR and successfully compiled it. Now all you need to do is "register it to a database", which amounts to mapping it to an SQL routine.

Let's assume we have a "bladelet" with a single routine, "Foo()". Let's also assume we're going to follow the convention that most DataBlades do, and store our "Foo" files in "$INFORMIXDIR/extend/Foo". We'll call the script that maps our "Foo" Java routine to an SQL "Foo" routine -- that "registers the UDR to the database" -- "register.sql".

Following this convention, $INFORMIXDIR/extend/Foo will contain:

  • register.sql
  • Foo.class
  • Foo_SJProfileKeys.class
  • Foo_SJProfile0.ser

Your register.sql script looks like this:

create procedure testmain()
            external name 'Foo.Foo()'
            language java; 

The first "Foo" in the "external name" identifies the Java class, and the second "Foo" refers to the method name within that class.

How does the server find the class? It looks in each of the directories named in its JVPCLASSPATH variable until it finds the one with the name "Foo.class". If we've remembered to include d:\informix\extend\Foo in our JVPCLASSPATH entry, the server will find it.

IBM, DB2, Informix, and WebSphere are trademarks or registered trademarks of IBM Corporation in the United States, other countries, or both.

Windows and Windows NT are registered trademarks of Microsoft Corporation in the United States, other countries, or both.

Java and all Java-based trademarks and logos are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States, other countries, or both.

Other company, product, and service names may be trademarks or service marks of others.



dyerac in java... 2007-07-09 21:48 發表評論
]]>
Vi指令大全http://m.tkk7.com/dyerac/articles/129135.htmldyerac in java...dyerac in java...Mon, 09 Jul 2007 12:36:00 GMThttp://m.tkk7.com/dyerac/articles/129135.htmlhttp://m.tkk7.com/dyerac/comments/129135.htmlhttp://m.tkk7.com/dyerac/articles/129135.html#Feedback0http://m.tkk7.com/dyerac/comments/commentRss/129135.htmlhttp://m.tkk7.com/dyerac/services/trackbacks/129135.htmlVi指令大全

Wikipedia,自由的百科全書

目錄 [隱藏]

 

進入vi的命令

vi filename: 打開或新建文件,并將光標置于第一行首

vi +n filename: 打開文件,并將光標置于第n行首

vi + filename: 打開文件,并將光標置于最后一行首

vi +/pattern filename: 打開文件,并將光標置于第一個與pattern匹配的串處

vi -r filename: 在上次正用vi編輯時發生系統崩潰,恢復filename

vi filename....filename: 打開多個文件,依次進行編輯

 

移動光標類命令

h: 光標左移一個字符

l: 光標右移一個字符

space: 光標右移一個字符

Backspace: 光標左移一個字符

k或Ctrl+p: 光標上移一行

j或Ctrl+n: 光標下移一行

Enter: 光標下移一行

w或W : 光標右移一個字至字首

b或B : 光標左移一個字至字首

e或E : 光標右移一個字至字尾

): 光標移至句尾

(: 光標移至句首

}: 光標移至段落開頭

{: 光標移至段落結尾

nG: 光標移至第n行首

n+: 光標下移n行

n-: 光標上移n行

n$: 光標移至第n行尾

H: 光標移至屏幕頂行

M: 光標移至屏幕中間行

L: 光標移至屏幕最后行

0: 光標移至當前行首

$: 光標移至當前行尾

屏幕翻滾類命令

Ctrl+u: 向文件首翻半屏

Ctrl+d: 向文件尾翻半屏

Ctrl+f: 向文件尾翻一屏

Ctrl+b: 向文件首翻一屏

nz: 將第n行滾至屏幕頂部,不指定n時將當前行滾至屏幕頂部。

插入文本類命令

i: 在光標前

I: 在當前行首

a: 光標后

A: 在當前行尾

o: 在當前行之下新開一行

O: 在當前行之上新開一行

r: 替換當前字符

R: 替換當前字符及其后的字符,直至按ESC鍵

s: 從當前光標位置處開始,以輸入的文本替代指定數目的字符

S: 刪除指定數目的行,并以所輸入文本代替之

ncw或nCW: 修改指定數目的字

nCC: 修改指定數目的行

刪除命令

ndw或ndW: 刪除光標處開始及其后的n-1個字

do: 刪至行首

d$: 刪至行尾

ndd: 刪除當前行及其后n-1行

x或X: 刪除一個字符,x刪除光標后的,而X刪除光標前的

Ctrl+u: 刪除輸入方式下所輸入的文本

搜索及替換命令

/pattern: 從光標開始處向文件尾搜索pattern
?pattern: 從光標開始處向文件首搜索pattern
n: 在同一方向重復上一次搜索命令
N: 在反方向上重復上一次搜索命令
:s/p1/p2/g: 將當前行中所有p1均用p2替代
:n1,n2s/p1/p2/g: 將第n1至n2行中所有p1均用p2替代
:g/p1/s//p2/g: 將文件中所有p1均用p2替換

選項設置

all: 列出所有選項設置情況

term: 設置終端類型

ignorance: 在搜索中忽略大小寫

list: 顯示制表位(Ctrl+I)和行尾標志($)

number: 顯示行號

report: 顯示由面向行的命令修改過的數目

terse: 顯示簡短的警告信息

warn: 在轉到別的文件時若沒保存當前文件則顯示NO write信息

nomagic: 允許在搜索模式中,使用前面不帶“\”的特殊字符

nowrapscan: 禁止vi在搜索到達文件兩端時,又從另一端開始

mesg: 允許vi顯示其他用戶用write寫到自己終端上的信息

最后行方式命令

:n1,n2 co n3: 將n1行到n2行之間的內容拷貝到第n3行下
:n1,n2 m n3:將n1行到n2行之間的內容移至到第n3行下
:n1,n2 d: 將 n1行到n2行之間的內容刪除
:w: 保存當前文件
:e filename: 打開文件filename進行編輯
:x: 保存當前文件并退出
:q: 退出vi
:q!: 不保存文件并退出vi
:!command: 執行shell命令command
:n1,n2 w!command: 將文件中n1行至n2行的內容作為command的輸入并執行之,
若不指定n1,n2,則表示將整個文件內容作為command的輸入 :r!command: 將命令command的輸出結果放到當前行

寄存器操作

"?nyy: 將當前行及其下n行的內容保存到寄存器?中,其中?為一個字母,n為一個數字

"?nyw: 將當前行及其下n個字保存到寄存器?中,其中?為一個字母,n為一個數字

"?nyl: 將當前行及其下n個字符保存到寄存器?中,其中?為一個字母,n為一個數字

"?p: 取出寄存器?中的內容并將其放到光標位置處。這里?可以是一個字母,也可以是一個數字

ndd: 將當前行及其下共n行文本刪除,并將所刪內容放到1號刪除寄存器中



dyerac in java... 2007-07-09 20:36 發表評論
]]>
(zt)現在你可以定義自己的語言!http://m.tkk7.com/dyerac/articles/129134.htmldyerac in java...dyerac in java...Mon, 09 Jul 2007 12:34:00 GMThttp://m.tkk7.com/dyerac/articles/129134.htmlhttp://m.tkk7.com/dyerac/comments/129134.htmlhttp://m.tkk7.com/dyerac/articles/129134.html#Feedback0http://m.tkk7.com/dyerac/comments/commentRss/129134.htmlhttp://m.tkk7.com/dyerac/services/trackbacks/129134.html閱讀全文

dyerac in java... 2007-07-09 20:34 發表評論
]]>
(zt)利用 DB2 UDB 來使用 Java CachedRowSet 實現http://m.tkk7.com/dyerac/articles/129133.htmldyerac in java...dyerac in java...Mon, 09 Jul 2007 12:32:00 GMThttp://m.tkk7.com/dyerac/articles/129133.htmlhttp://m.tkk7.com/dyerac/comments/129133.htmlhttp://m.tkk7.com/dyerac/articles/129133.html#Feedback0http://m.tkk7.com/dyerac/comments/commentRss/129133.htmlhttp://m.tkk7.com/dyerac/services/trackbacks/129133.html 

利用 DB2 UDB 來使用 Java CachedRowSet 實現

斷開連接

將此頁作為電子郵件發送

未顯示需要 JavaScript 的文檔選項

樣例代碼

級別: 初級

Kulvir Singh Bhogal (kbhogal@us.ibm.com), IBM Software Services for WebSphere, IBM Corporation

2004 年 8 月 01 日

高速緩存行集(Cached Row Set)是 Java™ 1.5 提供的一項新功能,源自 JSR114 的努力。這一新功能使您可以擁有一個可串行化的斷開連接的對象。這意味著您可以連接到數據庫,以結果集的形式取得數據,釋放連接并在本地操縱這些數據,然后恢復連接以完成事務,這樣可以大大減少對連接和服務器資源的使用。本文展示這一切是如何利用 DB2® Universal Database™ 來實現的,并包含示例代碼。

簡介

應該把數據庫連接看作是一種被應用程序廣泛使用的寶貴資源。尤其是在高流量的 Web 站點中,客戶機應該使用由應用程序服務器(例如,IBM WebSphere® Application Server)管理的數據庫連接池中的數據庫連接,并在其必要的事務發生之后釋放數據庫連接,這一點很重要。

在許多情況下,事務會話會持續較長一段時間,占用著數據庫連接,直到完成。過去,Java 程序員一直使用沒有高速緩存解決方案的 JDBC API。高速緩存解決方案允許用戶在本地高速緩存結果集,釋放連接,操縱結果集數據,并在稍后的時間點與數據庫同步。在本文中,我將介紹 javax.sql.RowSet 接口的實現,該實現允許我們實現高速緩存解決方案。

回頁首

獲得 RowSet 實現

javax.sql.RowSet 接口是在 J2SE Version 1.4 中引入到 Java 語言的。隨著 Java 2 Standard Edition version 1.5 的發布,我們將會看到該接口的增強和綁定到語言的接口實現。 RowSet 接口是 JSR 114的結果,JSR 114 勾勒了一個方案,也就是“將表格數據與數據源分隔開……”,從而增加“應用程序的可擴展性和編程模型的靈活性”。我使用 beta 版本的 Tiger (Java 1.5) 來進行開發。如果您使用的是以前版本的 Java,應該嘗試 RowSet 的參考實現,可以 從 Sun Microsystems 下載參考實現。對于我們的例子,我們將利用 CachedRowSet 實現。

回頁首

您以前看到過 RowSet 實現

本文中突出展示的 CachedRowSetImpl 類是 javax.sql.Rowset 接口的一個實現。 javax.sql.Rowset 擴展了 java.sql.ResultSet 接口。因此,如果您熟悉 javax.sql.ResultSet 接口,我是這樣假設的,那么您會認出 CachedRowSetImpl 提供的許多方法。 java.sql.RowSet 接口提供您在標準 JDBC 2.0 ResultSet 中看到過的所有方法;附加價值是,我們不需要連續使用數據庫連接。就相當于我們可以走進商店,取走商品目錄之后進行挑選,然后再帶著填好的訂單回到商店。

回頁首

使用 CachedRowSet

CachedRowSet 是一個 JavaBean。您可以通過使用現有的 ResultSet 對象,或者通過指定連接連接信息和 SQL 查詢,來填充 CachedRowSet 。我們采用后一種方法。但是,首先為我們的沙箱創建一個小的 DB2 數據庫。

db2 => create database cachedex

我假設在您的機器上具有一個叫做 db2admin 的用戶,口令為 db2admin:

db2=> connect to cachedex user db2admin using db2admin

創建一個名為 cachetbl 的表:

db2=> create table cachetbl (id int primary key not null, firstname varchar(40) not null, lastname varchar(40) not null)

然后用以下行填充該表:

insert into cachetbl values (12345,’Kulvir’,’Bhogal’)
insert into cachetbl values (23456,’Meet’,’Feona’)
insert into cachetbl values (34567,’Bicky’,’Singh’)

我提供的示例代碼建立一個到 DB2 的直接連接。如果您是通過由應用程序服務器(比如 IBM WebSphere Application Server)管理的池獲得數據庫連接,那么可以使用 execute 方法的另一種形式,該方法利用 java.sql.Connection 對象作為參數。通過閱讀我的相關主題的文章 Using Data Sources the Right Way,可以更多地了解使用數據源 —— 一種 J2EE 最佳實踐。

回頁首

可串行化

javax.sql.RowSet 的實現可以被串行化。對于處理 Enterprise Java Beans 的程序員來說,這是一個比較好的消息。標準 JDBC 2.0 ResultSets 是不可串行化的,這使得是否需要使用定制對象,以便 ResultSet 數據可以被發送回 EJB 設置中的客戶機以進行操縱或查詢,成了一個爭論。有了 RowSet 實現的出現,我們就可以串行化 ResultSets ,將它們發送到我們的客戶機,然后我們的客戶機可以讀取和更新 ResultSet ,并將它發送回服務器。

回頁首

可滾動

CachedRowSetImpl 實現是可滾動的,所以允許您在 RowSet 給出的記錄集中向前和向后滾動。這在 JDBC 2.0 ResultSet 中是允許的。但是以前,在滾動發生期間必須維護一個會話。現在,我們可以在離線數據中滾動了。

回頁首

作一個數據完整性的樂天派

您可能會想,如果在客戶機 A 將更改與數據庫服務器進行同步之前,客戶機 A 上緩存的數據被另一個客戶機(客戶機 B)操縱,那將會發生什么事情。 CachedRowSet 的默認實現不對數據庫服務器維護鎖。參考實現使用樂觀的同步。具體地說就是,如果客戶機 A 試圖操縱的數據在數據庫服務器上沒有更改,那么更新將會被數據庫接受。但是,如果在次期間目標數據被更改,就會拋出一個同步異常。注意,這種樂觀方法也是參考實現處理并發性的方式。其他實現可能采取不同的并發策略;規范并不強制要求使用某個特定的并發模型。

回頁首

查看起作用的東西

我提供了一個 示例程序,該程序演示了 CachedRowSetImpl 提供的一些功能。這些代碼都可以在文件 DisconnectedExample.java 中找到。我將解釋該程序的一些部分,以便您可以理解我想要傳達的內容。注意,要運行示例應用程序,需要在運行時類路徑中包含 DB2 Universal JDBC 驅動程序 (db2jcc.jar)。還需要包含 db2jcc_license_cu.jar 文件。關于設置環境的更多信息,請參考我的文章: Hooking Up with DB2 Universal Database Version 8 using Java

Class.forName("com.ibm.db2.jcc.DB2Driver");
CachedRowSet crs = new CachedRowSetImpl();
crs.setUsername("db2admin"); crs.setPassword("db2admin"); crs.setUrl("jdbc:db2://localhost:50000/cachedex"); crs.setCommand("SELECT id,firstname,lastname from cachetbl");
crs.execute();
System.out.println("---------------------------");
// display size of cached row set
System.out.println("Size: " + crs.size() + " records");
// display records in cachedrowset
while (crs.next())
{
System.out.println(crs.getRow() + " - " + crs.getString("firstname") + " " + crs.getString("lastname"));
}
System.out.println("---------------------------");

在上面的代碼中,我創建了一個 com.sun.rowset.CachedRowSetImpl 對象。注意我是如何為 CachedRowsetImpl 對象指定數據庫連接信息的。我用 setCommand 方法來指定想要執行的查詢。當發出 execute 方法時,就會填充 CachedRowSetImpl 對象。就是在該方法調用中,我們獲得然后再關閉數據庫連接。然后我可以在對象中迭代,并使用 getter 方法來抽取和報告其中包含的數據。

正如前面所提到的, CachedRowSetImpl 對象是可滾動的。下面的代碼例示了這項功能,我在該代碼中使用 last()previous() 方法在數據間前后滾動。

System.out.println("Showcase scrollability");
// move backwards through rowset
// scroll to last row
crs.last();
// iterate to next row
while (crs.previous())
{
// report current row contents
System.out.println(crs.getRow() + " - " + crs.getString("lastname"));
}

方法 first()next() 也可用于在數據間滾動。

為了演示從數據庫斷開連接的能力,示例程序設計為暫停,并讓您實際地執行生動的操作,即停止 DB2,以真正了解 CachedRowSet 功能的優勢。在繼續操作(由完成 BufferedReader 對象的一個簡單 readLine 而推動)之前,應用程序等待按下任意鍵。當示例程序提示您停止 DB2 時,可以在一個新的 DB2 命令行處理器窗口中使用下面的命令:

db2 force applications all

然后再使用

db2stop

來強迫 DB2 的停止。

盡管數據庫已經停止,但是下面的代碼必須執行:

System.out.println("Demonstration of how to update cached row set"); crs.updateString("lastname","Kaur");
// commit changes to cached portion of rowset
crs.updateRow();
System.out.println(crs.getRow() + " - " + crs.getString("lastname"));

在上面的代碼中,我們更改了當前行條目的 last name 字段。注意,對 CachedRowSetImpl 對象使用了 updateRow() 方法,以記錄對該對象的更改。在這一時間點,數據庫還沒有被更新。正如您可以回想起的,數據庫 甚至沒有運行。應用程序將提示您啟動 DB2。為此,可以從 DB2 命令行處理器發出下面的命令:

db2start

在 DB2 啟動之后,按任意鍵繼續示例應用程序。

此時,下面的代碼將會運行,這將有效地在數據庫中同步更改。

crs.acceptChanges();

通過對 cachetbl 執行一個選擇查詢,可以確認數據庫實際上已經更新,如 圖 1所示:

圖 1. 確認更新更改已經與數據庫同步

為了結束我們對 CachedRowSet 的動手研究,示例應用程序還演示了如何插入和刪除行。要執行插入,必須將光標移動到一個叫做“插入行”的特殊位置。在這里,我們使用更新方法來填充新行。當我們使用 insertRow() 方法時, CachedRowSetImpl 對象就會被更新。當執行 acceptChanges() 方法時,更改就被持久地存儲到數據庫中。

以下代碼演示了這一點:

// move the cursor to a blank row crs.moveToInsertRow();
// populate the new row
crs.updateInt(1,01234);
crs.updateString(2,"Judith");
crs.updateString(3,"Smith");
// insert the new row
crs.insertRow();
// move cursor back to previous position
crs.moveToCurrentRow();
// synchronize changes to database
crs.acceptChanges();

在插入完成之后程序將會暫停,以允許您在數據庫中查詢插入。

從對象刪除行相當直觀。只需要將光標定位到想要刪除的地方,然后使用 deleteRow 方法即可。跟前面一樣,需要一個后續的同步,以將更改持久存儲到數據庫中:

// delete row (where the cursor is currently positioned)
crs.deleteRow();
// synchronize changes to database
crs.acceptChanges();

回頁首

只是一種實現

讀者應該注意, javax.sql.RowSet 接口的 CachedRowSetImpl 實現只是一種實現(更確切地說是參考實現)。其他供應商也擁有 RowSet 的實現,這些實現與參考實現處理問題(比如數據完整性)的方式可能會不同(例如,第三方實現可能會對服務器進行鎖維護)。

回頁首

普遍含義

可更新的“斷開連接的” ResultSets 在普遍世界中具有各種含義,其中,網絡連接可以是斷斷續續的。使用 CachedRowSet 可以允許客戶機在連接可用時將數據緩存在本地,然后重新連接,以同步對數據執行的更改。

回頁首

謹慎使用

斷開連接具有其優點。但是用戶必須理解,斷開連接的對象是保存在內存中。因此,不應該使用具有大型結果集的方法。大型結果集的相應更新和滾動會是耗資源的操作。

回頁首

結束語

與標準 JDBC 2.0 ResultSet 不一樣,利用 CachedRowSet 不再需要連續使用數據庫連接。因為數據庫連接池中的數據庫連接是寶貴的資源,所以連接數據庫、斷開連接,然后重新連接以便同步數據庫,這種能力無疑是非常受歡迎的。

回頁首

致謝

作者感謝 IBM Life Sciences Development 的 Richard Dettinger 對本文的審稿。

回頁首

下載

名字 大小 下載方法

DisconnectedExample.java

4.03 KB

HTTP

關于下載方法的信息

Get Adobe® Reader®

參考資料

關于作者

Kulvir Singh Bhogal 是一名 IBM 顧問,他為全國性的客戶網站設計和實現以 Java 為中心的解決方案。 .

 

源文檔 <http://www.ibm.com/developerworks/cn/db2/library/techarticles/dm-0406bhogal/index.html>

 



dyerac in java... 2007-07-09 20:32 發表評論
]]>
主站蜘蛛池模板: 亚洲jjzzjjzz在线观看| 日本特黄特黄刺激大片免费| a在线免费观看视频| AAAAA级少妇高潮大片免费看| 香蕉视频免费在线播放| 边摸边吃奶边做爽免费视频网站| 在线观看亚洲视频| 久久精品国产亚洲AV天海翼| 男女男精品网站免费观看| 野花高清在线观看免费完整版中文 | 久久青草91免费观看| 曰批全过程免费视频在线观看无码| 99re6在线精品免费观看| 久久久久久免费一区二区三区| 欧洲人免费视频网站在线| 91热久久免费精品99| 无码人妻一区二区三区免费手机 | 色多多免费视频观看区一区| 免费看又黄又爽又猛的视频软件| 特级毛片在线大全免费播放| 亚洲另类古典武侠| 精品亚洲国产成人| 亚洲AV无码一区二区乱子仑 | 亚洲另类无码专区丝袜| 亚洲电影一区二区| 亚洲成人黄色网址| 亚洲日本久久久午夜精品| 亚洲av最新在线观看网址| 一级毛片免费全部播放| 美女被cao网站免费看在线看| 18女人腿打开无遮掩免费| 无码一区二区三区免费视频| 午夜国产羞羞视频免费网站| 美腿丝袜亚洲综合| 亚洲导航深夜福利| 国产亚洲视频在线观看| 成人无码a级毛片免费| 台湾一级毛片永久免费| 深夜国产福利99亚洲视频| 国产亚洲欧洲精品| 亚洲一区二区三区无码国产 |