Mybatis 和 Solon 在一起的升級版

劉之西東發表於2020-08-17

終於說通 Solon 作者,讓他為 Solon 框架新增事務註解支援了;並且把 mybatis-solon-plugin 的 @Df 註解更名為 @Db ,接地氣多了(Df是什麼鬼呢?新手肯定這麼想...)。真是費盡了筆者的口水。。。此文主要重寫《Mybatis 和 Solon 勾搭在一起》的事務部分,並優化細節。

新故事相關的原始碼

https://gitee.com/noear/solon_demo/tree/master/demo08.solon_mybatis_multisource

新故事開講

Mybatis 是個資深的前輩,多年來它基本上只和 Spring 的家族企業合作。今天他嘗試和年輕選手Solon組隊做業務;Solon 是Java世界裡一個新的極易上手的Web框架(哎,如同十八線的演員,沒人知道的啦。。。但業務活也是一流的)

本次組隊需要完成如下挑戰:

  1. 簡單的配置
  2. 多資料來源支援(分割槽模式 和 註解模式)
  3. 事務支援
  4. 支援分頁元件(這個,其實破壞了SQL的透明性......但業內很流行)

Action...

一、環境說明

環境 版本
IDEA 2020.2
Maven 4.0
Solon 1.0.12 (這是升級版啊)
mybatis-solon-plugin 1.0.12
mybatis-sqlhelper-solon-plugin 1.0.12
Mybatis 5.3.3
JDK 1.8

二、現在程式碼走起

新建個空白的Maven專案:solon_mybatis_multisource,下面開始操作:

  • (一)在 pom.xml 檔案裡新增依賴
<parent>
    <groupId>org.noear</groupId>
    <artifactId>solon-parent</artifactId>
    <version>1.0.12</version>
    <relativePath />
</parent>

<dependencies>
    <dependency>
        <groupId>org.noear</groupId>
        <artifactId>solon-web</artifactId>
        <type>pom</type>
    </dependency>

    <dependency>
        <groupId>org.noear</groupId>
        <artifactId>mybatis-solon-plugin</artifactId>
    </dependency>
    
    <dependency>
        <groupId>org.noear</groupId>
        <artifactId>mybatis-sqlhelper-solon-plugin</artifactId>
    </dependency>
    
    <!-- 其它依賴參考原始碼,不然佔板面太多了  -->
</dependencies>
  • (二)修改屬性檔案 application.yml (新增多資料來源和分佈元件的配置)

Solon 沒有特定的資料來源配置,所以隨便自己起個頭就可以;配置項與使用的資料來源匹配即可。本例用的是HikariCP

#資料庫1的配置
test.db1:
    schema: rock
    jdbcUrl: jdbc:mysql://localdb:3306/rock?useUnicode=true&characterEncoding=utf8&autoReconnect=true&rewriteBatchedStatements=true
    driverClassName: com.mysql.cj.jdbc.Driver
    username: demo
    password: UL0hHlg0Ybq60xyb

#資料庫2的配置(其實我用的是同一個庫)
test.db2:
    schema: rock
    jdbcUrl: jdbc:mysql://localdb:3306/rock?useUnicode=true&characterEncoding=utf8&autoReconnect=true&rewriteBatchedStatements=true
    driverClassName: com.mysql.cj.jdbc.Driver
    username: demo
    password: UL0hHlg0Ybq60xyb


#預設(這個可以換成:mybatis.db1)
mybatis:
    typeAliases:    #支援包名 或 類名(.class 結尾)
        - "webapp.model"
    mappers:        #支援包名 或 類名(.class 結尾)或 xml(.xml結尾)
        - "webapp.dso.mapper.AppxMapper.class"

#再定義個新配置(為了體現多資料來源性 - 應該簡單吧?)
mybatis.db2:
    typeAliases:
        - "webapp.model"
    mappers:
        - "webapp.dso.mapper.Appx2Mapper.class"


#分頁元件的配置
sqlhelper:
    mybatis:
        instrumentor:
            dialect: "mysql"
            cache-instrumented-sql: true
            subquery-paging-start-flag: "[PAGING_StART]"
            subquery-paging-end-flag: "[PAGING_END]"
        pagination:
            count: true
            default-page-size: 10
            use-last-page-if-page-no-out: true
            count-suffix: _COUNT
  • (三)新增配置器(完成會話工廠的構建 及 Mapper 的描述與關聯;看上去,挺簡潔的)

