PetaPojo —— JAVA版的PetaPoco

来源:http://www.cnblogs.com/bagegejin/archive/2016/12/23/6216402.html
-Advertisement-
Play Games

背景 由於工作的一些原因,需要從C#轉成JAVA。之前PetaPoco用得真是非常舒服,在學習JAVA的過程中熟悉了一下JAVA的數據組件: MyBatis 非常流行,代碼生成也很成熟,性能也很好。但是DEBUG的時候不方便,且XML寫SQL也不是很適應,尤其是團隊比較小沒有專職DBA的情況下。 H ...


背景

由於工作的一些原因,需要從C#轉成JAVA。之前PetaPoco用得真是非常舒服,在學習JAVA的過程中熟悉了一下JAVA的數據組件:

  • MyBatis 非常流行,代碼生成也很成熟,性能也很好。但是DEBUG的時候不方便,且XML寫SQL也不是很適應,尤其是團隊比較小沒有專職DBA的情況下。
  • Hibernate 使用過NHibernate,做企業應用倒是挺適合的。掌握並用好它不是一件很容易的事情,尤其是團隊水平不夠,目標項目為互聯網游戲平臺的時候。
  • sql2o 開源項目,輕量級的ORM,與Dapper,PetaPoco非常類似,感覺上還是沒有PetaPoco好用。

基於以上的理解,便打算造一個JAVA版的PetaPoco —— PataPojo

  • 處於學習JAVA階段,能夠學習並使用一些高級語法
  • 理解JAVA的基礎資料庫組件
  • 若開發成功,則原有的團隊與項目基本上能夠很好地遷移至JAVA開發環境,提升開發效率

功能概述

  • 輕量級
  • 用於簡單的POJO
  • 泛型的增刪改查的幫助方法提供
  • 自動分頁,自動計算出總記錄數及頁數據
  • 簡單的事務支持
  • 暫時僅支持MYSQL
  • 更好的參數支持
  • 仍然使用SQL語法,並提供強大的Sql生成器類
  • 開源

下載

怎麼使用

引用jar包

下載petapojo.jar包後,在項目中進行引用

執行查詢

實體Mapping

// 對應表 user_info
@TableName("user_info")
// 主鍵映射,欄位名,是否自增
@PrimaryKey(value = "id",autoIncrement = true)
public class UserInfo {

    private int id;
    private String userName;

    // 列名與欄位名的映射 (若無註解,則按欄位名映射為列名)
    @Column("password")
    private String password;

    // 該欄位不進行映射
    @Ignore
    private String none;

    //... getter and setter
}

下一步,使用database.java進行查詢:


DruidDataSource dataSource = new DruidDataSource();
// 配置dataSource
// ...
Database database = new Database(dataSource);
List<UserInfo> userList = database.query(UserInfo.class, "SELECT * FROM user_info");

for (UserInfo userInfo : userList) {
       System.out.println(userInfo.getUserName());
}

查詢第一行第一列:

Integer number = database.executeScalar(Integer.class,
        "SELECT COUNT(1) FROM user_info");

或者,查找第一條記錄:

UserInfo userInfo = database.firstOrDefault(UserInfo.class,
        "SELECT * FROM user_info WHERE id = ?",123);

分頁

// 參數說明:
// 1  - 頁索引
// 10 - 頁大小
// 20 - 是指 age > ? 的參數值
PageInfo<UserInfo> pagedList = database.pagedList(UserInfo.class, 1,10,
                "SELECT * FROM user_info WHERE age > ? ORDER BY createDate DESC",20);

返回的PageInfo描述:

/**
 * 分頁泛型
 */
public class PageInfo<T> {
    // 當前頁索引
    private int currentPage;
    // 總頁數
    private int totalPages;
    // 總記錄數
    private int totalItems;
    // 每頁記錄數
    private int itemsPrePage;
    // 當前頁列表
    private List<T> items;

    public PageInfo() {
        items = new ArrayList<>();
    }

    // ...
    // getter and setter
}

執行沒有返回的SQL:

// 返回影響行數
int row = database.executeUpdate("DELETE FROM user_info WHERE id = ?",123);

實體的增刪改
新增:

UserInfo userInfo = new UserInfo();
userInfo.setUserName("PetaPojo");
userInfo.setPassword("123123");

database.insert(userInfo);

修改:

UserInfo userInfo = database.firstOrDefault(UserInfo.class,
            "SELECT * FROM user_info WHERE id = ?", 1);
userInfo.setPassword("123456");

database.update(userInfo);

刪除:

UserInfo userInfo = database.firstOrDefault(UserInfo.class,
            "SELECT * FROM user_info WHERE id = ?", 1);
database.delete(userInfo);

// 或者 根據主鍵刪除
database.delete(UserInfo.class,1);

// 或者 根據條件進行刪除
database.delete(UserInfo.class,"WHERE id = ?",1);

自動添加查詢列

當我們在使用ORM時,我們常常需要先編寫查詢列名及表名的SQL語句SELECT * FROM user_info,其實是非常影響開發效率的。
因此,PetaPojo增加了自動添加查詢列與表名的自動匹配功能。
例如:

