Sqlla: 數(shù)據(jù)庫(kù)操作從未如此簡(jiǎn)單

Sqlla

一套數(shù)據(jù)庫(kù)的 ORM 微型庫(kù)彰亥,提供簡(jiǎn)單高效的 API 來(lái)操作數(shù)據(jù)庫(kù)。

Sqlla 擁有極少的API臂痕,使用方式簡(jiǎn)單匾南。讓開發(fā)者不需要關(guān)心數(shù)據(jù)庫(kù)操作的具體細(xì)節(jié),只需專注SQL和業(yè)務(wù)邏輯馏锡。同時(shí)簡(jiǎn)單的事務(wù)模型讓開發(fā)過(guò)程增益很多雷蹂。

簡(jiǎn)單使用

  • 創(chuàng)建實(shí)體類,用 @SqllaEntity 標(biāo)識(shí)
@SqllaEntity
public class UserBean {

    private String uid;
    private String phone;
    private String name;
    
    // 使用 SqllaColumnAlias 標(biāo)識(shí)后的屬性使用 alias 的值來(lái)對(duì)應(yīng)表中的列
    // 沒(méi)有標(biāo)識(shí)時(shí)直接使用屬性的名字來(lái)對(duì)應(yīng)
    @SqllaColumnAlias("gender")
    private int sex;
    
    // setter getter here
}
  • DAO 接口類
public interface UserDao {

    // 用 @Sql 標(biāo)識(shí)
    @Sql("select * from t_user where uid = ?")
    UserBean getUserById(String uid);

    @Sql("select * from t_user desc by lastActiveTS limit ?")
    List<UserBean> topUsers(int limit);

    @Sql("select (count(*) > 0) from t_user where name = ?")
    boolean userExist(String name);

    @Sql("insert into t_user (id, uid, name, phone) values (null, ?, ?, ?)")
    boolean insertUser(String uid, String name, String phone);

    @Sql("delete from t_user where uid = ?")
    boolean deleteUserById(String uid);
}
  • 創(chuàng)建 Sqlla 實(shí)例
Sqlla.ConnectionPool pool = your implimention;
Sqlla sqlla = new Sqlla.Builder().pool(pool).build();
  • 數(shù)據(jù)庫(kù)操作 CRUD
UserDao dao = sqlla.createApi(UserDao.class);

// 獲取結(jié)果集中的第一個(gè)對(duì)象(結(jié)果集的第一行)
UserBean bean = dao.getUserById("uid_10000001");

// 查詢最新的10個(gè)用戶
List<UserBean> beanList = dao.topUsers(10);

// 查詢用戶是否存在:對(duì)于updateable sql, 返回值可以是int, boolean(>0 for true), void
boolean exists = dao.userExist("李多情");

// 插入用戶到數(shù)據(jù)庫(kù)(update count > 0 for true)
boolean inserted = dao.insertUser("uid_10000002", "李明洙", "1324113361*");

// 刪除指定用戶
boolean deleted = dao.deleteUserById("uid_10000003");

DAO接口不需要任何的實(shí)現(xiàn)類杯道,是不是使用非常簡(jiǎn)單匪煌???

概念

  • 實(shí)體: 庫(kù)中預(yù)置了兩種實(shí)體模型
    • @SqllaEntity 標(biāo)識(shí)的Pojo實(shí)體
    • ViewObject 結(jié)果集視圖實(shí)體,代表著結(jié)果集的一行蕉饼,類似于扁平的 JSONObject
  • 轉(zhuǎn)換器: 將結(jié)果集轉(zhuǎn)換成實(shí)體的部件虐杯,可以自定義
  • DAO接口: CRUD 操作集合,每個(gè)方法代表一條SQL操作
  • 事務(wù): Transaction<T> 代表一個(gè)多條 DAO 方法的事務(wù)

深入使用

Sqlla.Builder 提供 pool()addConverterFactory() 方法昧港。

