• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
lwdba – 開放原始碼的輕量級資料庫存取程式庫
 

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

on

  • 1,225 views

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

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

Statistics

Views

Total Views
1,225
Views on SlideShare
1,224
Embed Views
1

Actions

Likes
0
Downloads
11
Comments
0

1 Embed 1

http://a0.twimg.com 1

Accessibility

Categories

Upload Details

Uploaded via as Microsoft PowerPoint

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment
  • lwdba 不是要做一個無所不斬的寶劍 , 它有它設定的目標 , 以及要滿足的對象 在現存的程式庫中 , 和 lwdba 都以輕量級為目標的 , 應該就是 Commons 的 DbUtils

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

  • lwdba – 開放原始碼的輕量級資料庫存取程式庫 王建興
  • 個人簡介
    • 研究興趣
      • 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 )
  • Agenda
    • lwdba 是什麼
      • lwdba 的適合 / 不適合應用情境
    • lwdba 的設計目標
    • Commons DbUtils: JDBC Utility Component
    • lwdba 的取得及建構
    • lwdba 的設定
    • lwdba 的架構及程式設計
    • 歡迎參與 lwdba 專案
  • lwdba 是什麼
    • lwdba 的名稱源自於 Light Weight DataBase Access ( 輕量級的資料庫存取 )
    • lwdba 是一個開放原始碼的計畫
      • Apache License V2.0
    • lwdba 是基於關聯式資料庫的 Java 存取程式庫
      • 它並不是一個以物件導向概念存取資料的 Java 程式庫(如 Hibernate )
      • 程式員透過簡單的 SQL 述句產生器,或直接利用 SQL 述句存取資料庫
  • 使用複雜的 Framework 的問題
    • 設定複雜,一般程式員不易上手
    • 行為複雜,不僅不易學習,出了問題也不易除錯
    • 衍生大量的資料類別
  • 直接使用 JDBC 的問題
    • JDBC 所提供的 API 過於原始,無法直接滿足程式員的大多數需求
    • 單純的 JDBC 缺乏 connection pooling 的機制
  • 直接以 SQL 存取資料庫的問題
    • 程式員直接撰寫 SQL 述句,容易直接 hardcode SQL 述句於程式之中
    • 造成程式可讀性低
    • 程式碼不易管理,也難以修改
      • 倘若資料庫 schema 變動,會發生什麼事?
    • 所開發的程式難具資料庫可攜性
  • lwdba 的設計目標
    • 簡化設定
    • 減少所需的類別數
    • 支援 Connection Pooling
    • 直接以關聯式資料的方式,以 SQL 的語法進行程式設計
    • 提高跨資料庫時的可移植性
    • 簡化程式設計的複雜度,容易上手
    • 支援 Query Caching
  • Commons DbUtils: JDBC Utility Component
    • DbUtils 是 Jakarta Apache Project 下的一個程式庫
    • DbUtils 是一小組設計用來操作 JDBC 的類別所構成的程式庫
    • DbUtils 的設計目標包括了
      • 小型(易於理解)
      • 通透(毋需理解底層運作,只管下查詢得到資料)
      • 快速(毋需建立大量暫時性物件)
  • lwdba 不同於 DbUtils 之處
    • 支援 Connection Pooling
    • 支援 Query Caching
    • 支援 SQL 述句的產生及管理
    • 對應一套進行設計時的原則
  • 如何取得 lwdba
    • 上 lwdba 在 sourceforge 上的官方網站下載原始碼
    • http:// lwdba.sourceforge.net /
  • 如何建構 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 的程式庫
  • 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
  • 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
      • 資料庫存取的帳號密碼
  • lwdba 的設定 (3/3)
    • lwdba.pool.default.maxConnectionCount
      • 資料庫連線 Connection Pool 的最大連線數
    • lwdba.pool.default.encoding
      • 預設的字元語系
    • lwdba.pool.default.sqlFile
      • SQLManager 所用的 SQL 設定檔名稱
      • 若設定為 sql ,則代表使用 CLASSPATH 下的 sql.properties
  • lwdba 主架構 SQLExecutorManager DBCP JDBC SQLExecutor SQLManager DBFacade DBRow 基於 lwdba 的應用程式 Database
  • lwdba 中的主要類別
    • DBRow
      • 簡易的 SQL 述句產生器
    • SQLManager
      • 管理所有的 SQL 述句
    • DBFacade
      • 執行 SQL 述句(查詢,更新)
  • lwdba 如何看待 SQL statement
    • 一般人不在程式中使用 SQL 的原因?
      • 資料庫相依性
      • schema change 帶來的影響
    • lwdba 對 SQL statement 的觀點
      • 在程式中使用 SQL statement
      • 但在程式中看不到 SQL statement
    • 做法
      • SQL statement composer
      • SQL statement 抽離至外部的設定檔
  • 在 lwdba 中得到 SQL 述句的兩種途徑
    • 透過 DBRow 自動幫你產生
      • 人工撰寫 SQL 述句容易出錯,也煩人
      • 透過一個類別來自動產生,可以省去許多功夫
    • 人工手寫於 SQL 述句設定檔,透過 SQLManager 進行管理
      • 再怎麼好的 SQL 述句產生器,都無法滿足所有的需求
      • 在實務的應用上,你可能要需要十分複雜的 SQL 述句,才能達成需求,或是提供更好的效能
  • DBRow - 建構式 (1/2)
    • 每個 DBRow 物件,都代表一筆 table 的資料(一個 row )
    • public DBRow(String _tableName, String _pkName)
      • 指定欲產生的 table 名稱,及唯一的 PK 名稱
    • public DBRow(String _tableName, String _pkName[])
      • 指定欲產生的 table 名稱,及複合的一組 PK 名稱
  • DBRow - 建構式 (2/2)
    • 另可指定 databaseType
      • 目前有特殊作用的 databaseType 為” oracle”
    • public DBRow(String _tableName, String _pkName, String _databaseType)
    • public DBRow(String _tableName, String _pkName[] , String _databaseType)
  • DBRow - 存取整個 row 值
    • 在建構 DBRow 之後, DBRow 內並無任何 column 之值,你可以逐一設定各 column 之值,或利用設定整個 row 值的方式來設定其值
    • public void setRow(HashMap hm)
      • HashMap 中的名稱及值的對映,代表欲設定之 column 及其值的對映
    • public HashMap getRow()
      • 將 DBRow 內各 column 的值,以 HashMap 的形式回傳
  • 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 之值
  • DBRow - 產生 SQL 述句
    • public String toInsertString()
      • 產生 SQL insert 述句,可用於新增該筆資料
    • public String toDeleteString()
      • 產生 SQL delete 述句,可用於刪除該筆資料
    • public String toUpdateString()
      • 產生 SQL update 述句,可用於更新該筆資料
    • public String toQueryString()
      • 產生 SQL query 述句,可用於查詢資料
  • 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')
  • 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 子句中的條件
  • 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 即可!
  • 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 子句中的條件
  • 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')
  • SQLManager
    • SQLManager 是 lwdba 為了避免將 SQL 述句寫死在程式中的類別
    • SQLManager 會依據 system.properties 中所設定的 sqlFile 來決定實際使用的 SQL 敘述設定檔
      • 例如: sql.properties
    • 針對不同的資料庫類型( mysql, mssql, oracle ),可分別提供一份外掛的 SQL 敘述設定檔
    • 程式中若想使用 SQL 敘述,則務必透過 SQLManager 來取得 SQL 敘述
  • SQL 述句設定檔
    • SQL 設定檔中的每一行文字行皆代表一組 SQL 敘述,並且皆為 name=value 的對應
      • 例如: User.getUserPassword=select password from UserAccount where id={0}
    • 設定中的 Xxx.yyyyy 建議命名方式
      • Xxx 為子系統名稱
      • yyyy 為子系統提供的服務,通常為一動作
    • 上例中的 {0} 為可代入 SQL 述句的參數, 0 代表第 0 個參數,可依此類推設定 {1}, {2}, …
  • SQLManager 所帶來的好處
    • SQLManager 集中管理所有的 SQL 述句
    • 當系統欲切換所使用的資料庫類型時,便毋需徹底修改程式中漫於四處的 SQL 敘述
    • 當系統遭遇 schema 更動時,只需檢視此一檔案即可
    • 程式員為所使用的 SQL 述句逐一命名,所以在程式中所見,皆為 SQL 述句的名稱,而非 SQL 述句之細節資訊,更為高階並更富可讀性
    • 所採用的命名慣例,以子系統以及它所提供服務的觀點來切入資料的處理,隔離了 SQL 述句的具體實作寫法
  • 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)
  • 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}
  • 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.
  • DBFacade - 用以實作資料存取的子系統
    • 在應用系統中,總是會找出若干個高度相關的資料表格,對它們所需的存取動作,存在極高的內聚力,我們可以將這些動作聚集在一起,構成一個子系統
    • 例如使用者帳戶管理可能牽扯進幾個表格
      • User :使用者帳戶資訊
      • Role :角色
      • Group :群組
      • UserRole :使用者所屬的角色
      • UserGroup :使用者所屬的群組
      • UserPermission :使用者被賦予的權限
      • RolePermission :角色被賦予的權限
      • GroupPermission :群組被賦予的權限
    • 可將對這幾個 table 主要的操作,聚集在一起,成為 UserAccountFacade
  • UserAccountFacade 的介面
    • Façade 提供更為高階,隱藏資料操作細節及事務邏輯的介面
    • boolean loginUser(String id, String password)
    • boolean hasRole(String roleId)
    • boolean inGroup(String groupId)
    • boolean hasPermission(String id, String perm)
  • 基於子系統劃分的設計方式
    • 依據資料的處理特性,劃分你的子系統
      • AdFacade
      • AnnouncementFacade
      • HotelFacade
      • MemberFacade
      • OrderFacade
      • ZipCodeFacade
  • 基於 Façade 從事設計的優點
    • 將事務邏輯封裝於特定的層次
    • 用戶端類別不再充斥著事務邏輯
      • 降低相依性
      • 提昇因為變動所造成的影響
    • 用戶端類別所面對的是一組高度相關的服務,而非直接操作資料
      • 在開發 Web 應用程式的你,或許將操作資料的事務邏輯,撰寫於 Action 類別中
  • DBFacade - lwdba 中所有 Façade 的基礎類別
    • DBFacade 是 lwdba 中所有 Façade 類別的基礎類別
    • DBFacade 具有兩個重要的成員
      • protected SQLExecutor sqlExecutor :可用以執行 SQL 述句
      • protected SQLManager sqlManager :可用以取得 SQL 述句
  • 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
  • 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 的引數,決定是否回傳資料的總筆數
  • QueryResult - 用來表示一組查詢結果
    • public ArrayList getRows()
      • 取得所有的資料, ArrayList 中的每個元素皆為 HashMap 型別
    • public int getTotalRowCount()
      • 取得實際的總資料筆數
      • 當限定查詢範圍時(指定 idxRow 及 count ),可使用 fReturnTotal 引數指定是否回傳實際的總筆數
  • DBFacade - 進行查詢,回傳 ArrayList
    • public ArrayList sqlQueryRows(String query)
      • 執行所指定的 SQL query 述句,並將查詢結果儲存於 ArrayList 中回傳
    • public ArrayList sqlQueryRows(String query, int idxRow, int count)
      • 執行所指定的 SQL query 述句,並以 ArrayList 回傳查詢結果中從第 idxRow 筆開始的資料,最多不超過 count 筆,無法回傳資料的總筆數
  • 取得查詢結果
    • lwdba 將查詢結果置於 ArrayList 中
    • ArrayList 中的每個元素都是 HashMap
      • 用 HashMap 表示 ResultSet 中的一筆結果
    • HashMap 即為通用性質的 DAO
    • 可直接將 ArrayList 及 HashMap 整合快取系統
  • 取得查詢結果 - 範例 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> <% } %>
  • DBFacade - 更新資料
    • public int sqlUpdate(String update)
      • 執行 SQL update 述句( insert, delete, update, create table, … )
      • 回傳更新的資料筆數
  • 如何使用 DBFacade
    • 繼承 DBFacade
    • 分析出系統中的子系統,找出每個子系統與底層資料表格的關聯性
    • 設計時基於系統分析的結果( User Case, User Story ),為滿足這些需求,你會為各子系統設計出一個個的 method ( business service )
    • 針對所設計出來的每個 method ,利用 DBFacade 提供的資料查詢及更新機制予以實作
  • 處理交易 - TransSQLExecutor
    • SQLExecutor 所執行 SQL 述句,皆為 auto commit ,也就是說,並不提供交易的能力
    • 對於一連串被視為同一交易的 SQL 述句,可利用 lwdba 的 TransSQLExecutor 執行
    • TransSQLExecutor 為 SQLExecutor 之衍生類別
  • TransSQLExecutor 與 SQLExecutor 的差異處
    • TransSQLExecutor 在建構之後、 close() 被呼叫之前,自始至終皆使用同一個 Connection 物件
      • SQLExecutor 則每次自 connection pool 取出一 Connection 物件
    • TransSQLExecutor 擴增了 commit() 及 rollback() 兩個函式,分別支援交易的提交及回繞
  • TransSQLExecutor - 支援交易
    • public void commit()
      • 提交
    • public void rollback()
      • 回繞
  • 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();
  • SQL 查詢結果的快取
    • 許多應用程式,有對 SQL 查詢做快取的需求
      • 對資料庫的複雜查詢常是應用程式效能的瓶頸
      • 依據應用程式的型態,許多類型的查詢
        • 資料變動速度慢
        • 不需要百分之百的即時性
      • 重複執行結果相同的資料庫查詢缺乏效率
    • lwdba 目前支援以 memcached 做為快取的伺服器
  • memcached
    • memcached 是一套分散式的快取系統
    • 最早是 Danga Interactive 為了 LiveJournal 所開發的
      • 每日有上百萬個用戶, 20M 個 page views
    • memcached 是由 C 所寫成,但目前有各種語言的 Client APIs
      • Perl, PHP, Python, Ruby, Java, C#, C, …
  • 取得並設置 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/
  • SQL 查詢結果的快取 - CachedQueryFacade
    • public HashMap[] sqlQueryCached(String sql)
      • 倘若快取中無指定 sql 述句的查詢結果,或上次查詢時間已超過 10 分鐘,則進行查詢,並將結果置於快取中
    • public HashMap[] sqlQueryCached(String sql, long refreshInterval)
    • 倘若快取中無指定 sql 述句的查詢結果,或上次查詢時間已超過指定的 refreshInterval ,則進行查詢,並將結果置於快取中
  • CachedQueryFacade - 快取的失效與刷新
    • public void invalidateSQLQueryCached(String sql)
      • 令快取中的查詢結果失效
    • public HashMap[] refreshSQLQueryCached(String sql)
      • 強迫更新快取中的查詢結果
  • 使用 lwdba 於你的資料庫存取
    • 簡單
      • 僅操作幾個類別便能輕易的存取資料庫中的資料
    • 易學
    • 直接以習慣的關聯式資料存取方式來存取資料
    • 輔以基於子系統的設計觀念來設計你的系統
  • 歡迎參加 lwdba 專案或提供各種建議及指教! qing at cs.nthu.edu.tw
    • 王建興
      • qing at cs.nthu.edu.tw
      • http://blog.qing.tw
    Thank You