欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
用數據庫框架控制開(kāi)發(fā)環(huán)境

用數據庫框架控制開(kāi)發(fā)環(huán)境




本文從數據庫管理員的角度,討論了保護數據庫的重要性。作者建議通過(guò)添加Java數據庫框架,在開(kāi)發(fā)人員和數據庫之間構建一個(gè)經(jīng)過(guò)反復試驗的穩固的中間層,以降低風(fēng)險,并提供跟蹤及報告問(wèn)題的工具。

沒(méi)有什么比這樣一只Java開(kāi)發(fā)小組更影響數據庫性能的了:他們有一堆需求,又要使用數據庫,但卻僅僅了解了一些Java數據庫連接(JDBC)的皮毛。連接會(huì )打開(kāi)并閑置好幾個(gè)小時(shí),一旦連接超時(shí),問(wèn)題就會(huì )扔給數據庫管理員(DBA)。未關(guān)閉的語(yǔ)句和占用系統資源的結果將是數據庫管理員頭痛的問(wèn)題。編程人員使用含糊的JDBC方法和動(dòng)態(tài)SQL導致性能低下。

因此,本文討論了如何使用Java數據庫框架幫助數據庫遠離隨意操作的開(kāi)發(fā)人員。它提供了連接池和管理、跟蹤及報告JDBC對象、有選擇地刪除性能低下的結構和方法。目的在于防止開(kāi)發(fā)人員影響性能、避免沾上常見(jiàn)的不良開(kāi)發(fā)習慣,并且在無(wú)法防止這類(lèi)活動(dòng)的情況下提供跟蹤機制。這樣一來(lái),數據庫管理員就可以找到問(wèn)題的根源,在系統進(jìn)入生產(chǎn)環(huán)境之前改正問(wèn)題。使用Java數據庫框架的另一個(gè)目的在于,讓一切開(kāi)發(fā)工作都保持簡(jiǎn)單,那樣開(kāi)發(fā)人員就可以盡快熟悉情況。

與任何框架一樣,Java數據庫框架的目的在于隱藏復雜性,并為處理復雜任務(wù)提供一套標準操作程序。同樣重要的一個(gè)方面是讓執行任務(wù)的方式具有一致性。這可以改進(jìn)封裝、大大提高代碼的可維護性。只要設想一下:假如每個(gè)人都構建各自的類(lèi)和方法來(lái)建立數據庫連接,勢必會(huì )導致混亂、無(wú)序的局面。除了數據庫外,框架通常適用的一些方面包括:進(jìn)程間通信、多線(xiàn)程管理和圖形用戶(hù)界面(GUI)標準。

本文描述的框架旨在供所有中間件開(kāi)發(fā)人員使用,它在由數據庫開(kāi)發(fā)商提供的實(shí)際的JDBC實(shí)現上添加了一層(如圖1)。

JDBC問(wèn)題和陷阱

記得下面這一點(diǎn)很重要:JDBC是數據庫開(kāi)發(fā)商提供的實(shí)現,但不是所有的實(shí)現都是相同的。但是,在數據庫框架讓?zhuān)_(kāi)發(fā)人員可以在某種程度上讓它們相同。在個(gè)別情況下,同一家開(kāi)發(fā)商提供的JDBC驅動(dòng)程序的各個(gè)版本之間會(huì )存在差異。不同開(kāi)發(fā)商提供的JDBC驅動(dòng)程序免不了總是會(huì )存在差異。差異通常出現在以下幾方面:連接管理;存儲過(guò)程和返回ResultSets;處理ResultSets;元數據支持;因語(yǔ)句和ResultSets未結束而消耗資源;連接未關(guān)閉帶來(lái)的問(wèn)題;性能異常及實(shí)現緩慢;數據庫優(yōu)化器從一個(gè)版本到下一個(gè)版本所出現的變化;數據庫從一個(gè)版本到下一個(gè)版本添加了新特性。

