如何搭建mybatisPlus模块及其多数据源配置

  • 一般来说应该是MybatisPlus和common模块 一起放在一个common模块上,方便演示则将MybatisPlus拆出来单独为一个模块

骨架图演示

在这里插入图片描述

依赖maven

  • 依赖项目公共模块
   <dependencies>
         <dependency>
            <groupId>com.xk100</groupId>
            <artifactId>xk-practice-common</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>com.xk100</groupId>
            <artifactId>xk-practice-entity</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.3.14</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>com.zaxxer</groupId>
            <artifactId>HikariCP</artifactId>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-tx -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
        </dependency>
    </dependencies>

config配置包

  • 在实体类新增/更新到数据库时 对特定属性值做自动填充操作
  • 实体类上加以下注解
//插入时填充字段
  @TableField(
        value = "gmt_create",
        fill = FieldFill.INSERT
    )
    private LocalDateTime gmtCreate;
    @TableField(
        value = "create_by",
        fill = FieldFill.INSERT
    )
    private String createBy;
    
//插入和更新时填充字段
   @TableField(
        value = "gmt_update",
        fill = FieldFill.INSERT_UPDATE
    )
    private LocalDateTime gmtUpdate;

    @TableField(
        value = "update_by",
        fill = FieldFill.INSERT_UPDATE  
    )
    private String updateBy;

GlobalMetaObjectHandler.class(属性填充配置类)

  • 对应以上的注解指定操作 的自动填充配置类
package com.xk.practice.mybatisplus.config;

import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;

/**
 * <p>
 * Mybatis Plus 自定义元对象字段填充控制器,实现公共字段自动写入
 * <p>
 */
@Component
@Slf4j
public class GlobalMetaObjectHandler implements MetaObjectHandler {

    /**
     * 创建时间
     */
    private final String gmtCreate = "gmtCreate";
    /**
     * 修改时间
     */
    private final String gmtUpdate = "gmtUpdate";

    /**
     * 新增时填充的字段
     *
     * @param metaObject
     */
    @Override
    public void insertFill(MetaObject metaObject) {
        setInsertFieldValByName(gmtCreate, LocalDateTime.now(), metaObject);
        setInsertFieldValByName(gmtUpdate, LocalDateTime.now(), metaObject);
    }

    /**
     * 更新时需要填充字段
     *
     * @param metaObject
     */
    @Override
    public void updateFill(MetaObject metaObject) {
        setUpdateFieldValByName(gmtUpdate, LocalDateTime.now(), metaObject);
    }
}

MybatisPlusConfig.clas

import com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import com.baomidou.mybatisplus.extension.plugins.SqlExplainInterceptor;
import com.xk.practice.common.constant.EnvConstant;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import javax.sql.DataSource;

/**
 * <p>
 * Mybatis Plus配置类
 * </p>
 *
 */
@EnableTransactionManagement
@Configuration
@ConditionalOnBean({DataSource.class})
@AutoConfigureAfter(DataSourceAutoConfiguration.class)
//@PropertySource("classpath:mybatis.properties")
public class MybatisPlusConfig {

	/**
	 * 分页插件,自动识别数据库类型
	 */
	@Bean
	public PaginationInterceptor paginationInterceptor() {
		return new PaginationInterceptor();
	}

	/**
	 * 乐观锁插件
	 */
	@Bean
	public OptimisticLockerInterceptor optimisticLockerInterceptor() {
		return new OptimisticLockerInterceptor();
	}

	/**
	 * 执行分析插件
	 */
	@Bean
	@Profile({EnvConstant.LOCAL,EnvConstant.DEV,EnvConstant.TEST })
	public SqlExplainInterceptor sqlExplainInterceptor() {
		return new SqlExplainInterceptor();
	}



}

PracticeMyBatisPlusConfig.class

import com.xk.practice.mybatisplus.constant.PackageConstant;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Configuration;

@MapperScan(value = {PackageConstant.Mapper_PACKAGE})
@Configuration
public class PracticeMyBatisPlusConfig extends MybatisPlusConfig {

    public PracticeMyBatisPlusConfig(){
        System.out.println("*** PracticeMyBatisPlusConfig.init ***");
    }

}

多数据源配置(重要细节)

  • 多数据源要通过类上面的注解@MapperScan 区分不同数据源对应扫描的包(演示的是v1v1second两个数据源对应扫描的路径)
  • 若多数据源扫描同一个包,则以主数据源为主进行操作
  • 两个数据源配置是一样的,区别在于扫描mapper包路径不同,以及引用文件的账号密码等参数不同,以及主数据源必须贴@Primary注解

DataSourceConfig1.class