UserInfo userInfo = database.firstOrDefault(UserInfo.class,
        "SELECT * FROM user_info WHERE id = ?", 1);

PetaPojo可以允許簡化為:

UserInfo userInfo = database.firstOrDefault(UserInfo.class,"WHERE id = ?",1);

查詢組裝器 Sql Builder

在我們查詢資料庫時,經常需要添加一些條件或排序之類的。總之,儘可能地讓SQL語句動態化或更靈活,以應對複雜的業務需要。
與此同時,如果我們只是進行單純的SQL硬編寫,開發效率將會是一個很大的問題,維護亦比較複雜費時。

在此基礎上,PetaPojo提供了一個非常便捷的SQL查詢組裝器。

基礎模式:

int id = 1;
Sql sql = Sql.create()
        .append("SELECT * FROM user_info")
        .append("WHERE id = ?",id);
UserInfo userInfo = database.firstOrDefault(UserInfo.class,sql);

或者:

int id = 1;
Sql sql = Sql.create()
        .append("SELECT * FROM user_info")
        .append("WHERE id = ?", id)
        .append("AND createDate >= ?", DateTime.now());
UserInfo userInfo = database.firstOrDefault(UserInfo.class, sql);

同樣,可以根據不同的條件來進行組裝:

int id = 1;
Sql sql = Sql.create()
        .append("SELECT * FROM user_info")
        .append("WHERE id <> ?", id)

if(age != null)
     sql.append("AND age > ?", age);

if(startDate != null)
    sql.append("AND createDate >= ?", startDate);

List<UserInfo> userList = database.query(UserInfo.class,sql);

在SQL組裝時,參數列表是無限的,只需要與SQL語句中的參數替代符?相匹配即可,如:

int id = 1;
DateTime now = DateTime.now();

Sql sql = Sql.create()
        .append("SELECT * FROM user_info")
        .append("WHERE id <> ? AND createDate >= ?", id, now);

List<UserInfo> userList = database.query(UserInfo.class,sql);

Sql.append的基礎上,PetaPojo提供了更為便捷的鏈式函數:

Sql sql = Sql.create()
        .select("*")
        .from("user_info")
        .where("id = ?", 1)
        .where("createDate >= ?", DateTime.now().toString())
        .where("age >= ? AND age <= ?", 10, 20)
        .orderBy("createDate DESC");

PageInfo<UserInfo> pagedList = database.pagedList(UserInfo.class,1,10,sql);

基於自動添加查詢列的功能,上述語句可變改為:

Sql sql = Sql.create() 
        .where("id = ?", 1)
        .where("createDate >= ?", DateTime.now())
        .where("age >= ? AND age <= ?", 10, 20)
        .orderBy("createDate DESC");

PageInfo<UserInfo> pagedList = database.pagedList(UserInfo.class,1,10,sql);

因此,在一些複雜的查詢中,我們可這樣用:

int id = 1;
Sql sql = Sql.create() 
        .where("id <> ?", id)

if(age != null)
     sql.where("age > ?", age);

if(startDate != null)
    sql.where("createDate >= ?", startDate);

sql.orderBy("createDate DESC");

List<UserInfo> userList = database.query(UserInfo.class,sql);

枚舉支持

在開發中,經常會碰到一些需要使用枚舉的地方,如訂單狀態,用戶類型等。
JAVA預設枚舉類型不是很好用,最主要的問題在於:用戶類型,訂單狀態這些枚舉在系統中我們可以理解為一個鍵值對的列表,而JAVA預設枚舉的index是不可自定義的。

因此,PetaPojo在枚舉的支持上做了一些擴展。

首先,PetaPojo定義了一個枚舉介面:

/**
 * 枚舉必須要實現的介面
 */
public interface IEnumMessage {

    int getValue();

    String getName();
}

並提供了一個枚舉幫助類:

public class EnumUtils {

    private static final ReentrantReadWriteLock rrwl = new ReentrantReadWriteLock();
    private static final ReentrantReadWriteLock.ReadLock rl = rrwl.readLock();
    private static final ReentrantReadWriteLock.WriteLock wl = rrwl.writeLock();
    private static Map<Class<? extends IEnumMessage>, Map<Integer, IEnumMessage>> ENUM_MAPS = new HashMap<>();

    /**
      * 根據key以及枚舉類型,得到具體的枚舉對象
      */
    public static <T extends IEnumMessage> T getEnum(Class<T> type, int value) {
        return (T) getEnumValues(type).get(value);
    }

     /**
      * 將枚舉類型轉化為一個鍵值對的Map
      */
    public static <T extends IEnumMessage> Map<Integer, String> getEnumItems(Class<T> type) {
        Map<Integer, IEnumMessage> map = getEnumValues(type);
        Map<Integer, String> resultMap = new HashMap<>();
        map.forEach((k, v) -> {
            resultMap.put(k, v.getName());
        });
        return resultMap;
    }