筆者曾有幸參于來(lái)自Sybase和Oracle的JDBC實(shí)現,它們采用的方法形成了鮮明對比。筆者常開(kāi)玩笑說(shuō),Oracle好比是“父親”,Sybase好比是“母親”。如果你在冬天沒(méi)穿衣服就出去,母親會(huì )叫你停下來(lái),穿上衣服,免得感冒;而父親會(huì )一言不發(fā)地看著(zhù),覺(jué)得要是天氣寒冷,你會(huì )曉得自己添衣服。Sybase驅動(dòng)程序在連接、語(yǔ)句和結果集管理方面可以為開(kāi)發(fā)人員做大量工作;而Oracle驅動(dòng)程序只會(huì )做開(kāi)發(fā)人員讓它做的那些事情。如果開(kāi)發(fā)人員沒(méi)有結束語(yǔ)句,它恐怕不會(huì )自動(dòng)結束,也肯定不會(huì )把會(huì )話(huà)、進(jìn)程及打開(kāi)的游標清理干凈。這里不會(huì )去研究哪個(gè)方向是正確的,我們只是為框架添加了代碼,讓它們看上去很相似。

圖2顯示了框架示例,旨在處理上面討論的JDBC問(wèn)題。它還在數據庫上提供了抽象層,那樣開(kāi)發(fā)人員可以更迅速、更安全地訪(fǎng)問(wèn)數據庫。CWDatabase類(lèi)負責管理開(kāi)發(fā)人員的所有訪(fǎng)問(wèn),它利用CWConnectionPool管理連接、利用CWSqlRepository管理SQL字符串。較低級的Connection和Statement類(lèi)都進(jìn)行了封裝,以便提供跟蹤機制,并保證連接重新簽入到連接池后,所有語(yǔ)句和結果集都已關(guān)閉。下文討論了這些類(lèi),隨后討論了比較高級的框架特性,用于跟蹤執行性能、限制JDBC特性及報告連接池。下面的所有框架類(lèi)都以代表筆者所在公司CodeWorks Software的“CW”開(kāi)頭,這樣它們很容易識別。

重要的類(lèi)

數據庫接口類(lèi):CWDatabase和CWParamList

為開(kāi)發(fā)人員添加用于數據庫訪(fǎng)問(wèn)的一個(gè)簡(jiǎn)單類(lèi)。通過(guò)創(chuàng )建框架類(lèi)的實(shí)例,他們可以獲得運行SQL命令及存儲過(guò)程的連接及簡(jiǎn)單方法。異常處理得到了適當的處理及報告;通過(guò)使用CWParamList允許用戶(hù)創(chuàng )建參數列表,數據庫管理員就可以牢牢地控制Java數據類(lèi)型及它們如何綁定到數據庫中的基本數據類(lèi)型。目的在于絕對不允許用戶(hù)直接控制jdbc.Connection實(shí)例。牢牢獲得這種控制權的另一個(gè)好處是,通??梢垣@得很高的數據速率,因為數據庫管理員可以控制數據庫訪(fǎng)問(wèn)。

public class CWDatabase

{

 Connection m_conn = null;

 public CWDatabase()

 {

  m_conn = CWConnectionPool.checkOut();

 }

 public int executeUpdate(String queryName, CWParamList plist)

 public int executeUpdate(String queryName)

 public ResultSet executeQuery(String queryName, CWParamList plist)

 public ResultSet executeQuery(String queryName)

 private void processException(String msg, Throwable ex)

}

有了上述這個(gè)類(lèi),用戶(hù)可以運行如下的簡(jiǎn)單查詢(xún):

public void updateSensorType()

{

 CWDatabase theDB = null;

 try

 {

  // 創(chuàng )建數據庫實(shí)例和參數列表實(shí)例

  theDB = new CWDatabase();

  CWParamList plist = new CWParamList();

  // 添加參數

  plist.addParameter(1,"TYPE1");

  plist.addParameter(2,1);

  plist.addParameter(3,"ACT");

  // 執行更新

  int numupdate = theDB.executeUpdate("sensor.updateSensorType",plist);

 }

 catch( Exception exception )

 {

  CWExceptionReporter.write(this,CWExceptionReporter.FATAL,"Error updating sensor type.");

 }

 finally

 {

  theDB.close();

 }

 return;

} // End方法

