入坑mybatis-plus

前言

之前我寫過一篇《mybatis分頁插件pagehelper的基本使用方法》。當(dāng)時主要是圖簡單,引入簡單,使用簡單,不用想那么多功能。不過最近,我對自己進(jìn)行了深入的反思。覺得自己太過于糾結(jié)代碼的細(xì)節(jié)了。其實(shí),之前查過mybatis plus,但是由于學(xué)習(xí)成本有些高,封裝的功能有點(diǎn)多,就不太像學(xué)它。另外,由于我對于實(shí)體的建立,增刪改查的操作邏輯,各層對象的屬性把控都提出了很高的要求,要求研發(fā)人員注意思考并實(shí)現(xiàn)。于是,就造成了像mybatis plus這種可以快速幫助我們進(jìn)行增刪改查的框架發(fā)揮不了多大作用。
但是,后來我進(jìn)行了自我的深入反思。反觀一年來團(tuán)隊的建設(shè)內(nèi)容,說實(shí)話,少的可憐。而且,質(zhì)量也不見得多高。為什么呢?因為,我無法和我自己合作,研發(fā)人員和我是兩個個體,我無法對他們提出對我自己的要求,因為他們不知道我在想什么,我接下來想到了什么。另外,由于建設(shè)思考的多,速度就慢下來了,所以反饋循環(huán)走的少,自然質(zhì)量高不起來,自己再怎么思考也是空想,需要結(jié)合實(shí)踐的反饋才有現(xiàn)實(shí)意義。
而且,最近我 突然想通了。其實(shí),大部分的操作就是快速的增刪改查。因為,有了基礎(chǔ)的數(shù)據(jù),才能夠進(jìn)行更高層面的設(shè)計和建設(shè)。所謂設(shè)計能力,不是憑空設(shè)計和想象的能力,而是在變化和不確定中帶著項目一步一步向前走的能力。所以,現(xiàn)在我要擁抱mybatis plus這種生產(chǎn)力工具啦。(熟悉之后,我還希望能夠參與這個開源項目)

引入

這次的引入費(fèi)了我不小的周折呀。先說正確的引入方法吧,其實(shí)很簡單:

  1. 引入mybatis-plus-boot-starter,配好DataSource。其實(shí)這樣就完成了引入,就可以使用了。
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.3.1</version>
</dependency>
  1. 但是,我是老項目改造,所以還有些后續(xù)工作,就是修改SqlSessionFactory的bean,之前這個bean是直接使用Mybatis的Bean,這里要改成Mybatis plus的bean
@Bean
public SqlSessionFactory sqlSessionFactory() throws Exception {
    MybatisSqlSessionFactoryBean fb = new MybatisSqlSessionFactoryBean();
    fb.setDataSource(dataSource);// 指定數(shù)據(jù)源(這個必須有,否則報錯)
    return fb.getObject();
}
  1. 這一步其實(shí)可有可無,但是鑒于我費(fèi)了那么大的勁,還是寫上吧,就是調(diào)整好依賴。由于我引入的starter的springboot的版本和項目原本的版本并不一致,所以起初我以為是這個原因。但是,后來經(jīng)過問題的排查和解決,基本可以確定不是這里的原因。但是,調(diào)整的過程中,卻出現(xiàn)過Application找不到上下文的問題,起原因是2.1.x和2.2.x的差異導(dǎo)致的。這也是我最近發(fā)現(xiàn)的,即現(xiàn)在spring里面第二位版本號的差異也可能導(dǎo)致一些兼容性問題了。

使用BaseMapper

其實(shí),這個使用也很簡單,但是因為我引入的過程是那它做的第一個例子。所以,這里還是介紹下我驗證過的一些事情。

  1. 首先,在官方文檔中都是使用MapperScan來劃定引入范圍的,其實(shí)使用Mapper注解是同樣生效的。
  2. BaseMapper的生效一是依賴于Mapper的掃描,而是你需要使用mybatis plus的SqlSessionFactory,就是我在引入章節(jié)第二點(diǎn)寫的。
  3. 能找到Mapper了,我們還需要標(biāo)志實(shí)體對應(yīng)的是哪張表,主鍵是誰。這通過在類上的注解TableName和屬性上的注解TableId來解決這個問題。
  4. 它對應(yīng)的操作會自動的把實(shí)體中駝峰的命名轉(zhuǎn)換為下劃線分隔的命名方式,不一致的可以自己通過注解指明。但是,需要注意的是,java的數(shù)據(jù)類型要和數(shù)據(jù)庫的對應(yīng)上。我把我驗證過的數(shù)據(jù)類型列在了下面,由于我使用的是PostgreSQL,所以這里的數(shù)據(jù)類型是PostgreSQL的
JAVA類型 PostgreSQL類型
Integer int(4)
Long int(8)
Boolean bool
String varchar
  1. 說了這么多都沒說怎么用。其實(shí)很簡單,建立自己的Mapper接口,然后讓他繼承BaseMapper并指定實(shí)體泛型即可

常用注解

TableName

我主要用來標(biāo)志表名是誰。在使用自定義的TypeHandler的時候,可以打在屬性上,然后設(shè)置autoResultMap為true。別的功能就沒用過了。

