flea-frame-db使用之基於EntityManager實現JPA分表的數據庫操做

基於EntityManager實現JPA分表的數據庫操做

本文采用 EclipseLink的JPA實現,相關JPA接入使用請移步個人另外幾篇博文html

首先仍是討論一下,實現JPA分表的增刪改查操做,咱們須要作什麼:java

  • 分表規則定義(即從主表到分表的轉換實現)
  • 分表操做實現(即EntityManager根據分表規則操做具體分表)

1. EntityManager持久化操做

經常使用接口方法以下:git

// 新增
    void persist(Object var1);
    // 更新
    <T> T merge(T var1);
    // 刪除
    void remove(Object var1);
    // 查找
    <T> T find(Class<T> var1, Object var2);

下面來分析一下上述增刪改查的接口方法實現:github

org.eclipse.persistence.internal.jpa.EntityManagerImpl數據庫

  • persist
    入參 : 實體對象實例
    出參 : 無
    flea-frame-db使用之基於EntityManager實現JPA分表的數據庫操做
    org.eclipse.persistence.internal.sessions.UnitOfWorkImpl
    flea-frame-db使用之基於EntityManager實現JPA分表的數據庫操做
  • merge
    入參 : 實體對象實例
    出參 : 實體對象實例
    flea-frame-db使用之基於EntityManager實現JPA分表的數據庫操做
    flea-frame-db使用之基於EntityManager實現JPA分表的數據庫操做
  • remove
    入參 : 實體對象實例
    出參 : 無
    flea-frame-db使用之基於EntityManager實現JPA分表的數據庫操做
    flea-frame-db使用之基於EntityManager實現JPA分表的數據庫操做
  • find
    入參 : 實體類Class, 實體類主鍵
    出參 : 實體對象實例
    flea-frame-db使用之基於EntityManager實現JPA分表的數據庫操做

而後咱們須要瞭解下getDescriptor方法的具體實現 :緩存

org.eclipse.persistence.internal.sessions.AbstractSession
flea-frame-db使用之基於EntityManager實現JPA分表的數據庫操做
flea-frame-db使用之基於EntityManager實現JPA分表的數據庫操做
ClassDescriptor 最後都會被緩存到 lastDescriptorAccessed 變量。session

最後切到debug視圖,查看一下 ClassDescriptor,從中能夠看到 與實際表名相關的 DatabaseTable
flea-frame-db使用之基於EntityManager實現JPA分表的數據庫操做
到了這一步,咱們已經知道了表名存儲在DatabaseTable中,要想實現分表操做,勢必須要動態改變這裏的值。app

下面給出上述咱們須要作的事情的解決方案:eclipse

2. 分表規則定義

實體類中定義的表名,咱們能夠理解爲主表名;分表名的命名規則首先須要肯定一下,定義以下配置:ide

<?xml version="1.0" encoding="UTF-8"?>
<tables>

    <!-- 定義分表配置
        name : 分表對應的主表名
        exp  : 分表名錶達式 (FLEA_TABLE_NAME)_(列名大寫)_(列名大寫)
    -->
    <table name="flea_login_log" exp="(FLEA_TABLE_NAME)_(CREATE_DATE)" desc="Flea登陸日誌表分表規則">
        <splits>
            <!-- 定義分表後綴
                key : 分表類型關鍵字 (可查看 com.huazie.frame.db.common.table.split.TableSplitEnum )
                column : 分表屬性列字段名
                implClass : 分表後綴轉換實現類
            -->
            <split key="yyyymm" column="create_date" implClass="com.huazie.frame.db.common.table.split.impl.YYYYMMTableSplitImpl"/>
        </splits>
    </table>

</tables>

分表規則相關實現代碼,能夠移步 GitHub 查看 TableSplitHelper

3. 分表操做實現

在上述分表規則定義中, 咱們能夠看到分表名錶達式exp是由 主表名 和 分表字段 組成,分表字段的轉換實現規則由split定義。
分表處理者實現 EclipseLinkTableSplitHandler

