數據庫中間件-jdbi

文章來源:https://www.jianshu.com/p/1ee34c858cb9

Java 的數據庫原生使用 jdbc,中間件有很多,例如說 hibernate、mybatis、jdbi,這幾種是最常用的中間件。

怎麼選擇

一般情況下,如果始終只會使用到一種數據庫,jdbc 就是最好的選擇了,使用這種方式,就是直接使用最底層的東西,定位問題等都非常方便。數據庫中間件就是節省開發人力,用很少的代碼就可以快速開發。但是也會引入一些複雜度,特別是如果對中間件不熟悉或者中間件存在 bug,會導致更高複雜度。如果使用數據庫中間件,各種中間件都有各自的優劣勢,對於相關的東西需要了解清楚,否則會導致不恰當的選擇。

jdbi

jdbi 是我比較喜歡的一個數據庫中間件,它是非 ORM 的,特別適合於數據庫固定不變的場景,即不會對應多種數據庫,以後也不會更換數據庫的場景。如果不是這種場景,那麼使用 jdbc 或者最好選擇 hibernate 等對多種數據庫兼容較好的中間件。 基於上述使用場景,jdbi 的優點有:

和 jdbci 比較接近,使用和掌握非常簡單。與時俱進,例如說現在最新的 jdbi3,增加了流式編程函數式等編程風格。源代碼的實現思路非常清晰,有一種美感。使用 jdbi 封裝出的數據庫代碼也非常清晰。

jdbi 的兩種風格

Fluent Api

<code>handle.createUpdate ("INSERT INTO user (id, name) VALUES (:id, :name)") .bind ("id", 2) .bind ("name", "Clarice") .execute ();/<code>

這裡就是 java8 的流式風格,用連貫式表達式將一個 sql 實現串在一起

Declarative Api

<code>// Define your own declarative interface public interface UserDao { @SqlUpdate ("CREATE TABLE user (id INTEGER PRIMARY KEY, name VARCHAR)") void createTable (); @SqlUpdate ("INSERT INTO user (id, name) VALUES (?, ?)") void insertPositional (int id, String name); @SqlUpdate ("INSERT INTO user (id, name) VALUES (:id, :name)") void insertNamed (@Bind ("id") int id, @Bind ("name") String name); @SqlUpdate ("INSERT INTO user (id, name) VALUES (:id, :name)") void insertBean (@BindBean User user); @SqlQuery ("SELECT * FROM user ORDER BY name") @RegisterBeanMapper (User.class) List listUsers (); }/<code>

聲明式的主要是使用註解來實現,在實際的面向對象風格的代碼中,我個人覺得聲明式的比較簡潔,容易閱讀和維護。所以下面都按照 Declarative Api 的方式。

一些關鍵性的問題

對於 jdbi 的實現,需要自己去看 jdbi 的主頁,http://jdbi.org/,這裡講一些實際使用中遇到的需要注意到的問題

返回自動遞增的主鍵

jdbc 方式怎麼做的呢?

<code>try { Connection conn = DBUtil2.getConnection (); //PreparedStatement ps = // conn.prepareStatement (SAVE_SQL, new String [] { "id" }); // 應該返回生成的主鍵,上下兩種方式都可 PreparedStatement ps = conn.prepareStatement (SAVE_SQL,PreparedStatement.RETURN_GENERATED_KEYS); ps.setString (1, user.getName ()); ps.setFloat (2, user.getSalary ()); ps.setInt (3, user.getAge ()); if (ps.executeUpdate () > 0) { // 獲取主鍵 ResultSet rs = ps.getGeneratedKeys (); rs.next (); int i = rs.getInt (1); user.setId (i); ps.close (); return true; } ps.close (); } catch (SQLException e) { e.printStackTrace (); } finally { DBUtil2.closeConnection (); }/<code>

jdbi 提供的機制:

<code>public interface UserDao { @SqlBatch ("INSERT INTO users (name) VALUES (?)") @GetGeneratedKeys List createUsers (String... names); }/<code>

非常直觀簡潔

查詢

jdbc 方式,我們在查詢大數據量時,一般使用數據庫遊標,逐條查詢。 jdbi 的查詢是什麼樣的呢?如下:

<code>public interface UserDao { @SqlQuery ("select name from users") List listNames (); }/<code>

但是這個時候,如果遇到大數據量怎麼辦,jdbi 提供的解決方案:

<code>public interface UserDao { @SqlQuery ("select name from users") ResultIterator getNamesAsIterator (); }/<code>

這裡使用了迭代器,依次去查詢,和 jdbi 遊標的作用是一樣的。

批量插入

jdbi 的插入,當一個列表插入,如果要提升效率,就是拆分插入,拆分插入 jdbi 提供了機制 SqlBatch

<code>public interface UserDao { @SqlBatch ("insert into users (tenant_id, id, name)" + "values (:tenantId, :user.id, :user.name)") void bulkInsert (@Bind ("tenantId") long tenantId, @BindBean ("user") User... users); }/<code>

小結

jdbi 是非常簡潔優美的數據庫中間件組件,當在數據庫唯一特別是 pg 數據庫,個人認為是首選方式,有效的把 jdbc 封裝了一下,更加適合於開發。

資源後花園:https://gitee.com/alterem/picFB/raw/master/pics/2020/05/20/1569337870.png