    private static <T extends IEnumMessage> Map<Integer, IEnumMessage> getEnumValues(Class<T> clazz) {
        rl.lock();
        try {
            if (ENUM_MAPS.containsKey(clazz))
                return ENUM_MAPS.get(clazz);
        } finally {
            rl.unlock();
        }

        wl.lock();
        try {
            if (ENUM_MAPS.containsKey(clazz))
                return ENUM_MAPS.get(clazz);

            Map<Integer, IEnumMessage> map = new HashMap<>();
            try {
                for (IEnumMessage enumMessage : clazz.getEnumConstants()) {
                    map.put(enumMessage.getValue(), enumMessage);
                }
            } catch (Exception e) {
                throw new RuntimeException("getEnumValues error", e);
            }
            ENUM_MAPS.put(clazz, map);

            return map;
        } finally {
            wl.unlock();
        }
    }
}

進而,在項目使用枚舉(如UserType)時,實現IEnumMessage介面即可:


/**
 * 用戶類型
 */
public enum UserType implements IEnumMessage {

    Student(1,"學生"),
    Teacher(2,"老師"),
    Coder(4,"碼農");

    private int value;
    private String name;

    UserType(int value,String name){
        this.value = value;
        this.name = name;
    }

    @Override
    public int getValue() {
        return this.value;
    }

    @Override
    public String getName() {
        return this.name;
    }
}

對應的實體:

@TableName("user_info")
@PrimaryKey(value = "id",autoIncrement = true)
public class UserInfo {

    private int id;
    private String userName;
    private String password;

    // 直接使用枚舉,資料庫中作為int型進行存儲
    private UserType userType;

    // ...  getter setter
}
UserInfo userInfo = database.firstOrDefault(UserInfo.class,
        "SELECT * FROM user_info WHERE id = ?",1);
// 設置用戶類型為碼農
userInfo.setUserType(UserType.Coder);

database.update(userInfo);

時間類型支持 org.joda.time.DateTime

PetaPojo支持org.joda.time.DateTime類型,映射的資料庫表欄位類型為datetime

@TableName("user_info")
@PrimaryKey(value = "id",autoIncrement = true)
public class UserInfo {

    private int id;
    private String userName;
    private String password;

    // 直接使用枚舉,資料庫中作為int型進行存儲
    private UserType userType;

    private DateTime createDate;

    // ...  getter setter
}

當SQL查詢中的參數值為org.joda.time.DateTime時,這樣使用:

Sql sql = Sql.create()
            .where("createDate >= ?",DateTime.now().toString());
// 將DateTime類型toString即可

以上便是整體PetaPojo的主要功能。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • web部件是ASP.NET WebForm裡面的伺服器控制項,它涵蓋的內容比較多,鑒於這種狀況的話鄙人不打算深究下去了,只是局限於瞭解web.config配置裡面的配置內容則可。 那麼也得稍微說說啥是Web部件。引用MSDN的話:ASP.NET Web 部件是一組集成控制項,用於創建網站使最終用戶可以直 ...
  • 在上一篇C#多線程之線程同步2中,我們主要學習了AutoResetEvent構造、ManualResetEventSlim構造和CountdownEvent構造,在這一篇中,我們將學習Barrier構造、ReaderWriterLockSlim構造和SpinWait構造。 七、使用Barrier構造 ...
  • #region 發送郵件 //填寫電子郵件地址,和顯示名稱 System.Net.Mail.MailAddress from = new System.Net.Mail.MailAddress("[email protected]", "wode"); //填寫郵件的收件人地址和名稱 ... ...
  • 瞭解過入口函數 Main() 嗎?帶你用批處理玩轉 Main 函數 目錄 簡介 特點 方法的參數 方法的返回值 與批處理交互的一個示例 簡介 我們知道,新建一個控制台應用程式的時候,IDE 會同時創建一個預設的類 Program.cs,該類會包含一個 Main 方法。我們在直接 F5 的時候就會立即 ...
  • 1、ViewBag Controller:ViewBag.Message = "Hello, Word"; View:@ViewBag.Message 註:ViewBag的類型是動態的,不確定的,直接就可以使用,它的傳值範圍是:controller向view傳值,view自己和自己傳值。2、View ...
  • 實現效果如下: 1.在前臺Web的Category Menu顯示 Vendor; 2.點擊Vendor 顯示Vendor List列表; 主要配置步驟: 1.運行網站 Admin 後臺 Categorys 增加 Vendor 並配置其SEO 如vendor-all 2.代碼層面 Nop.Web In ...
  • 然ASP.NET Core應用的路由是通過RouterMiddleware這個中間件來完成的,但是具體的路由解析功能都落在指定的Router對象上,不過我們依然有必要以代碼實現的角度來介紹一下這個中間件。 ...
  • 有時需要追求效率,會代替一些算術運算。 求商:a >> n <=> a / 2^n 求積:a << n <=> a * 2^n 求餘:a & ((1 << n) - 1) <=> a % 2^n 奇偶判斷:a & 1 == 1 <==> a % 2 == 1 一般1表示選中或者開啟項,0表示未選或者 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...