lwdba – 開放原始碼的輕量級資料庫存取程式庫

  • 1,102 views
Uploaded on

介紹我們開放原始碼的資料庫存取程式庫

介紹我們開放原始碼的資料庫存取程式庫

More in: Technology
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
    Be the first to like this
No Downloads

Views

Total Views
1,102
On Slideshare
0
From Embeds
0
Number of Embeds
0

Actions

Shares
Downloads
11
Comments
0
Likes
0

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide
  • lwdba 不是要做一個無所不斬的寶劍 , 它有它設定的目標 , 以及要滿足的對象 在現存的程式庫中 , 和 lwdba 都以輕量級為目標的 , 應該就是 Commons 的 DbUtils

Transcript

  • 1. lwdba – 開放原始碼的輕量級資料庫存取程式庫 王建興
  • 2. 個人簡介
    • 研究興趣
      • Distributed Network Management System
      • Mobile Code System & Mobile Agent
      • P2P Networking
    • 開發興趣
      • Java-based Application
      • Multimedia Streaming
      • P2P Networking
    • iThome 程式人專欄寫作
    • Thinking in Java 中文版第二版及第四版的共同譯者
    • 部落格 : 程式者的胡言亂語( http://blog.qing.tw )
  • 3. Agenda
    • lwdba 是什麼
      • lwdba 的適合 / 不適合應用情境
    • lwdba 的設計目標
    • Commons DbUtils: JDBC Utility Component
    • lwdba 的取得及建構
    • lwdba 的設定
    • lwdba 的架構及程式設計
    • 歡迎參與 lwdba 專案
  • 4. lwdba 是什麼
    • lwdba 的名稱源自於 Light Weight DataBase Access ( 輕量級的資料庫存取 )
    • lwdba 是一個開放原始碼的計畫
      • Apache License V2.0
    • lwdba 是基於關聯式資料庫的 Java 存取程式庫
      • 它並不是一個以物件導向概念存取資料的 Java 程式庫(如 Hibernate )
      • 程式員透過簡單的 SQL 述句產生器,或直接利用 SQL 述句存取資料庫
  • 5. 使用複雜的 Framework 的問題
    • 設定複雜,一般程式員不易上手
    • 行為複雜,不僅不易學習,出了問題也不易除錯
    • 衍生大量的資料類別
  • 6. 直接使用 JDBC 的問題
    • JDBC 所提供的 API 過於原始,無法直接滿足程式員的大多數需求
    • 單純的 JDBC 缺乏 connection pooling 的機制
  • 7. 直接以 SQL 存取資料庫的問題
    • 程式員直接撰寫 SQL 述句,容易直接 hardcode SQL 述句於程式之中
    • 造成程式可讀性低
    • 程式碼不易管理,也難以修改
      • 倘若資料庫 schema 變動,會發生什麼事?
    • 所開發的程式難具資料庫可攜性
  • 8. lwdba 的設計目標
    • 簡化設定
    • 減少所需的類別數
    • 支援 Connection Pooling
    • 直接以關聯式資料的方式,以 SQL 的語法進行程式設計
    • 提高跨資料庫時的可移植性
    • 簡化程式設計的複雜度,容易上手
    • 支援 Query Caching
  • 9. Commons DbUtils: JDBC Utility Component
    • DbUtils 是 Jakarta Apache Project 下的一個程式庫
    • DbUtils 是一小組設計用來操作 JDBC 的類別所構成的程式庫
    • DbUtils 的設計目標包括了
      • 小型(易於理解)
      • 通透(毋需理解底層運作,只管下查詢得到資料)
      • 快速(毋需建立大量暫時性物件)
  • 10. lwdba 不同於 DbUtils 之處
    • 支援 Connection Pooling
    • 支援 Query Caching
    • 支援 SQL 述句的產生及管理
    • 對應一套進行設計時的原則
  • 11. 如何取得 lwdba
    • 上 lwdba 在 sourceforge 上的官方網站下載原始碼
    • http:// lwdba.sourceforge.net /
  • 12. 如何建構 lwdba
    • 相依程式庫
      • commons-collection-3.1
      • commons-dbcp-1.2.1
      • commons-logging-1.1
      • commons-pool-1.2
      • log4j-1.2.8
      • memcached-1.4.jar
      • spy-2.4.jar
    • 利用 Apache Ant 來建構
      • http:// ant.apache.org / 上可下載
      • ant package
      • dist/lwdba.jar <- lwdba 的程式庫
  • 13. lwdba 的設定 (1/3)
    • 資料庫的設定皆設定於 CLASSPATH 下的 system.properties 檔案
    lwdba.pool.default.type=mysql lwdba.pool.default.driverClassName=org.gjt.mm.mysql.Driver lwdba.pool.default.driverURL=jdbc:mysql://localhost:3306/lwdba lwdba.pool.default.userName=root lwdba.pool.default.password=root lwdba.pool.default.maxConnectionCount=32 lwdba.pool.default.encoding=UTF-8 lwdba.pool.default.sqlFile=sql Pool Name
  • 14. lwdba 的設定 (2/3)
    • lwdba.pool.default.type
      • 資料庫的類型,例如 mysql, mssql, oracle
    • lwdba.pool.default.driverClassName
      • JDBC 驅動程式的類別名稱
    • lwdba.pool.default.driverURL
      • JDBC 連線 URL 字串
    • lwdba.pool.default.userName
      • 資料庫存取的帳號名稱
    • lwdba.pool.default.password
      • 資料庫存取的帳號密碼
  • 15. lwdba 的設定 (3/3)
    • lwdba.pool.default.maxConnectionCount
      • 資料庫連線 Connection Pool 的最大連線數
    • lwdba.pool.default.encoding
      • 預設的字元語系
    • lwdba.pool.default.sqlFile
      • SQLManager 所用的 SQL 設定檔名稱
      • 若設定為 sql ,則代表使用 CLASSPATH 下的 sql.properties
  • 16. lwdba 主架構 SQLExecutorManager DBCP JDBC SQLExecutor SQLManager DBFacade DBRow 基於 lwdba 的應用程式 Database
  • 17. lwdba 中的主要類別
    • DBRow
      • 簡易的 SQL 述句產生器
    • SQLManager
      • 管理所有的 SQL 述句
    • DBFacade
      • 執行 SQL 述句(查詢,更新)
  • 18. lwdba 如何看待 SQL statement
    • 一般人不在程式中使用 SQL 的原因?
      • 資料庫相依性
      • schema change 帶來的影響
    • lwdba 對 SQL statement 的觀點
      • 在程式中使用 SQL statement
      • 但在程式中看不到 SQL statement
    • 做法
      • SQL statement composer
      • SQL statement 抽離至外部的設定檔
  • 19. 在 lwdba 中得到 SQL 述句的兩種途徑
    • 透過 DBRow 自動幫你產生
      • 人工撰寫 SQL 述句容易出錯,也煩人
      • 透過一個類別來自動產生,可以省去許多功夫
    • 人工手寫於 SQL 述句設定檔,透過 SQLManager 進行管理
      • 再怎麼好的 SQL 述句產生器,都無法滿足所有的需求
      • 在實務的應用上,你可能要需要十分複雜的 SQL 述句,才能達成需求,或是提供更好的效能
  • 20. DBRow - 建構式 (1/2)
    • 每個 DBRow 物件,都代表一筆 table 的資料(一個 row )
    • public DBRow(String _tableName, String _pkName)
      • 指定欲產生的 table 名稱,及唯一的 PK 名稱
    • public DBRow(String _tableName, String _pkName[])
      • 指定欲產生的 table 名稱,及複合的一組 PK 名稱
  • 21. DBRow - 建構式 (2/2)
    • 另可指定 databaseType
      • 目前有特殊作用的 databaseType 為” oracle”
    • public DBRow(String _tableName, String _pkName, String _databaseType)
    • public DBRow(String _tableName, String _pkName[] , String _databaseType)
  • 22. DBRow - 存取整個 row 值
    • 在建構 DBRow 之後, DBRow 內並無任何 column 之值,你可以逐一設定各 column 之值,或利用設定整個 row 值的方式來設定其值
    • public void setRow(HashMap hm)
      • HashMap 中的名稱及值的對映,代表欲設定之 column 及其值的對映
    • public HashMap getRow()
      • 將 DBRow 內各 column 的值,以 HashMap 的形式回傳
  • 23. DBRow - 存取 column
    • public void setColumn(String columnName, Object value)
      • 指定 column 名稱,及欲設定的值,設定該 DBRow 物件的 column 之值
    • public Object getColumn(String columnName)
      • 指定 column 名稱,取得該 DBRow 中該 column 之值
    • public void removeColumn(String columnName)
      • 指定 column 名稱,移除該 DBRow 中該 column 之值
  • 24. DBRow - 產生 SQL 述句
    • public String toInsertString()
      • 產生 SQL insert 述句,可用於新增該筆資料
    • public String toDeleteString()
      • 產生 SQL delete 述句,可用於刪除該筆資料
    • public String toUpdateString()
      • 產生 SQL update 述句,可用於更新該筆資料
    • public String toQueryString()
      • 產生 SQL query 述句,可用於查詢資料
  • 25. DBRow - 產生新增資料 SQL 述句的例子 DBRow dr = new DBRow(&quot;Customer&quot;, &quot;seqNo&quot;); dr.setColumn(&quot;name&quot;, name); dr.setColumn(&quot;phone&quot;, phone); dr.setColumn(&quot;address&quot;, address); System.out.println(dr.toInsertString()); insert into Customer(phone, address, name) values('0988168168', 'Hsinchu City, Taiwan', 'Qing')
  • 26. DBRow - 產生刪除資料 SQL 述句的例子
    • 欲刪除 Customer 表格, seqNo=123 的資料
    DBRow dr = new DBRow(&quot;Customer&quot;, &quot;seqNo&quot;); dr.setColumn(“seqNo&quot;, 123); System.out.println(dr.toDeleteString()); 所設定的 column 會做為 where 子句中的條件
  • 27. DBRow - 產生更新資料 SQL 述句的例子
    • Customer 表格, seqNo=123 的資料,其 phone 欄位之值原為 0935168888 ,欲更改為 0939168888
    DBRow dr = new DBRow(&quot;Customer&quot;, &quot;seqNo&quot;); dr.setColumn(“seqNo&quot;, 123); dr.setColumn(“phone&quot;, ”0939168888”); System.out.println(dr.toUpdateString()); 只設定 PK 及欲更新的 column 即可!
  • 28. DBRow - 產生查詢資料 SQL 述句的例子
    • 欲查詢 Customer 表格中 phone 欄位值為 0939168888 的資料
    DBRow dr = new DBRow(&quot;Customer&quot;, &quot;seqNo&quot;); dr.setColumn(“phone&quot;, ”0939168888”); System.out.println(dr.toQueryString()); 所設定的 column 會做為 where 子句中的條件
  • 29. DBRow -建構式中 databaseType 引數的作用
    • 結果
    DBRow dr = new DBRow(&quot;Customer&quot;, &quot;seqNo&quot;, &quot;oracle&quot;); dr.setColumn(&quot;name&quot;, name); dr.setColumn(&quot;phone&quot;, phone); dr.setColumn(&quot;address&quot;, address); dr.setColumn(&quot;createdTime&quot;, new Date()); System.out.println(dr.toInsertString()); insert into Customer(phone, createdTime, address, name) values('0988168168', TO_DATE('2009-03-12 14:13:37', 'YYYY-MM-DD HH24:MI:SS'), 'Hsinchu City, Taiwan', 'Qing')
  • 30. SQLManager
    • SQLManager 是 lwdba 為了避免將 SQL 述句寫死在程式中的類別
    • SQLManager 會依據 system.properties 中所設定的 sqlFile 來決定實際使用的 SQL 敘述設定檔
      • 例如: sql.properties
    • 針對不同的資料庫類型( mysql, mssql, oracle ),可分別提供一份外掛的 SQL 敘述設定檔
    • 程式中若想使用 SQL 敘述,則務必透過 SQLManager 來取得 SQL 敘述
  • 31. SQL 述句設定檔
    • SQL 設定檔中的每一行文字行皆代表一組 SQL 敘述,並且皆為 name=value 的對應
      • 例如: User.getUserPassword=select password from UserAccount where id={0}
    • 設定中的 Xxx.yyyyy 建議命名方式
      • Xxx 為子系統名稱
      • yyyy 為子系統提供的服務,通常為一動作
    • 上例中的 {0} 為可代入 SQL 述句的參數, 0 代表第 0 個參數,可依此類推設定 {1}, {2}, …
  • 32. SQLManager 所帶來的好處
    • SQLManager 集中管理所有的 SQL 述句
    • 當系統欲切換所使用的資料庫類型時,便毋需徹底修改程式中漫於四處的 SQL 敘述
    • 當系統遭遇 schema 更動時,只需檢視此一檔案即可
    • 程式員為所使用的 SQL 述句逐一命名,所以在程式中所見,皆為 SQL 述句的名稱,而非 SQL 述句之細節資訊,更為高階並更富可讀性
    • 所採用的命名慣例,以子系統以及它所提供服務的觀點來切入資料的處理,隔離了 SQL 述句的具體實作寫法
  • 33. SQLManager - 取得 SQL 述句( 1/2 )
    • SQLManager 提供 getSQL() 族系的方法來取得 SQL 設定檔的內容
      • String getSQL(String key)
      • String getSQL(String key, Object arg)
      • String getSQL(String key, Object arg1, Object arg2)
      • String getSQL(String key, Object arg1, Object arg2, Object arg3)
      • String getSQL(String key, Object arg1, Object arg2, Object arg3, Object arg4)
      • String getSQL(String key, Object[] arg)
  • 34. SQLManager - 取得 SQL 述句( 2/2 )
    • 例如
    • 得到的 sql 為
      • select password from UserAccount where id= ‘qing’
    String sql = sqlManager.getSQL(“ User.getUserPassword”, “qing”); 自動加上單引號 User.getUserPassword=select password from UserAccount where id= {0}
  • 35. DBFacade - 何謂 Facade
    • Façade 就是建築物正面的入口
    • The Façade pattern simplifies access to a related sets of objects by providing one object that all objects outside the set use to communicate with the set.
    *Gamma et al (1995). Design Patterns: Elements of Reusable Object-Oriented Software.
  • 36. DBFacade - 用以實作資料存取的子系統
    • 在應用系統中,總是會找出若干個高度相關的資料表格,對它們所需的存取動作,存在極高的內聚力,我們可以將這些動作聚集在一起,構成一個子系統
    • 例如使用者帳戶管理可能牽扯進幾個表格
      • User :使用者帳戶資訊
      • Role :角色
      • Group :群組
      • UserRole :使用者所屬的角色
      • UserGroup :使用者所屬的群組
      • UserPermission :使用者被賦予的權限
      • RolePermission :角色被賦予的權限
      • GroupPermission :群組被賦予的權限
    • 可將對這幾個 table 主要的操作,聚集在一起,成為 UserAccountFacade
  • 37. UserAccountFacade 的介面
    • Façade 提供更為高階,隱藏資料操作細節及事務邏輯的介面
    • boolean loginUser(String id, String password)
    • boolean hasRole(String roleId)
    • boolean inGroup(String groupId)
    • boolean hasPermission(String id, String perm)
  • 38. 基於子系統劃分的設計方式
    • 依據資料的處理特性,劃分你的子系統
      • AdFacade
      • AnnouncementFacade
      • HotelFacade
      • MemberFacade
      • OrderFacade
      • ZipCodeFacade
  • 39. 基於 Façade 從事設計的優點
    • 將事務邏輯封裝於特定的層次
    • 用戶端類別不再充斥著事務邏輯
      • 降低相依性
      • 提昇因為變動所造成的影響
    • 用戶端類別所面對的是一組高度相關的服務,而非直接操作資料
      • 在開發 Web 應用程式的你,或許將操作資料的事務邏輯,撰寫於 Action 類別中
  • 40. DBFacade - lwdba 中所有 Façade 的基礎類別
    • DBFacade 是 lwdba 中所有 Façade 類別的基礎類別
    • DBFacade 具有兩個重要的成員
      • protected SQLExecutor sqlExecutor :可用以執行 SQL 述句
      • protected SQLManager sqlManager :可用以取得 SQL 述句
  • 41. DBFacade - 建構式
    • DBFacade()
      • 使用名為” default” 的 connection pool
    • DBFacade(String poolName)
      • 使用 poolName 引數所指定的 connection pool
      • 此名稱對應至 system.properties 中的設定
    lwdba.pool. default .type=mysql lwdba.pool. default .driverClassName=org.gjt.mm.mysql.Driver lwdba.pool. default .driverURL=jdbc:mysql://localhost:3306/lwdba … . lwdba.pool. default .sqlFile=sql
  • 42. DBFacade - 進行查詢,回傳 QueryResult
    • public QueryResult sqlQuery(String query)
      • 執行所指定的 SQL query 述句,並以 QueryResult 物件的方式回傳查詢結果
    • public QueryResult sqlQuery(String query, int idxRow, int count, boolean fReturnTotal)
      • 執行所指定的 SQL query 述句,並以 QueryResult 物件的方式回傳查詢結果中從第 idxRow 筆開始的資料,最多不超過 count 筆,並依據 fReturnTotal 的引數,決定是否回傳資料的總筆數
  • 43. QueryResult - 用來表示一組查詢結果
    • public ArrayList getRows()
      • 取得所有的資料, ArrayList 中的每個元素皆為 HashMap 型別
    • public int getTotalRowCount()
      • 取得實際的總資料筆數
      • 當限定查詢範圍時(指定 idxRow 及 count ),可使用 fReturnTotal 引數指定是否回傳實際的總筆數
  • 44. DBFacade - 進行查詢,回傳 ArrayList
    • public ArrayList sqlQueryRows(String query)
      • 執行所指定的 SQL query 述句,並將查詢結果儲存於 ArrayList 中回傳
    • public ArrayList sqlQueryRows(String query, int idxRow, int count)
      • 執行所指定的 SQL query 述句,並以 ArrayList 回傳查詢結果中從第 idxRow 筆開始的資料,最多不超過 count 筆,無法回傳資料的總筆數
  • 45. 取得查詢結果
    • lwdba 將查詢結果置於 ArrayList 中
    • ArrayList 中的每個元素都是 HashMap
      • 用 HashMap 表示 ResultSet 中的一筆結果
    • HashMap 即為通用性質的 DAO
    • 可直接將 ArrayList 及 HashMap 整合快取系統
  • 46. 取得查詢結果 - 範例 StatisticsFacade facade = StatisticsFacade.getInstance(); ArrayList al = PPTVStatisticsFacade.listStatistics(n); <% for(int i=0;i<al.size();i++) { HashMap hm = (HashMap) al.get(i); %> <tr> <td><%=hm.get(&quot;seqNo&quot;)%></td> <td><%=hm.get(&quot;uid&quot;)%></td> <td><%=hm.get(&quot;remoteHost&quot;)%></td> <td><%=hm.get(&quot;type&quot;)%></td> <td><%=hm.get(&quot;createTime&quot;)%></td> </tr> <% } %>
  • 47. DBFacade - 更新資料
    • public int sqlUpdate(String update)
      • 執行 SQL update 述句( insert, delete, update, create table, … )
      • 回傳更新的資料筆數
  • 48. 如何使用 DBFacade
    • 繼承 DBFacade
    • 分析出系統中的子系統,找出每個子系統與底層資料表格的關聯性
    • 設計時基於系統分析的結果( User Case, User Story ),為滿足這些需求,你會為各子系統設計出一個個的 method ( business service )
    • 針對所設計出來的每個 method ,利用 DBFacade 提供的資料查詢及更新機制予以實作
  • 49. 處理交易 - TransSQLExecutor
    • SQLExecutor 所執行 SQL 述句,皆為 auto commit ,也就是說,並不提供交易的能力
    • 對於一連串被視為同一交易的 SQL 述句,可利用 lwdba 的 TransSQLExecutor 執行
    • TransSQLExecutor 為 SQLExecutor 之衍生類別
  • 50. TransSQLExecutor 與 SQLExecutor 的差異處
    • TransSQLExecutor 在建構之後、 close() 被呼叫之前,自始至終皆使用同一個 Connection 物件
      • SQLExecutor 則每次自 connection pool 取出一 Connection 物件
    • TransSQLExecutor 擴增了 commit() 及 rollback() 兩個函式,分別支援交易的提交及回繞
  • 51. TransSQLExecutor - 支援交易
    • public void commit()
      • 提交
    • public void rollback()
      • 回繞
  • 52. TransSQLExecutor -處理交易的例子 TransSQLExecutor tse = new TransSQLExecutor(); DBRow dr = new DBRow(&quot;Customer&quot;, &quot;seqNo&quot;); dr.setColumn(&quot;name&quot;, “Alice&quot;); dr.setColumn(&quot;phone&quot;, &quot;0988168168&quot;); dr.setColumn(&quot;address&quot;, &quot;Hsinchu City, Taiwan&quot;); tse.executeUpdate(dr.toInsertString()); tse.rollback(); dr = new DBRow(&quot;Customer&quot;, &quot;seqNo&quot;); dr.setColumn(&quot;name&quot;, “Bob&quot;); dr.setColumn(&quot;phone&quot;, &quot;0968168168&quot;); dr.setColumn(&quot;address&quot;, &quot;Hsinchu City, Taiwan&quot;); tse.executeUpdate(dr.toInsertString()); tse.commit(); tse.close();
  • 53. SQL 查詢結果的快取
    • 許多應用程式,有對 SQL 查詢做快取的需求
      • 對資料庫的複雜查詢常是應用程式效能的瓶頸
      • 依據應用程式的型態,許多類型的查詢
        • 資料變動速度慢
        • 不需要百分之百的即時性
      • 重複執行結果相同的資料庫查詢缺乏效率
    • lwdba 目前支援以 memcached 做為快取的伺服器
  • 54. memcached
    • memcached 是一套分散式的快取系統
    • 最早是 Danga Interactive 為了 LiveJournal 所開發的
      • 每日有上百萬個用戶, 20M 個 page views
    • memcached 是由 C 所寫成,但目前有各種語言的 Client APIs
      • Perl, PHP, Python, Ruby, Java, C#, C, …
  • 55. 取得並設置 memcached
    • Unix
      • 下載:
        • http://www.danga.com/memcached/download.bml
      • 安裝:
        • 參考 http://www.ajohnstone.com/archives/installing-memcached/
        • memcached 需要 libevent
    • Windows
      • 下載( memcached for Win32 )
        • http://jehiah.cz/projects/memcached-win32/
    • Java API
      • 下載 http://bleu.west.spy.net/~dustin/projects/memcached/
  • 56. SQL 查詢結果的快取 - CachedQueryFacade
    • public HashMap[] sqlQueryCached(String sql)
      • 倘若快取中無指定 sql 述句的查詢結果,或上次查詢時間已超過 10 分鐘,則進行查詢,並將結果置於快取中
    • public HashMap[] sqlQueryCached(String sql, long refreshInterval)
    • 倘若快取中無指定 sql 述句的查詢結果,或上次查詢時間已超過指定的 refreshInterval ,則進行查詢,並將結果置於快取中
  • 57. CachedQueryFacade - 快取的失效與刷新
    • public void invalidateSQLQueryCached(String sql)
      • 令快取中的查詢結果失效
    • public HashMap[] refreshSQLQueryCached(String sql)
      • 強迫更新快取中的查詢結果
  • 58. 使用 lwdba 於你的資料庫存取
    • 簡單
      • 僅操作幾個類別便能輕易的存取資料庫中的資料
    • 易學
    • 直接以習慣的關聯式資料存取方式來存取資料
    • 輔以基於子系統的設計觀念來設計你的系統
  • 59. 歡迎參加 lwdba 專案或提供各種建議及指教! qing at cs.nthu.edu.tw
  • 60.
    • 王建興
      • qing at cs.nthu.edu.tw
      • http://blog.qing.tw
    Thank You