連接池:CWConnectionPool

建立連接很費資源,所以通過(guò)重復使用連接,就可以避免每次重新建立連接帶來(lái)的成本。系統啟動(dòng)時(shí),可以為連接池提供可隨時(shí)使用的幾個(gè)連接。用戶(hù)創(chuàng )建數據庫接口類(lèi)的實(shí)例后,連接就會(huì )簽出。用戶(hù)調用關(guān)閉命令后,連接重新簽入,供其他用戶(hù)使用。

雖然重復使用連接是連接池的主要目的,但還有許多其他好處。因為所有連接都在一個(gè)地方加以管理及創(chuàng )建,所以數據庫管理員就能夠嚴格管理隔離級別和數據庫選項。SQL Anywhere在這方面的例子包括:DELAYED_COMMITS、ISOLATION_LEVEL和 COOPERATIVE_COMMITS,以及面向原始設備制造商(OEM)版本的軟件的授權代碼方面的設置。

不過(guò),筆者在建立連接池時(shí)發(fā)現了一個(gè)問(wèn)題,它們會(huì )留下一些“行李(baggage)”。這樣一來(lái),多次重復使用會(huì )漸漸減慢連接速度。而且,筆者根本查不出這個(gè)問(wèn)題的根源,不過(guò)懷疑它與PreparedStatements、ResultSets或者當時(shí)出現的其他某種內部跟蹤機制有關(guān)。鑒于所有連接都由連接池管理,這樣就有可能跟蹤連接存在了多久;重新簽入后,可以“刷新”連接。通過(guò)在過(guò)了限定時(shí)間后丟棄連接,就可以更好地維持很高的性能比率。

這種嚴密跟蹤機制的另一個(gè)好處就是,還可以監控誰(shuí)把連接簽出了、時(shí)間有多久。長(cháng)時(shí)間保持的連接,尤其是作為成員變量,可能會(huì )導致問(wèn)題。如果連接好幾個(gè)小時(shí)都處于休眠狀態(tài),就會(huì )超時(shí),進(jìn)而導致問(wèn)題。有了這種額外的跟蹤機制,數據庫管理員就可以報告誰(shuí)擁有哪個(gè)連接、打開(kāi)狀態(tài)保持了多久。如果知道簽出問(wèn)題連接的那一行代碼,就能找到相應的開(kāi)發(fā)人員,告訴他如何使用框架。因為跟蹤連接需要一定開(kāi)銷(xiāo),筆者在編寫(xiě)框架時(shí)在默認狀態(tài)下禁用了這項特性,不過(guò)測試過(guò)程中可以啟用它。

public class CWConnectionPool

{

 // 維護閑置及簽出列表上的連接

 private static ArrayList m_freePool = null;

 private static HashMap m_outPool = null;

 public CWConnectionPool()

 {

  m_freePool = new ArrayList();

  m_outPool = new HashMap();

 }

 public static void initialize()

 public static synchronized Connection checkOut()

 public static synchronized void checkIn(Connection conn)

 public static void discardConnection(Connection conn)

 private static CWConnection createConnection()

 public static reportConnectionPool()

}

SQL存儲庫:CWSqlRepository

SQL語(yǔ)句最好保存在不同文件中,那樣不必重新編譯代碼就可以修改語(yǔ)句。譬如說(shuō),如果發(fā)現了某個(gè)性能問(wèn)題,經(jīng)過(guò)分析,發(fā)現是數據庫優(yōu)化器選錯了索引,這時(shí)就很容易添加SQL提示。為了管理SQL語(yǔ)句,筆者使用了CWSQLRepository類(lèi)。該存儲庫還允許重復使用代碼;又因為所有SQL語(yǔ)句都在同一個(gè)地方,數據庫管理員就更容易找到可能受模式改變影響的所有語(yǔ)句。

public class CWSqlRepository

{

 private static CWSqlRepository m_SQLRepository;

 private static Properties m_SQLrepositoryTable;

 public static void initialize()

 {

  if (m_SQLRepository == null)

   m_SQLRepository = new CWSqlRepository();

  return;

 }

 private static void loadSQLrepository(String sqlfile)

 public static String getSQLString(String tag)

}

封裝JDBC類(lèi)

說(shuō)到簡(jiǎn)化數據庫訪(fǎng)問(wèn),通過(guò)提供上面討論的那幾個(gè)簡(jiǎn)單類(lèi),就能得到很大成效。不過(guò)說(shuō)到消除JDBC實(shí)現在較低層面上的差異,從事重復工作毫無(wú)意義。只要封裝JDBC類(lèi),就可以處理問(wèn)題、添加功能。JDBC文檔齊全,開(kāi)發(fā)人員很熟悉它,數據庫管理員也是一樣。另外,很容易教人學(xué)會(huì ),并提供合理使用的示例。通過(guò)創(chuàng )建封裝器類(lèi),數據庫管理員可以添加自己需要的任何跟蹤、定時(shí)及報告機制,還可以消除差異。只有在極少數情況下,開(kāi)發(fā)人員才真正知道自己在使用Connection.prepareStatement()的框架實(shí)現,而不是實(shí)際的實(shí)現。

CWConnection

要封裝的最重要的一個(gè)類(lèi)是java.sql.Connection。數據庫管理員可以在這里跟蹤某連接簽出了多久,并維護所有已創(chuàng )建語(yǔ)句的列表。為了調試,數據庫管理員可以維護堆棧跟蹤信息(stack trace)。這樣在建立連接后,一旦發(fā)現“連接濫用”,就能更準確地找到建立該連接的代碼,譬如說(shuō),連接簽出時(shí)間超過(guò)規定。

public class CWConnection implements Connection

{

 // 連接的基本信息

 private Connection _conn = null;

 //封裝的java.sql.Connection

 private int _connNum ;

 // 跟蹤號碼

 private long _createTime;

 // 設定時(shí)間

 private ArrayList _stmtTracker;

 // 跟蹤語(yǔ)句

 public int getConnectionNum()

 public int getElapseTime()

 public void closeStatements()

 private ArrayList getStatementTracker()

 private void clearStatementTracker()

 String reportConnnection()

 // 封裝的JDBC方法

 public Statement createStatement() throws SQLException

  {

   CWStatement stmt = new CWStatement(_conn.createStatement());

   _stmtTracker.add(stmt);

   return stmt;

  }

}

CWStatement、CWPreparedStatement和CWCallableStatement

數據庫管理員可以編寫(xiě)這樣的框架:很少允許開(kāi)發(fā)人員可以控制Statements、CallableStatements和PreparedStatements。封裝這些類(lèi)的主要原因是可以跟蹤時(shí)間設定,如果返回結果集的話(huà),還可以跟蹤ResultSet實(shí)例。雖然在下面討論了串行化的結果集,但筆者并不建議把結果集隱藏起來(lái),不讓開(kāi)發(fā)人員看到,因為接口方面的文檔很齊全。主要的濫用現象就是讓結果集打開(kāi)著(zhù),不過(guò)對此進(jìn)行跟蹤卻相當簡(jiǎn)單。連接簽入后,所有語(yǔ)句都被關(guān)閉,每個(gè)語(yǔ)句保證結果集被關(guān)閉。筆者仍封裝了ResultSet,但主要目的是消除性能低下的方法,那樣開(kāi)發(fā)人員就沒(méi)法用它們。稍后會(huì )討論這個(gè)話(huà)題。

public class CWStatement implements Statement

{

 // 語(yǔ)句的基本信息

 private Statement m_stmt = null;

 //封裝的java.sql.Statement

 private int m_stmtNum;

 // 跟蹤號碼

 private long m_createTime;

 // 設定時(shí)間

 protected ResultSet m_rsTracker;

 // 跟蹤結果集

 private String m_sqlTracker;

 // 隨該語(yǔ)句一起發(fā)出的Sql

 public String reportStatement()

 public CWStatement( Statement stmt, int stmtNum)

