數據庫中間件-jdbi

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

數據庫中間件-jdbi

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 封裝了一下,更加適合於開發。

數據庫中間件-jdbi

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


分享到:


相關文章: