天天看點

SpringBoot中整合使用jFinal的ActiveRecord并支援多資料源和事務

在一些特殊場景,我們用到了Spring Boot,資料ORM層并沒有使用流行的hibernate或mybatis,而采用了國内開源的jFinal中的ActiveRecord。不要問為什麼不直接使用jFinal,就是這麼個特殊需求。

在我們的需求中,需要使用多個資料源,并支援事務,下面是配置的詳細過程。

依賴包的版本:

springboot 2.3.0.RELEASE

jFinal ActiveRecord 4.8

mysql connector java 5.1.20

druid 1.1.22

一、spring boot 整合jFinal的ActiveRecord

1.1 pom.xml中的包依賴:

<properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <springboot.version>2.3.0.RELEASE</springboot.version>
        <jfinal.activerecord.version>4.8</jfinal.activerecord.version>
        <mysql.version>5.1.20</mysql.version>
        <druid.version>1.1.22</druid.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.jfinal</groupId>
            <artifactId>activerecord</artifactId>
            <version>${jfinal.activerecord.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>${springboot.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>${springboot.version}</version>
            <exclusions>
                <!-- 移除 tomcat 以使用 undertow -->
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-tomcat</artifactId>
                </exclusion>
                <!-- 去掉logback配置 -->
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-logging</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <!-- 使用實務 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
            <version>${springboot.version}</version>
            <exclusions>
                <!-- 去掉logback配置 -->
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-logging</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-undertow</artifactId>
            <version>${springboot.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-log4j2</artifactId>
            <version>${springboot.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <version>${springboot.version}</version>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>${mysql.version}</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>${druid.version}</version>
        </dependency>
    </dependencies>
           

1.2 建立 JfinalActiveRecordConfig java檔案:

如下:

@Configuration
public class JfinalActiveRecordConfig {
    /**
     * 主資料源名稱
     */
    private static final String MAIN_DATA_SOURCE_CONFIG = "main";


    @Bean
    @ConfigurationProperties("spring.datasource.main")
    public DruidDataSource masterDataSource(){
        return new DruidDataSource();
    }

    /**
     * 主資料源
     * @return
     */
    @Bean
    public ActiveRecordPlugin initMainActiveRecord() {
        ActiveRecordPlugin arp = new ActiveRecordPlugin(MAIN_DATA_SOURCE_CONFIG, masterDataSource());

        arp.addMapping("emp", Emp.class);

        arp.start();

        return arp;
    }
}
           

1.3 在application.yml配置檔案裡增加

spring:
  # 資料源配置
  datasource:
    main: #主資料源
      driverClassName: com.mysql.jdbc.Driver
      url: jdbc:mysql://localhost:3306/csdn1
      username: root
      password: 123456
           

至此已經完成了spingboot和activerecord的整合,接下來加入多資料源的支援。

二、多資料源支援

2.1 在application.yml增加第二個資料源

spring:
  # 資料源配置
  datasource:
    main: #主資料源
      driverClassName: com.mysql.jdbc.Driver
      url: jdbc:mysql://localhost:3306/csdn1
      username: root
      password: 123456
    biz: #業務資料源
      driverClassName: com.mysql.jdbc.Driver
      url: jdbc:mysql://localhost:3306/csdn2
      username: root
      password: 123456
           

2.2 修改JfinalActiveRecordConfig,加入第二個資料源的支援

/**
     * 主資料源名稱
     */
    private static final String MAIN_DATA_SOURCE_CONFIG = "main";

    /**
     * 業務資料源名稱
     */
    private static final String BIZ_DATA_SOURCE_CONFIG = "biz";

    @Bean
    @ConfigurationProperties("spring.datasource.main")
    public DruidDataSource masterDataSource(){
        return new DruidDataSource();
    }

    @Bean
    @ConfigurationProperties("spring.datasource.biz")
    public DruidDataSource bizDataSource(){
        return new DruidDataSource();
    }

    /**
     * 主資料源
     * @return
     */
    @Bean
    public ActiveRecordPlugin initMainActiveRecord() {
        ActiveRecordPlugin arp = new ActiveRecordPlugin(MAIN_DATA_SOURCE_CONFIG, masterDataSource());

        arp.addMapping("emp", Emp.class);

        arp.start();

        return arp;
    }

    /**
     * 業務資料源
     * @return
     */
    @Bean
    public ActiveRecordPlugin initBizActiveRecord() {
        ActiveRecordPlugin arp = new ActiveRecordPlugin(BIZ_DATA_SOURCE_CONFIG, bizDataSource());
// 第二個資料源如何和第一個資料有相同的表,則不需要重複映射,隻需要在調用時指定資料源即可
//        arp2.addMapping("emp", Emp.class);

        arp.start();

        return arp;
    }
           

2.3 調用不同資料源的方式:

// 預設使用主資料源
Emp emp = Emp.dao.findById(1);
System.out.println(emp.getStr("name"));

// 調用其他資料源
Emp emp3 = new Emp().use("biz").findById(1);
System.out.println(emp3.getStr("name"));

// 也可以這樣
Record emp2 = Db.use("biz").findFirst("select * from emp where id = 1");
System.out.println(emp2.getStr("name"));
           

三、資料庫的事務支援

(注意:隻支援同一資料源的事務)

修改JfinalActiveRecordConfig

@Configuration
public class JfinalActiveRecordConfig {
    /**
     * 主資料源名稱
     */
    private static final String MAIN_DATA_SOURCE_CONFIG = "main";

    /**
     * 業務資料源名稱
     */
    private static final String BIZ_DATA_SOURCE_CONFIG = "biz";

    @Bean
    @ConfigurationProperties("spring.datasource.main")
    public DruidDataSource masterDataSource(){
        return new DruidDataSource();
    }

    @Bean
    @ConfigurationProperties("spring.datasource.biz")
    public DruidDataSource bizDataSource(){
        return new DruidDataSource();
    }

    /**
     * 主資料源
     * @return
     */
    @Bean
    public ActiveRecordPlugin initMainActiveRecord() {
        ActiveRecordPlugin arp = new ActiveRecordPlugin(MAIN_DATA_SOURCE_CONFIG, masterTransactionAwareDataSourceProxy());

        arp.addMapping("emp", Emp.class);
        arp.addMapping("emp_balance", EmpBalance.class);

        arp.start();

        return arp;
    }

    /**
     * 業務資料源
     * @return
     */
    @Bean
    public ActiveRecordPlugin initBizActiveRecord() {
        ActiveRecordPlugin arp = new ActiveRecordPlugin(BIZ_DATA_SOURCE_CONFIG, bizTransactionAwareDataSourceProxy());

//        arp2.addMapping("emp", Emp.class);

        arp.start();

        return arp;
    }

    /**
     * 設定資料源代理
     */
    @Bean
    public TransactionAwareDataSourceProxy masterTransactionAwareDataSourceProxy() {
        TransactionAwareDataSourceProxy transactionAwareDataSourceProxy = new TransactionAwareDataSourceProxy();
        transactionAwareDataSourceProxy.setTargetDataSource(masterDataSource());
        return transactionAwareDataSourceProxy;
    }

    @Bean
    public TransactionAwareDataSourceProxy bizTransactionAwareDataSourceProxy() {
        TransactionAwareDataSourceProxy transactionAwareDataSourceProxy = new TransactionAwareDataSourceProxy();
        transactionAwareDataSourceProxy.setTargetDataSource(bizDataSource());
        return transactionAwareDataSourceProxy;
    }

    /**
     * 設定事務管理
     */
    @Bean(name="mainDataSourceTransactionManager")
    public DataSourceTransactionManager masterDataSourceTransactionManager() {
        DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
        dataSourceTransactionManager.setDataSource(masterTransactionAwareDataSourceProxy());
        return dataSourceTransactionManager;
    }

    @Bean(name="bizDataSourceTransactionManager")
    public DataSourceTransactionManager bizDataSourceTransactionManager() {
        DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
        dataSourceTransactionManager.setDataSource(bizTransactionAwareDataSourceProxy());
        return dataSourceTransactionManager;
    }
}
           

之前的 ActiveRecordPlugin arp = new ActiveRecordPlugin(MAIN_DATA_SOURCE_CONFIG, masterDataSource());

換成了 

ActiveRecordPlugin arp = new ActiveRecordPlugin(MAIN_DATA_SOURCE_CONFIG, masterTransactionAwareDataSourceProxy());

接着在service中加入注解 @Transactional(transactionManager="mainDataSourceTransactionManager", rollbackFor = Exception.class)

如下:

@Service
public class EmpBalanceService {

    @Transactional(transactionManager="mainDataSourceTransactionManager", rollbackFor = Exception.class)
    public void addBalance() {
        // 這個應該不能儲存進表中才對
        new EmpBalance().set("emp_id", 1)
                .set("balance", 10).save();

        Emp emp = Emp.dao.findById(1);

        // 這裡故意寫錯,以測試實務
        emp.set("name", "超出長度的字元串用于測試錯誤").update();
    }
}
           

四、源碼下載下傳

源碼的test裡面有測試用例,sql檔案夾下有建表語句,下載下傳位址:https://github.com/Liamliu/spring-jfinal-activerecord

繼續閱讀