@Override
    public void handle(EntityManager entityManager, Object entity, boolean isRead) throws Exception {

        if (ObjectUtils.isEmpty(entityManager) || ObjectUtils.isEmpty(entity)) {
            return;
        }

        // 獲取分表信息(包括主表名 和 分表名 【若是存在分表返回】)
        SplitTable splitTable = EntityUtils.getSplitTable(entity);

        // 存在分表,則須要操做具體分表
        if (StringUtils.isNotBlank(splitTable.getSplitTableName())) {
            // 獲取可用的數據庫會話對象
            AbstractSession session;
            if (isRead) {
                session = entityManager.unwrap(AbstractSession.class);
            } else {
                session = entityManager.unwrap(RepeatableWriteUnitOfWork.class);
            }
            // 從新設置 查詢的分表表名
            session.getDescriptor(entity.getClass()).setTableName(splitTable.getSplitTableName());
        }
    }

JPA分表的增刪改查操做相關代碼能夠 移步 GitHub 查看 AbstractFleaJPADAOImplEclipseLinkTableSplitHandler

4. 自測

自測類能夠查看 LoginLogAuthTest

4.1 新增數據

@Test
    public void testFleaLoginLogInsert() {
        try {
            IFleaLoginLogSV fleaLoginLogSV = (IFleaLoginLogSV) applicationContext.getBean("fleaLoginLogSV");
            FleaLoginLog fleaLoginLog = new FleaLoginLog();
            fleaLoginLog.setAccountId(1000000L);
            fleaLoginLog.setSystemAccountId(2000L);
            fleaLoginLog.setLoginIp4("127.0.0.1");
            fleaLoginLog.setLoginState(1);
            fleaLoginLog.setLoginTime(DateUtils.getCurrentTime());
            fleaLoginLog.setCreateDate(DateUtils.getCurrentTime());
            Long fleaLoginId = fleaLoginLogSV.getFleaNextValue(fleaLoginLog);
            fleaLoginLog.setLoginLogId(fleaLoginId);
            // 保存至分表
            fleaLoginLogSV.save(fleaLoginLog);
        } catch (Exception e) {
            LOGGER.error("Exception:", e);
        }
    }

4.2 查詢數據

@Test
    public void testFleaLoginLogQuery() {
        try {
            IFleaLoginLogSV fleaLoginLogSV = (IFleaLoginLogSV) applicationContext.getBean("fleaLoginLogSV");
            FleaLoginLog fleaLoginLog = new FleaLoginLog();
            fleaLoginLog.setCreateDate(DateUtils.getCurrentTime());
            fleaLoginLog = fleaLoginLogSV.queryNew(1L, fleaLoginLog);
            LOGGER.debug("FleaLoginLog = {}", fleaLoginLog);
        } catch (Exception e) {
            LOGGER.error("Exception:", e);
        }
    }

4.3 更新數據

@Test
    public void testFleaLoginLogUpdate() {
        try {
            IFleaLoginLogSV fleaLoginLogSV = (IFleaLoginLogSV) applicationContext.getBean("fleaLoginLogSV");
            FleaLoginLog fleaLoginLog = new FleaLoginLog();
            fleaLoginLog.setCreateDate(DateUtils.getCurrentTime());
            fleaLoginLog = fleaLoginLogSV.queryNew(1L, fleaLoginLog);
            LOGGER.debug("FleaLoginLog = {}", fleaLoginLog);
            // 更新記錄(分表)
            fleaLoginLog.setLogoutTime(DateUtils.getCurrentTime());
            fleaLoginLog.setDoneDate(DateUtils.getCurrentTime());
            fleaLoginLog.setLoginState(2);
            fleaLoginLog.setRemarks("用戶退出登錄");
            fleaLoginLogSV.update(fleaLoginLog);
        } catch (Exception e) {
            LOGGER.error("Exception:", e);
        }
    }

4.4 刪除數據

@Test
    public void testFleaLoginLogDelete() {
        try {
            IFleaLoginLogSV fleaLoginLogSV = (IFleaLoginLogSV) applicationContext.getBean("fleaLoginLogSV");
            FleaLoginLog fleaLoginLog = new FleaLoginLog();
            fleaLoginLog.setCreateDate(DateUtils.getCurrentTime());
            fleaLoginLogSV.removeNew(1L, fleaLoginLog);
        } catch (Exception e) {
            LOGGER.error("Exception:", e);
        }
    }
相關文章
相關標籤/搜索