 {

  m_stmt = stmt;

  m_stmtNum = stmtNum;

  m_createTime = System.currentTimeMillis();

  m_sqlTracker = null;

  m_rsTracker = null;

 }

 public ResultSet executeQuery(String sql) throws SQLException

 {

  CWResultSet rs = new CWResultSet(m_stmt.executeQuery(sql));

  m_rsTracker = rs;

  m_sqlTracker = sql;

  return rs;

 }

}

框架的先進(jìn)思想

上面討論的話(huà)題集中于簡(jiǎn)化數據庫接口、連接管理,并提供防范常見(jiàn)JDBC問(wèn)題的方法。接下來(lái)會(huì )介紹框架的附加部分,它們?yōu)楸O控及控制使用數據庫的開(kāi)發(fā)人員提供了更有效的機制,包括:解決結果集的問(wèn)題、限制性能低下的操作、監控SQL性能。

CWResultSetSerialized

許多Java編程人員沒(méi)有認識到(或者忘了)ResultSets實(shí)際上是數據庫游標。它們傳遞引用、把它們存儲為成員變量,往往從不關(guān)閉,因而占用了數據庫資源。為了消除所有風(fēng)險,可利用JDBC結果集來(lái)創(chuàng )建串行化的結果集。這還可以讓結果集通過(guò)遠程方法調用(RMI)在進(jìn)程之間發(fā)送。

在極端情況下,引起阻塞問(wèn)題的結果集頻頻傳送,以至筆者查不到該在什么地方關(guān)閉它。一旦用串行化的結果集取而代之,就能關(guān)閉實(shí)際的ResultSet,所有問(wèn)題都立馬消失了。串行化結果集的任何實(shí)現都需要限制可以創(chuàng )建的行數,因為100萬(wàn)行的串行化結果集會(huì )引起性能問(wèn)題。筆者開(kāi)始限制在5000行。

下面的代碼表明了結果集管理不善,因為它傳到了方法外面?,F在很難知道它是不是被關(guān)閉了,因為方法只有出現了錯誤才關(guān)閉數據庫實(shí)例。代碼可以使用,不過(guò),要是結果集在調用方法里面沒(méi)有關(guān)閉,連接會(huì )處于簽出狀態(tài),游標仍然是打開(kāi)的。

public ResultSet getAllSensors()

{

 CWDatabase theDB = null;

 ResultSet rs = null;

 try

 {

  // 創(chuàng )建數據庫實(shí)例和參數列表實(shí)例

  theDB = new CWDatabase();

  // 執行查詢(xún)

  rs = theDB.executeQuery("sensor.getAllSensors");

 }

 catch( Exception exception )

 {

  CWExceptionReporter.write(this,CWExceptionReporter.FATAL,"Error during query: " + " sensor.getAllSensors ");

  theDB.close();

 }

 return rs;

} // End方法

因為有時(shí)在開(kāi)發(fā)周期很晚時(shí)才發(fā)現這類(lèi)問(wèn)題,因而無(wú)法通過(guò)改寫(xiě)方法來(lái)解決,可以通過(guò)以下辦法解決問(wèn)題:傳回串行化的結果集,通過(guò)finally塊關(guān)閉數據庫實(shí)例,從而保證一切都正常關(guān)閉。筆者仍認為,數據庫管理員應當給引起問(wèn)題的工程師出難題,不過(guò)系統代碼凍結前一天不是改變大量代碼的時(shí)候。所作的變化用下面的黑體字表明:

public ResultSet getAllSensors()

{

 CWDatabase theDB = null;

 CWResultSetSerialized rss = null;

 try

 {

  // 創(chuàng )建數據庫實(shí)例和參數列表實(shí)例

  theDB = new CWDatabase();

  // 執行更新

  ResultSet rs = theDB.executeQuery("sensor.getAllSensors");

  rss = new ResultSetSerialized(rs);

 }

 catch( Exception exception )

 {

  CWExceptionReporter.write(this,CWExceptionReporter.FATAL,"Error during query: " + " sensor.getAllSensors ");

 }

 finally

 {

  theDB.close();

 }

// 返回串行化結果集

return rss;

} // End方法

性能級別