TableId

用來標(biāo)志誰是主鍵

TableField

這個是打在屬性上的。對屬性做的事情基本都在這里。我用過的功能有:

  • 設(shè)置數(shù)據(jù)庫對應(yīng)的列名。駝峰和下劃線是自動轉(zhuǎn)換的,無法自動轉(zhuǎn)換就得自己寫了。
  • 設(shè)置自定義的TypeHandler,比如我自己寫的JsonTypeHandler
  • 設(shè)置更新策略,比如我的updatetime和createtime都是數(shù)據(jù)庫自動更新,就需要設(shè)置插入和更新的策略忽略他們。還有一些,具體看官方文檔吧。

使用條件構(gòu)造器進(jìn)行條件查詢

其實(shí),早期的時候我并沒有把這個算成吸引我的東西。不過隨著寫的業(yè)務(wù)的深入,能夠直接使用java的條件構(gòu)造器自定義where語句,而不是想著怎么兼容各種可能有的沒有的條件去寫可以參數(shù)化的sql語句,這個確實(shí)是省了不少心的。這對于編碼量和研發(fā)時間是非常直接的節(jié)約,同時由于不用自己設(shè)計了,也會減少很多bug的產(chǎn)生,很實(shí)用。
具體的使用其實(shí)也很簡單,官方的指南中有條件構(gòu)造器的章節(jié)。它整體上都是基于其AbstractWrapper。其下,針對select和Update有特定的實(shí)現(xiàn)類,使用對應(yīng)的接口實(shí)現(xiàn)想要的功能就好。并不復(fù)雜。具體的使用,我就不贅述了,官網(wǎng)文檔講的很清楚:https://mybatis.plus/guide/wrapper.html#abstractwrapper 我的使用方式一般如下:

//我這個例子里用到了分頁參數(shù),需要自行構(gòu)建。
LambdaQueryWrapper<YourEntity> queryWrapper= Wrappers.lambdaQuery();
//下面根據(jù)你的條件構(gòu)造需要對queryWrapper進(jìn)行調(diào)整,比如下面:
//記錄ID
if(condition.getRecordId()!=null){
    queryWrapper=queryWrapper.eq(SensorBatchEntity::getRecordId,condition.getRecordId());
}
//最后,使用構(gòu)造好的queryWrapper進(jìn)行查詢即可。
IPage<YourEntity> data= this.sensorBatchDao.selectPage(page,queryWrapper);

下面要說的是一些小眾的操作。

自定義條件拼接

由于我的表里面有PostgreSQL的jsonb字段,使用jsonb里的值進(jìn)行查詢時,預(yù)定好的條件語句就顯得不夠用了。這個時候,就需要其條件構(gòu)造器中的apply方法進(jìn)行支持了。它的聲明如下:

apply(String applySql, Object... params)
apply(boolean condition, String applySql, Object... params)

這個方法里,可以放置你自定義的條件語句的sql,比如下面的形式:

apply("((light_source->>'ps')::int2={0} or (light_source->>'led')::int2={0})",queryCondition.getLightSource())

light_source的數(shù)據(jù)類型是jsonb,根據(jù)值中的屬性進(jìn)行查詢和篩選在mybatis plus中是不支持的。但是,我有不想自己寫一個查詢方法,于是就找到了apply方法來解決這個問題。在上述代碼中,可以看到我們使用了字符串的{index}來拼接語句。這樣是可以防止sql注入的,如果不用這種形式,直接拼接好字符串放進(jìn)去,也是可以的,但是無法防止sql注入。

分頁插件

默認(rèn)mybatis-plus是沒有配置分頁插件的。所以,即使你按照官網(wǎng)提供的方法調(diào)用了,也會發(fā)現(xiàn),分頁并沒有生效。我的配置代碼如下:

    @Bean
    public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
        MybatisSqlSessionFactoryBean fb = new MybatisSqlSessionFactoryBean();
        // 指定數(shù)據(jù)源(這個必須有,否則報錯)
        fb.setDataSource(dataSource);

        //分頁插件
        PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
        // 設(shè)置請求的頁面大于最大頁后操作, true調(diào)回到首頁,false 繼續(xù)請求  默認(rèn)false
        // paginationInterceptor.setOverflow(false);
        // 設(shè)置最大單頁限制數(shù)量,默認(rèn) 500 條,-1 不受限制
        // paginationInterceptor.setLimit(500);
        // 開啟 count 的 join 優(yōu)化,只針對部分 left join
        paginationInterceptor.setDbType(DbType.POSTGRE_SQL);
        paginationInterceptor.setCountSqlParser(new JsqlParserCountOptimize(true));


        fb.setPlugins(paginationInterceptor);
        // 開啟 數(shù)據(jù)庫字段 下劃線 轉(zhuǎn)駝峰
        //fb.getObject().getConfiguration().setMapUnderscoreToCamelCase(true);
        return fb.getObject();
    }

總之,就是使用mybatis-plus提供的SqlSessionFactory來創(chuàng)建SqlSession,并把分頁插件配置進(jìn)去,就可以了。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容