[simple-orm-mybaits]基於Mybatis的ORM封裝介紹

[toc]html

simple-orm-mybatis在github開源,直接跳轉查看,歡迎你們fork和star。有什麼建議也能夠提出,我會盡快修復或實現。java

前言

最先接觸Java的web開發框架就是SSH,其中的H就是Hibernate。Hibernate做爲最出名的Java的ORM框架,如今的版本已經到了5.3.10.Final,6.0.0.Alpha2。圍繞數據持久化或者DAL層也發展了多種工具,Hibernate Validator目前也是在不少的企業框架中被用做數據有效性檢查。 接下來還有用過JPA來實現ORM。JPA全稱Java Persistence API,是JSR-220(EJB3.0)規範的一部分,在JSR-220中規定實體對象(EntityBean)由JPA進行支持。在個人使用中,實際上底層實現仍然使用了Hibernate,只是標註或者操做類都是使用了JPA的接口標準而沒有直接使用Hibernate。 Hibernate具備強大的ORM封裝能力,極大的簡化了CUD的操做,並且無需作太多的配置,使用標準註解就能解決不少問題。簡單的查詢操做也不在話下,多級關聯、延遲查詢等豐富特性基本上也能夠說是極大覆蓋了開發過程的各類需求。可是實際上在這麼多團隊中,不少人的反饋是這樣的:「Hibernate的ORM確實很方便,可是在一些特殊條件下很難用,好比複雜查詢就很難控制語句生成的效率」。Hibernate有三種查詢方式:HQL、Criteria、Native Sql。確實在複雜查詢下,若是使用Criteria,確實可以拼出想要的語句,可是可能對於其中的方法要很是熟悉,學習曲線很高,沒辦法作到團隊中每一個成員都能數量輕易的掌握,並且後期的審覈很困難沒法直接看清邏輯。HQL和NativeSql對個人感受,彷佛回到了JSP時代,HTML和Java代碼混寫,很難忍受。這時候你們找到了另外的框架Mybatis。mysql

ORM框架現狀

截止(2019/5/27)Mybatis的Star是10806,UsedBy140381;Hibernate的Star是3817,UsedBy157879。看使用量Hibernate和Mybatis其實已經差很少了,實際企業開發中,Mybatis可能還會更多一些。git

Mybatis優缺點

Mybatis放棄了Hibernate的強封裝,主要包含了映射的部分,並且放棄了自動解析生成Sql,而直接使用用戶XML配置Sql的方式,只是在Sql的拼接上提供了一些標籤來避免重複代碼。這樣的討巧之處在於:github

  • 門檻下降:開發人員不須要了解框架的內部語法,只須要了解Sql語法便可。
  • 可讀性提升:審覈代碼時,很容易的就能看清楚多級關聯以及關聯使用的條件、語法是否正確。
  • 維護方便:當查詢語法出錯時,Mybatis只須要修改XML,而Hibernate則須要修改代碼從新編譯,操做相對複雜。

缺點也有幾處:web

  • 簡單操做複雜:因爲放棄了自動解析生成Sql,因此普通的CUD也須要手動編寫Sql
  • 實體映射覆雜:必須在XML文件中配置大量的字段映射
  • SqlMapper中的sql id風險:因爲XML中的sql id是一個字符串,只能複製粘貼出來,因此出錯的概率也比較大。

實際上,針對上面缺點,Mybatis也提供瞭解決方案。 先說sql id的,在新的Mybatis中,實際上已經採用了面向接口的編碼方式,以下面的例子:算法

接口類spring

public interface UserMapper {
    public User findUserById(Integer id);
}

mapper的xml文件sql

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.software5000.mapper.dao.UserMapper">
    <select id="findUserById" resultType="com.software5000.entity.User" parameterType="int" >
        select * from user where id =#{id}
    </select>
</mapper>

這樣就能夠直接調用sql語句:數據庫

UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
User user = userMapper.findUserById(1);