Spring 的@MapperScan 需要多個配置器才可以完成多源,這個太煩人了;所以mybatis-solon-plugin把它調整成一個函式,故多個資料來源可以整到一個配置器玩了:

@XConfiguration
public class Config {
    @XBean("db1")
    public SqlSessionFactory db1(@XInject("${test.db1}") HikariDataSource dataSource) {
        //
        //此處用了預設的配置(也可以用:mybatis.db1 進行配置)
        //
        return new MybatisAdapter(dataSource)
                .mapperScan()   //類似Spring 的 @MapperScan註解的功能
                .getFactory();
    }

    @XBean("db2")
    public SqlSessionFactory db2(
            @XInject("${test.db2}") HikariDataSource dataSource,  
            @XInject("${mybatis.db2}") Properties props) {
        //
        //此處指定了 配置 ${mybatis.db2}
        //
        return new MybatisAdapter(dataSource, props)
                .mapperScan()
                .getFactory();
    }
}
  • (四)新增控制器

關於多資料來源的分包模式示例:

/**
 * 分包模式,一開始就被會話工廠mapperScan()並關聯好了
 * */
@XMapping("/demo/")
@XController
public class DemoController {
    @XInject
    AppxMapper appxMapper;      //已被db1 mapperScan 了,可直接注入

    @XInject
    Appx2Mapper appxMapper2;    //已被db2 mapperScan 了,可直接注入

    @XMapping("test")
    public AppxModel test(){
        return appxMapper.appx_get();
    }

    @XMapping("test2")
    public AppxModel test2(){
        return appxMapper2.appx_get2(48);
    }

}

關於多資料來源的註解模式示例:

/**
 * 註解模式,通過@Db注入,並指定具體的會話工廠
 *
 * @Db 可注入 Mapper, SqlSession, SqlSessionFactory 型別的欄位
 * */
@XMapping("/demo2/")
@XController
public class Demo2Controller {
    @Db("db1")
    AppxMapper appxMapper;     //使用@Db 指定會話工廠並注入

    @Db("db2")
    Appx2Mapper appxMapper2;

    @XMapping("test")
    public AppxModel test(){
        return appxMapper.appx_get();
    }

    @XMapping("test2")
    public AppxModel test2(){
        return appxMapper2.appx_get2(48);
    }

}

關於事務的示例:(分散式環境下,儘量用訊息代理JDBC事務)

/**
 * 事務演示
 * */
@XMapping("/tran/")
@XController
public class TranController {
    @XInject
    AppxMapper appxMapper;

    /**
     * mybatis-solon-plugin 的事務,由 @XTran 註解發起(更詳細的說明,以後發個新文說明)
     * */
    @XTran("db1")
    @XMapping("test")
    public Object test() throws Throwable{
        appxMapper.appx_get();
    }
}

關於多資料來源事務的示例,需要用到Service層:(分散式環境下,儘量用訊息代理JDBC事務)

/**
 * 多資料來源事務演示
 * */
@XMapping("/tran2/")
@XController
public class Tran2Controller {
    @XInject
    AppService appService;   //這是定義的Service類,裡面的函式註解了@XTran("db1")

    @XInject
    App2Service app2Service;    //同上


    /**
     * 申明這是一個多資料來源的事務(這個可以放在任何事務的最外層;用於管理下面的子事務)
     * */
    @XTran(multisource = true)
    @XMapping("test")
    public void test() throws Throwable {
        //內部申明瞭用db2的事務
        app2Service.add();

        //內部申明瞭用db1的事務
        appService.add();
    }
}

關於分頁的示例:(本案用的是sqlhelper)

@XMapping("/page/")
@XController
public class PageController {
    @XInject
    AppxMapper appxMapper;

    @XMapping("test")
    public Object test() throws Throwable{
        SqlPaginations.preparePagination(2,2);

       return appxMapper.appx_get_page();
    }
}
  • (五)略過的一些程式碼檔案(直接看開頭的相關原始碼)

故事結尾

加了事務註解後,終於優雅了。。。所有組隊挑戰全部完成,OY...

相關文章