pool()方法必須設(shè)置一個(gè)ConnectionPool實(shí)例(test 代碼提供了一個(gè)基于c3p0數(shù)據(jù)源的 pool)擎椰。

addConverterFactory() 方法設(shè)置 自定義的結(jié)果集轉(zhuǎn)換工廠(實(shí)現(xiàn) ResultConverter.Factory 接口)。 內(nèi)部預(yù)置了三種工廠,

  • PrimitiveTypeConverterFactory 轉(zhuǎn)換基礎(chǔ)數(shù)據(jù)類型
  • SqllaEntityConverterFactory 轉(zhuǎn)換 @SqllaEntity 表示的實(shí)體類和其列表(List)
  • ViewObjectConverterFactory 轉(zhuǎn)換 ViewObject 結(jié)果集視圖和其列表(List<ViewObject>)

外部可以自定義針對(duì)自己特定類型的轉(zhuǎn)換工廠 (ResultSet --> CustomType)创肥,自定義的轉(zhuǎn)換工廠 return !null 時(shí)會(huì)攔截系統(tǒng)預(yù)置的轉(zhuǎn)換工廠达舒。

事物支持

當(dāng)前版本對(duì)事物進(jìn)行了簡(jiǎn)單的支持,與Spring的配合暫時(shí)沒(méi)有做過(guò)測(cè)試叹侄。

例子

Boolean ret = sqlla.transact(new Transaction<Boolean>(Isolation.SERIALIZABLE) {
    public Boolean transact() throw Exception {
        UserDao dao = sqlla.createApi(UserDao.class);
        dao.deleteUserById("uid_10000004");
        // 也可以手動(dòng)rollback() or commit(true)
        dao.deleteUserById("uid_10000005");
        return true;
    }
}, false);  // failed value

上面的代碼執(zhí)行了一個(gè)簡(jiǎn)單的事務(wù)巩搏,事務(wù)中包含兩條刪除語(yǔ)句。如果都成功趾代,則自動(dòng) commit贯底;只要有一個(gè)失敗,則會(huì)rollback撒强。當(dāng)回滾之后禽捆,事務(wù)將返回給定的 failed value笙什。在事務(wù)中,也可以手動(dòng) rollback() 或者 commit(val)胚想,這兩個(gè)操作只能調(diào)用一次琐凭,而且會(huì)中斷其后面的代碼執(zhí)行,要謹(jǐn)慎使用浊服。

開啟一個(gè)事務(wù)有兩種方法:

<T> T sqlla.transact(Transaction<T> transaction);

void sqlla.transact(Transaction0 transaction);

注意: transact方法是一個(gè)同步方法统屈,它會(huì)立馬調(diào)用transaction, 并返回。

Transaction<T> 是一個(gè)抽象類牙躺,抽象方法transact用于實(shí)現(xiàn)事務(wù)的具體邏輯愁憔。最多有三個(gè)參數(shù):isolationreadOnlytimeout述呐,分別代表 隔離級(jí)別惩淳,是否只讀,超時(shí)秒數(shù)乓搬。Transaction0 是其范型為 Void 的子類思犁。

嵌套事務(wù)

Sqlla 對(duì)事務(wù)的嵌套提供了簡(jiǎn)單的支持。相比于Spring事務(wù)間的多種傳播機(jī)制进肯,Sqlla只提供了 REQUIRES_NEW 的傳播機(jī)制:內(nèi)層和外層完全隔離開來(lái)激蹲,互不影響。

methodAmethodB 是兩個(gè)事務(wù)方法江掩,他們之間完全隔離学辱,提交和回滾互不影響。

public void methodA() {
    sqlla.transact(new Transaction0() {
        protected void transact0() throws Exception {
            UserDao dao = sqlla.createApi(UserDao.class);
            
            boolean inserted = dao.insertUser("uid_1000007", "王五", "13241133615");
            methodB();  // 事務(wù)B方法
            boolean deleted = dao.deleteUserByName("張三");
        }
    });
}