再說映射覆雜的,Mybatis提供了MyBatis Generator做爲解決方案,一個命令生成下列內容:

  • 匹配表結構的Java POJOs。可能包括:
    • 表結構中主鍵字段(若是存在主鍵)
    • 表結構中的非主鍵字段(除了BLOB字段)
    • 表結構中的BLOB字段(若是有BLOB字段)
    • 動態查詢、更新和刪除的接口類

自動生成也可以合理的生成類之間的繼承關係。注意生成器也可以定義生產不一樣的POJO層次 - 例如若是你想要能夠爲每一個表格生成一個單獨的領域對象。

  • Mybatis/iBATIS兼容的SQL MAP的XML文件。按照配置針對每一個表生成簡單的增刪改查的SQL方法。生成的SQL包括:
    • 插入
    • 按主鍵更新
    • 使用example更新 (使用動態的where條件)
    • 按主鍵刪除
    • 使用example刪除 (使用動態的where條件)
    • 按主鍵查詢
    • 使用example查詢 (使用動態的where條件)
    • 使用example統計

生成的SQL語句取決於表格的結構(例如,表格若是沒有主鍵,就不會生成按主鍵更新的方法)

Java客戶端生成類可以合理使用上面的對象。生成的Java客戶端類也是有選擇性的。

  • 使用Mybatis 3.x的會生成:
    • 一個mapper接口和XML中的語句id相同,用於直接調用。
  • 使用iBATIS 2.x的會生成:
    • 適用於Spring框架的DAO層
    • 使用IBATIS SQL映射API的DAO層。這些DAO可使用兩種方式:使用構造函數提供SqlMapClient,或者經過注入方式提供。
    • DAOs that conform to the iBATIS DAO Framework (an optional part of iBATIS, this framework is now deprecated and we suggest that you use the Spring framework instead)
    • iBATIS的DAO框架符合的DAO層(iBATIS的一個額外部分,可是如今這個框架已經失效了,因此建議使用Spring DAO的框架代替)

可是,我對於MyBatis Generator的態度是堅決的反對。緣由是我認爲自動生成違反了簡單的原則,「如無必要,勿增實體」。自動生成的可複用性和可讀性必定是比較差的。我以爲最好的代碼就是不存在的代碼。所以我但願可以有一個簡單框架在Mybatis之上,接入簡單無侵入,可以提供基本的增刪改查方法。這就是下面的 simple-orm-mybatis 。

simple-orm-mybatis設計思路介紹

simple-orm-mybatis設計的初衷就是但願提供一個簡單無侵入,並且無需編寫或者生成任何代碼就可使用直接操做對象的方式來進行增刪改查的操做。要實現這樣的要求,主要是兩個主要技術點:

  1. 利用反射機制對應實體對象與數據庫結構
  2. 解析對象而且生成對應操做的SQL語句

第一點核心就是反射,設計要點以下:

  • Java對象與數據庫結構的對應規則
  • 虛字段(無數據庫對應字段)的處理
  • 考慮多層繼承的對象解析
  • 值的設置與獲取方式

第二點核心在於SQL解析,設計要點以下:

  • 根據不一樣入口區分基本CRUD語法結構
  • 字段(列名)須要分爲值字段與查詢字段兩類
  • 更新操做的時候,Null,空,有值的區分
  • 支持多種匹配操做符(大於、小於、Like等)

simple-orm-mybatis使用說明

  1. 首先引入依賴,項目已經發布在Maven Central上,能夠直接引入。
<dependency>
    <groupId>com.software5000</groupId>
    <artifactId>simple-orm-mybatis</artifactId>
    <version>1.0.2</version>
</dependency>
  1. 接着須要將 BaseDaoMapper.xml 文件放在你的 mapper 的掃描文件夾內。

  2. 最後須要在你的代碼中添加一個 BaseDao 實現類,用於提供數據庫操做服務(注意:須要在spring的掃描包內,由於須要注入某些屬性),整個複製便可,類名能夠改成你本身須要的名字