import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import com.xk.practice.mybatisplus.constant.PackageConstant;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import javax.sql.DataSource;

@Configuration
@PropertySource("classpath:mybatis.properties") //加载子模块自己的application.properties
@MapperScan(value = PackageConstant.Mapper_PACKAGE, sqlSessionTemplateRef = "db1SqlSessionTemplate")
public class DataSourceConfig1 {

    @Primary // 表示这个数据源是默认数据源, 这个注解必须要加,因为不加的话spring将分不清楚那个为主数据源(默认数据源)
    @Bean(name="db1DataSource")
    @ConfigurationProperties(prefix = "spring.datasource.one") //读取application.yml中的配置参数映射成为一个对象
    public DataSource DataSource() {
        return DataSourceBuilder.create().build();
    }

    @Primary
    @Bean(name="db1SqlSessionFactory")
    public SqlSessionFactory db1SqlSessionFactory(@Qualifier("db1DataSource") DataSource dataSource) throws Exception {
        MybatisSqlSessionFactoryBean bean = new MybatisSqlSessionFactoryBean();
        bean.setDataSource(dataSource);
        // mapper的xml形式文件位置必须要配置,不然将报错:no statement (这种错误也可能是mapper的xml中,namespace与项目的路径不一致导致)
        bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:mapper/**/*.xml"));
        return bean.getObject();
    }


    @Primary
    @Bean(name="db1SqlSessionTemplate")
    public SqlSessionTemplate db1SqlSessionTemplate(@Qualifier("db1SqlSessionFactory") SqlSessionFactory sqlSessionFactory){
        return new SqlSessionTemplate(sqlSessionFactory);
    }
}

DataSourceConfig2.class

import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import com.xk.practice.mybatisplus.constant.PackageConstant;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;

import javax.sql.DataSource;

@Configuration
@PropertySource("classpath:mybatis.properties") //加载子模块自己的application.properties
@MapperScan(basePackages = PackageConstant.Mapper_PACKAGE_SECOND, sqlSessionTemplateRef = "db2SqlSessionTemplate")
public class DataSourceConfig2 {

//    @Primary // 表示这个数据源是默认数据源, 这个注解必须要加,因为不加的话spring将分不清楚那个为主数据源(默认数据源)
    @Bean("db2DataSource")
    @ConfigurationProperties(prefix = "spring.datasource.second")
    public DataSource DataSource() {
        return DataSourceBuilder.create().build();
    }

//    @Primary
    @Bean("db2SqlSessionFactory")
    public SqlSessionFactory db1SqlSessionFactory(@Qualifier("db2DataSource") DataSource dataSource) throws Exception {
        MybatisSqlSessionFactoryBean bean = new MybatisSqlSessionFactoryBean();
        bean.setDataSource(dataSource);
        bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:mapper/**/*.xml"));
        return bean.getObject();
    }

//    @Primary
    @Bean("db2SqlSessionTemplate")
    public SqlSessionTemplate db1SqlSessionTemplate(@Qualifier("db2SqlSessionFactory") SqlSessionFactory sqlSessionFactory){
        return new SqlSessionTemplate(sqlSessionFactory);
    }
}

mybatis.properties

  • 放在resources资源包下
spring.datasource.one.driver-class-name = com.mysql.cj.jdbc.Driver
spring.datasource.one.jdbcUrl = jdbc:mysql://ip地址/数据库名?useUnicode=true&useSSL=false&characterEncoding=utf8&serverTimezone=Asia/Shanghai
spring.datasource.one.username = xxxxx
spring.datasource.one.password = xxxx
spring.datasource.second.driver-class-name = com.mysql.cj.jdbc.Driver
spring.datasource.second.jdbcUrl = jdbc:mysql://xxxxx
spring.datasource.second.username = xxxxx
spring.datasource.second.password = xxxx

constant常量包

PackageConstant.class

  • 记录各微服务统一的骨架路径位置
public interface PackageConstant {

	/**
	 * 顶级包
	 */
	String BASE_PACKAGE = "com.edt.practice.mybatisplus.";

	/**
	 * entity包路径
	 */
	String EENTITY_PACKAGE = BASE_PACKAGE + ".**.entity";

	/**
	 * mapper包路径
	 */
	String Mapper_PACKAGE = BASE_PACKAGE + "**.mapper.v1";

	String Mapper_PACKAGE_SECOND = BASE_PACKAGE + "**.mapper.v1second";

}

事务管理配置包

TransactionManagerConfig.class

import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.interceptor.TransactionInterceptor;

import javax.annotation.Resource;
import java.util.Properties;

/**
 * 事务管理配置类
 */
@Configuration
public class TransactionManagerConfig {

