NutzDao學習筆記-基本概念知識
一 環境搭建
- 首先,你必須安裝 JDK 1.6,推薦JDK 8u112
- 其次,為了執行 Nutz.Dao,你必須要有一個數據庫軟體:
- Mysql,Postgresql, SQLServer, Oracle, DB2 , H2都可以。
- 建立一個 Java 專案:
- 推薦使用Eclipse或Idea等IDE工具
- 你要將資料庫的 JDBC Driver 和你喜歡的連線池加入專案的 classpath。
- NutDao並不依賴MVC環境及Ioc.
- 在Mvc環境下,通常使用Ioc管理NutDao
- NutDao是執行緒安全的,無需重複建立其例項.
建立POJO
建立NutzDao例項,定義dataSource (重點)
二 Dao介面的基本操作
插入 |
Insert |
一條 SQL 插入一條記錄或者多條記錄 |
插入 |
FastInsert |
一條 SQL ,通過batch插入多條記錄 |
刪除 |
Delete |
一條 SQL 刪除一條記錄 |
更新 |
Update |
一條 |
獲取 |
Fetch |
一條 SQL 獲取一條記錄 |
查詢 |
Query |
一條 SQL 根據條件獲取多條記錄 |
清除 |
Clear |
一條 SQL 根據條件刪除多條記錄 |
建表 |
Create |
根據實體建表 |
刪表 |
Drop |
根據實體/表名稱進行刪表 |
聚合 |
Func |
執行sum,count等操作 |
傳統關係型資料庫定義了資料庫的四種操作,增刪改查,但是nutz.dao從使用者角度,又擴充套件了好幾種操作,而且都支援條件增刪改查,專門為條件封裝了介面,但是也有它的侷限性
1 不生成外來鍵,也不推薦用外來鍵
2 只能解決一般建表需求,複雜的表結構需通過自定義sql完成
三 注意事項
主鍵
對於一個 POJO,你可以同時為其宣告 @Id 和 @Name,它們都能正常工作。你只需要保證 @Name 對應的欄位 在資料庫裡有唯一性約束即可。 但是通常, Nutz.Dao 並沒有假設你同時在一個 POJO 裡應用 @Id, @Name 和 @PK,如果你 這麼做了,可能會引發一些奇怪的問題。事實上,你也不可能這麼做,不是嗎?
TIPS:註解 @Id 與註解 @Name 宣告的欄位不需要另外加上註解 @Column; 在註解 @PK 裡面宣告的對應複合主鍵的欄位不需要另外加上註解 @Column;
預設的,nutz.dao認為一個整數型的主鍵是自增的。所以它會在執行
Dao.insert(pet);
之後,為你插入的物件執行
SELECT MAX(id) from t_pet;(如果你使用的資料庫如mysql,支援主鍵返回,那這個操作不會出現)
不同的資料庫獲得自增值得方式是不一樣的,通過@Next註解,宣告資料庫本地方言,來獲取自增值,注意這裡的自增是由資料庫來實現的,而非nutzDao的內部自增機制
複雜的sql條件
- 對於 Nutz.Dao 來說,它本質上就是將你的 Java 物件轉化成 SQL,然後交給 JDBC 去執行。
- 而 SQL 中,當執行資料刪除和查詢操作時,最常用的就是 WHERE 關鍵字。
- WHERE 關鍵字後面的就是所謂的複雜查詢條件
有些情況,資料庫中的欄位同 Java 物件中的欄位並不同名, 所以就需要給 Java 欄位上的資料庫欄位註解加上引數 @Column("資料庫欄位名") 如果你通過 Cnd.wrap() 硬編碼某個欄位,那麼當這個欄位資料庫欄位名發生改變時,你就需要改動很多。 因此你希望僅僅將對於資料庫的變動限制在 Java 物件的原始檔裡 所以 Nutz 提供了 Cnd.where() 方法
提供Criteria介面(繼承Condition介面)
- 讓程式設計師更容易的拼裝複雜邏輯的條件
- 讓生成的 SQL 可以被引數化,更好的支援 PreparedStatement
// 建立一個 Criteria 介面例項
Criteria cri = Cnd.cri();
// 組裝條件
if(...){
cri.where().andIn("id", 3,4,5).andIn("name", "Peter", "Wendal", "Juqkai");
}else if(...){
cri.where().andLT("id", 9);
}
if(...){
cri.where().andLike("name", "%A%");
}
cri.getOrderBy().asc("name").desc("id");
// 執行查詢
List<MyObj> list = dao.query(MyObj.class, cri, null);
分頁
使用資料庫的應用程式,多數情況下都需要使用 分頁 這個功能。尤其是在 Web 應用程式中,後端的分頁查詢尤其的普遍。 在以往的使用經驗中,一個分頁查詢,除了能獲取到一個列表外,我們通常需要如下幾個資訊才能在客戶端顯示出一個完整的翻頁條。
- 當前頁數 -- 第幾頁
- 頁大小 -- 每頁有多少條記錄
- 總頁數 -- 一共多少頁
- 總記錄數 -- 如果不分頁,一共有多少條記錄
當我們獲得了這四條資訊後,對於維護一個翻頁查詢就足夠。
Nutz.Dao 的查詢介面天然就支援分頁查詢。
<T> List<T> query(Class<T> classOfT, Condition condition, Pager pager);
這個介面有三個引數
- classOfT 告訴 Nutz.Dao 需要查詢的實體型別
- condition 告訴 Nutz.Dao 查詢出的列表需要符合的條件。詳細請看 複雜條件。
- 最後一個引數,就是告訴 Nutz.Dao 將結果如何分頁的了。
Pager 物件有如下幾個注意事項:
- 如果 pager 被傳入了 null,則不分頁
- 生成 Pager 物件的時候需要傳入 “當前頁數” 和 “頁大小”
- Pager 雖然有 getRecordCount() 和 getPageCount() 方法,但是它不會自動被設值 -- 因為考慮到效率
- 通過 Pager.setRecordCount() 可以為 Pager 設定結果集的總數,Pager 會通過 getPageCount() 返回總頁數
- 分頁頁數從1開始算,如果頁數是0,代表不分頁,請特別注意
支援一對一,一對多,多對多對映,支援自定義sql
事務
對於事務安全,nutz提供了事務模板
- org.nutz.trans.Trans 類提供了兩個函式 exec
- 一個接受數目可變的 Atom 物件
- 一個接受一個整型值用以界定本事務的級別,以及一個數目可變的 Atom 物件
- Atom 類就是 java.lang.Runnable 的一個別名
- 在一個 Atom 裡,無論同時操作多少 DataSource,都是事務安全的(由於不是使用XADataSource,無法100%保證)
- 你可以通過實現自己的 Transaction 實現類,擴充套件 Nutz.Dao 對於事務的支援
示例
final Pet pet1 = dao.fetch(Pet.class,"XiaoBai");
final Pet pet2 = dao.fetch(Pet.class,"XiaoHei");
pet1.setNickname("BaiBai");
pet2.setNickname("HeiHei");
// Begin transaction
Trans.exec(new Atom(){
public void run() {
dao.update(pet1);
dao.update(pet2);
}
});
提供一個org.nutz.trans.Atom介面的匿名類來實現,在裡面的所有的dao操作都是原子性的,以為他們在同一個原子裡面“Atom”
設定事務的隔離級別
public static void exec(int level, Atom... atoms);
這裡的第一個引數 level 和 java.sql.Connection 介面中的 setTransactionIsolation 規定的 level 是一樣的。下面 是在 java.sql.Connection 裡面關於 level 引數的 JDoc 說明:
它可以是下列常量中的任意一個值:
- Connection.TRANSACTION_READ_UNCOMMITTED
- Connection.TRANSACTION_READ_COMMITTED
- Connection.TRANSACTION_REPEATABLE_READ
- Connection.TRANSACTION_SERIALIZABLE
實體解析
Class<?> ---> Entity<?> ---> PojoMaker ---> DaoStatement ---> DaoExecutor ---> JDBC
| | | | |
\------------------------ NutDao 的實現流程 -----------------------/
- PojoMaker 介面負責語句的生成
- DaoExecutor 介面負責語句的執行
內建服務類
單獨的呼叫一行介面,多傳入一個引數到沒什麼,但是如果頻繁的被使用,每次都要多寫一個引數畢竟很是麻煩,nutzdao提供了服務類來簡化這些操作
- 如果 POJO 即聲明瞭 @Id 又聲明瞭 @Name,那麼適合採用 IdNameEntityService
- 如果 POJO 僅聲明瞭 @Id,那麼適合採用 IdEntityService
- 如果 POJO 僅聲明瞭 @Name,那麼適合採用 NameEntityService
- 如果 POJO 即沒聲明瞭 @Id 又沒聲明瞭 @Name,那麼適合採用 EntityService
- 這四個內建的服務類,僅僅提供了一些基本的操作。
- 這些服務類都是支援泛型。
- 你可以直接使用,或者你可以從這四個服務類繼承你自己的實現。
- 如果你繼承這些服務類,請務必宣告泛型
Dao攔截器
var ioc = {
dao : {
type : "org.nutz.dao.impl.NutDao",
args : [{refer:"dataSource"}],
fields : {
interceptors : [
"log", //輸入sql語句到日誌,這是nutdao預設情況下唯一啟用的攔截器
"time", // 列印sql時耗
"net.demo.MyDaoInterceptor", // 自定義攔截器,需要實現DaoInterceptor
{refer:"superI"} // 引用另外一個bean作為攔截器
]
}
}
}