因性能需求不同,數據庫管理員的要求可能大不相同,有的是“只允許速度最快的數據庫訪(fǎng)問(wèn)”,有的是“我不在乎訪(fǎng)問(wèn)速度,只要可以使用任何特性”。大部分人介于兩者之間。 能夠“關(guān)閉”已知性能低下的JDBC方法大有幫助。譬如說(shuō),使用ResultSet.update()比使用不同的Statement.execute()來(lái)執行同樣的更新慢得多。允許用戶(hù)使用rs.last()等方法返回不是“只能向前移動(dòng)的”結果集也很慢。筆者使用三個(gè)基本的性能級別:

● 級別1:開(kāi)發(fā)人員不可以訪(fǎng)問(wèn)連接,也無(wú)法發(fā)出動(dòng)態(tài)SQL。所有性能低下的方法都被關(guān)閉,包括結果集更新和元數據訪(fǎng)問(wèn)。

● 級別2:允許動(dòng)態(tài)查詢(xún),但其他所有性能低下的方法仍然受到限制。筆者的架構就使用這種默認值。

● 級別3:全面的JDBC訪(fǎng)問(wèn),沒(méi)有任何限制。

關(guān)閉JDBC特性后,筆者建議發(fā)出異常,這可以解釋特性已被關(guān)閉,需要聯(lián)系數據庫管理員。在開(kāi)發(fā)期間,數據庫管理員可以決定是否真正需要該特性,并確定要不要重新添加到框架上,或者更改該特性的性能級別。

public class CWResultSet implements ResultSet

{

 private ResultSet m_rs;

 private long m_createTime;

 private int m_perf_level;

 public CWResultSet( ResultSet rs, perf_level)

 {

  m_rs = rs;

  m_createTime = System.currentTimeMillis();

  m_perf_level = perf_level;

 }

 public void updateRow() throws SQLException

 {

  if(perf_level < CWDatabase.HIGH_PERF_ONLY)

  {

   CWExceptionReporter.write(this,CWExceptionReporter.ERROR, "Use of method prohibited due to slow performance, “+ " as per the DBA.");

  }

  m_rs.updateRow();

 }

}

為數據庫管理員想要開(kāi)啟或者禁用的每一部分JDBC功能賦予名字,并且利用屬性文件控制這些值相當簡(jiǎn)單。不過(guò),筆者發(fā)現自己不需要這種靈活性,于是仍采用了基本級別。

SQL性能跟蹤

雖然SQL Anywhere提供了監控查詢(xún)的功能,但筆者還是提供了語(yǔ)句定時(shí)和報告機制。這樣數據庫管理員可以對某個(gè)SQL語(yǔ)句及所有語(yǔ)句開(kāi)啟跟蹤機制,或者設定時(shí)間閾值,報告超過(guò)給定閾值的查詢(xún)。筆者還考慮了在結果集層面的定時(shí),那樣就可以確認超過(guò)閾值的結果集。這會(huì )有所幫助,因為語(yǔ)句定時(shí)執行只提供返回首行的所用時(shí)間,除非語(yǔ)句里面有“按××排序”或者類(lèi)似子句。跟連接跟蹤的情況很相似,筆者在默認情況下關(guān)閉了這項功能,在測試階段加以利用。

public int executeUpdate(String queryName)

{

 private long startTime;

 < snip >

 // 執行更新

 startQueryTimer();

 int numupdate =theDB.executeUpdate queryName,plist);

 stopQueryTimer(queryName);

}

如果查詢(xún)跟蹤機制開(kāi)啟,查詢(xún)時(shí)間就會(huì )記錄到數據庫里面。

(沈建苗 編譯)

(計算機世界報 2006年10月16日 第40期 B31、B32)

本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
JDBC詳解
用JAVA從數據庫中讀出字段及內容
JSP分頁(yè)技術(shù)實(shí)現
請教JDBC怎么連接ORACLE數據庫
使用JDBC連接數據庫獲取表字段的注釋信息
利用Jakarta Commons組件beanutils、dbutils簡(jiǎn)化JDBC數據庫操作(一)
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久