    public static final String transactionExecution = "execution(* com.xk..service..*(..))";
    @Resource
    private PlatformTransactionManager transactionManager;

    @Bean
    public TransactionInterceptor transactionInterceptor() {
        Properties attributes = new Properties();
        attributes.setProperty("get*", "PROPAGATION_SUPPORTS,-Exception,readOnly");
        attributes.setProperty("select*", "PROPAGATION_SUPPORTS,-Exception,readOnly");
        attributes.setProperty("list*", "PROPAGATION_SUPPORTS,-Exception,readOnly");
        attributes.setProperty("page*", "PROPAGATION_SUPPORTS,-Exception,readOnly");
        attributes.setProperty("find*", "PROPAGATION_SUPPORTS,-Exception,readOnly");
        attributes.setProperty("has*", "PROPAGATION_SUPPORTS,-Exception,readOnly");
        attributes.setProperty("locate*", "PROPAGATION_REQUIRED,-Exception,readOnly");
        attributes.setProperty("register*", "PROPAGATION_REQUIRED,-Exception");
        attributes.setProperty("save*", "PROPAGATION_REQUIRED,-Exception");
        attributes.setProperty("insert*", "PROPAGATION_REQUIRED,-Exception");
        attributes.setProperty("update*", "PROPAGATION_REQUIRED,-Exception");
        attributes.setProperty("batch*", "PROPAGATION_REQUIRED,-Exception");
        attributes.setProperty("do*", "PROPAGATION_REQUIRED,-Exception");
        attributes.setProperty("lock*", "PROPAGATION_REQUIRED,-Exception");
        attributes.setProperty("add*", "PROPAGATION_REQUIRED,-Exception");
        attributes.setProperty("del*", "PROPAGATION_REQUIRED,-Exception");
        attributes.setProperty("modify*", "PROPAGATION_REQUIRED,-Exception");
        attributes.setProperty("auth*", "PROPAGATION_REQUIRED,-Exception");
        TransactionInterceptor txAdvice = new TransactionInterceptor(transactionManager, attributes);
        return txAdvice;
    }

    @Bean
    public DefaultPointcutAdvisor defaultPointcutAdvisor() {
        AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
        pointcut.setExpression(transactionExecution);
        DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor();
        advisor.setPointcut(pointcut);
        Properties attributes = new Properties();
        attributes.setProperty("get*", "PROPAGATION_SUPPORTS,-Exception,readOnly");
        attributes.setProperty("select*", "PROPAGATION_SUPPORTS,-Exception,readOnly");
        attributes.setProperty("list*", "PROPAGATION_SUPPORTS,-Exception,readOnly");
        attributes.setProperty("page*", "PROPAGATION_SUPPORTS,-Exception,readOnly");
        attributes.setProperty("find*", "PROPAGATION_SUPPORTS,-Exception,readOnly");
        attributes.setProperty("has*", "PROPAGATION_SUPPORTS,-Exception,readOnly");
        attributes.setProperty("locate*", "PROPAGATION_REQUIRED,-Exception,readOnly");
        attributes.setProperty("register*", "PROPAGATION_REQUIRED,-Exception");
        attributes.setProperty("save*", "PROPAGATION_REQUIRED,-Exception");
        attributes.setProperty("insert*", "PROPAGATION_REQUIRED,-Exception");
        attributes.setProperty("update*", "PROPAGATION_REQUIRED,-Exception");
        attributes.setProperty("batch*", "PROPAGATION_REQUIRED,-Exception");
        attributes.setProperty("do*", "PROPAGATION_REQUIRED,-Exception");
        attributes.setProperty("lock*", "PROPAGATION_REQUIRED,-Exception");
        attributes.setProperty("add*", "PROPAGATION_REQUIRED,-Exception");
        attributes.setProperty("del*", "PROPAGATION_REQUIRED,-Exception");
        attributes.setProperty("modify*", "PROPAGATION_REQUIRED,-Exception");
        attributes.setProperty("auth*", "PROPAGATION_REQUIRED,-Exception");
        TransactionInterceptor txAdvice = new TransactionInterceptor(transactionManager, attributes);
        advisor.setAdvice(txAdvice);
        return advisor;
    }


}

启动类

  • 继承该模块的启动类写法
import com.xk.practice.config.apiversion.EnableApiVersioning;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

@EnableFeignClients(basePackages = "com.xk")
@EnableDiscoveryClient
@SpringBootApplication(scanBasePackages = {"com.edt.practice"})
@EnableSwagger2
@EnableApiVersioning
public class ApiApplication {

	public static void main(String[] args) {
		SpringApplication.run(ApiApplication.class, args);
	}

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值