public void methodB() {
    sqlla.transact(new Transaction0() {
        protected void transact0() throws Exception {
            UserDao dao = sqlla.createApi(UserDao.class);
            boolean inserted = dao.insertUser("uid_1000008", "趙六", "13241133616");
        }
    }
}

如何驗(yàn)證兩個(gè)事務(wù)之間互不影響环形?

我們先把 mehtodA 中的 deleteUserByName 方法的sql改成一個(gè)錯(cuò)的sql

@Sql("delete from t_user where name = ????????")
boolean deleteUserByName(String name);

現(xiàn)在再調(diào)用 methodA策泣,你會(huì)發(fā)現(xiàn) “王五” 這個(gè)用戶并未插入到數(shù)據(jù)庫(kù)中, “張三” 也沒(méi)有被刪除,而 “趙六” 卻實(shí)實(shí)在在的插入到了數(shù)據(jù)庫(kù)中抬吟。

注意:假如 methodB 本身并不是一個(gè)單獨(dú)的事務(wù)方法 (未用 sqlla.transact 開啟)萨咕,那么他將使用外層的事務(wù)。所以要不要使用事務(wù)火本,一定要考慮好危队,不然可能會(huì)有一些意想不到的效果。

Sqlla雖然提供了注解的方式來(lái)操作SQL钙畔,但是事務(wù)并沒(méi)有使用注解的方式茫陆, 這和MyBatis一致。實(shí)際內(nèi)部實(shí)現(xiàn)也和 MyBatis 相差無(wú)幾擎析。

GitHub鏈接

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末簿盅,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌挪鹏,老刑警劉巖见秽,帶你破解...
    沈念sama閱讀 216,402評(píng)論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異讨盒,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)步责,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門返顺,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人蔓肯,你說(shuō)我怎么就攤上這事遂鹊。” “怎么了蔗包?”我有些...
    開封第一講書人閱讀 162,483評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵秉扑,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我调限,道長(zhǎng)舟陆,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,165評(píng)論 1 292
  • 正文 為了忘掉前任耻矮,我火速辦了婚禮秦躯,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘裆装。我一直安慰自己踱承,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,176評(píng)論 6 388
  • 文/花漫 我一把揭開白布哨免。 她就那樣靜靜地躺著茎活,像睡著了一般。 火紅的嫁衣襯著肌膚如雪琢唾。 梳的紋絲不亂的頭發(fā)上载荔,一...
    開封第一講書人閱讀 51,146評(píng)論 1 297
  • 那天,我揣著相機(jī)與錄音慧耍,去河邊找鬼身辨。 笑死,一個(gè)胖子當(dāng)著我的面吹牛芍碧,可吹牛的內(nèi)容都是我干的煌珊。 我是一名探鬼主播,決...
    沈念sama閱讀 40,032評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼泌豆,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼定庵!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,896評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤蔬浙,失蹤者是張志新(化名)和其女友劉穎猪落,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體畴博,經(jīng)...
    沈念sama閱讀 45,311評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡笨忌,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,536評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了俱病。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片官疲。...
    茶點(diǎn)故事閱讀 39,696評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖亮隙,靈堂內(nèi)的尸體忽然破棺而出途凫,到底是詐尸還是另有隱情,我是刑警寧澤溢吻,帶...
    沈念sama閱讀 35,413評(píng)論 5 343
  • 正文 年R本政府宣布维费,位于F島的核電站,受9級(jí)特大地震影響促王,放射性物質(zhì)發(fā)生泄漏犀盟。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,008評(píng)論 3 325
  • 文/蒙蒙 一硼砰、第九天 我趴在偏房一處隱蔽的房頂上張望且蓬。 院中可真熱鬧,春花似錦题翰、人聲如沸恶阴。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)冯事。三九已至,卻和暖如春血公,著一層夾襖步出監(jiān)牢的瞬間昵仅,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工累魔, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留摔笤,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,698評(píng)論 2 368
  • 正文 我出身青樓垦写,卻偏偏與公主長(zhǎng)得像吕世,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子梯投,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,592評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容