import com.software5000.base.BaseDao;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

/**
 * 整個類以 <code>org.mybatis:mybatis-spring:2.0.0</code> 的 <code>org.mybatis.spring.supportSqlSessionDaoSupport</code>
 * 爲參考編寫而成
 */
@Component
public class MyBaseDao extends BaseDao {
    private SqlSessionTemplate sqlSessionTemplate;
    
    public MyBaseDao() {
            // 在默認構造函數中設置 數據庫是否蛇形, 數據庫格式大小寫, 通用忽略的字段名稱
            this.initConfig(true,false,"serialVersionUID");
    }
        
    @Resource
    public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
        if (this.sqlSessionTemplate == null || sqlSessionFactory != this.sqlSessionTemplate.getSqlSessionFactory()) {
            this.sqlSessionTemplate = this.createSqlSessionTemplate(sqlSessionFactory);
        }
    }

    protected SqlSessionTemplate createSqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
        return new SqlSessionTemplate(sqlSessionFactory);
    }

    @Override
    public SqlSession getSqlSession() {
        return this.sqlSessionTemplate;
    }
}

simple-orm-mybatis實際使用

這裏給了一個單元測試的例子,實際通常是在service層直接使用,無需添加任何代碼。 示例中的 DailyRecord 是一個普通實體類,沒有任何繼承。

// 獲取啓動類,加載配置,肯定裝載 Spring 程序的裝載方法,它回去尋找 主配置啓動類(被 @SpringBootApplication 註解的)
@SpringBootTest
// 讓 JUnit 運行 Spring 的測試環境, 得到 Spring 環境的上下文的支持
@RunWith(SpringRunner.class)
public class BaseDaoTest {

    @Autowired
    private MyBaseDao myBaseDao;

    @Test
    public void testBaseDao(){
        DailyRecord dailyRecord = new DailyRecord();
        List<DailyRecord> dailyRecords = myBaseDao.selectEntity(dailyRecord);
        System.out.println(dailyRecords.size());
    }
}

推薦最佳實踐

雖然說總體的設計基於無侵入,基本沒有任何前提,可是仍是有一些推薦的實踐但願你們可以去嘗試:


一、 數據結構設計建議包含int類型的自增主鍵設計,名稱叫id。 緣由:不少時候咱們的業務主鍵是有一套特定規則,可是頗有可能面對修改,因此底層關聯主鍵統一使用id關聯在後期面對修改時影響較小。 弊端: 1. 如mysql中int最長2147483647,考慮到自增id可能會有跳過不連續的狀況,須要考慮實際可用的存儲量。不過大部分的業務表是到不了這個數量級的。 2. mysql的InnoDB有自增主鍵鎖表的問題,超大併發插入可能會影響效率。不過在5.1.22有提供了改進的策略。


二、 數據結構與實體結構儘可能符合統一轉換規則。 緣由:這樣研發過程當中,實體與數據庫的映射會比較簡單,無需大量的自定義。建議的規則有三類: - 兩邊都使用駝峯。 - 實體使用駝峯,數據庫使用全小寫蛇形 - 實體使用駝峯,數據庫使用全大寫蛇形


三、 代碼中實體的字段類型使用封裝類型而不是基本類型 緣由:基本類型是有默認值存在,而數據庫中咱們一旦設置字段可空,就會有NULL值存在。因此建議所有使用封裝類型。下面附上各類基本類型的默認值

基本類型 默認值
byte 0
short 0
int 0
long 0L
float 0.0f
double 0.0d
char ‘\u0000’
boolean false

四、 分頁算法 緣由:分頁推薦使用PageHelper,是利用Mybatis的底層插件機制修改Sql語句,也是無侵入。


更多說明

更多說明,能夠參考github上的wiki頁面

相關文章
相關標籤/搜索