项目集成seata和mybatis-plus冲突问题解决方案:(分页插件失效, 自动填充失效, 自己注入的id生成器失效 找不到mapper文件解决方案)

2021-12-15

项目集成seata和mybatis-plus,seata与mybatis-plus冲突问题(所有插件失效,自动填充失效,找不到mapper文件解决方案)

自动填充代码:

package com.from.mybatis.handler;
​
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;
​
import java.util.Date;
​
@Component
public class MyBatisMetaObjectHandler implements MetaObjectHandler {
    /**
     * 自定义插入时填充规则
     */
    @Override
    public void insertFill(MetaObject metaObject) {
        // 注意是类属性字段名称,不是表字段名称
        this.setFieldValByName("createTime", new Date(), metaObject);
        this.setFieldValByName("delFlag", 0, metaObject);
    }
​
    /**
     * 自定义更新时填充规则
     */
    @Override
    public void updateFill(MetaObject metaObject) {
        String now = DateUtil.now();
        // 注意是类属性字段名称,不是表字段名称
        this.setFieldValByName("updateTime", new Date(), metaObject);
    }
​
}
​

 

id生成器代码:

package com.from.mybatis.config;
​
import java.util.Date;
import java.util.UUID;
​
/**
 * compressed id generator, result id not great than 53bits before 2318-06-04.
 */
public class IdGenerator {
​
    private static IdGenerator instance = new IdGenerator(0);
​
    public static IdGenerator initDefaultInstance(int machineId) {
        instance = new IdGenerator(machineId);
        return instance;
    }
​
    public static IdGenerator getInstance() {
        return instance;
    }
​
    public static long generateId() {
        return instance.nextId();
    }
​
    // total bits=53(max 2^53-1:9007199254740992-1)
// private final static long TIME_BIT = 40; // max: 2318-06-04
    private final static long MACHINE_BIT = 5; // max 31
    private final static long SEQUENCE_BIT = 8; // 256/10ms
/**
     * mask/max value
     */
    private final static long MAX_MACHINE_NUM = -1L ^ (-1L << MACHINE_BIT);
    private final static long MAX_SEQUENCE = -1L ^ (-1L << SEQUENCE_BIT);
​
    private final static long MACHINE_LEFT = SEQUENCE_BIT;
    private final static long TIMESTMP_LEFT = MACHINE_BIT + SEQUENCE_BIT;
​
    private long machineId;
    private long sequence = 0L;
    private long lastStmp = -1L;
​
    private IdGenerator(long machineId) {
        if (machineId > MAX_MACHINE_NUM || machineId < 0) {
            throw new IllegalArgumentException(
                    "machineId can't be greater than " + MAX_MACHINE_NUM + " or less than 0");
        }
        this.machineId = machineId;
    }
​
    /**
     * generate new ID
     *
     * @return
     */
    public synchronized long nextId() {
        long currStmp = getTimestamp();
        if (currStmp < lastStmp) {
            throw new RuntimeException("Clock moved backwards.  Refusing to generate id");
        }
​
        if (currStmp == lastStmp) {
            sequence = (sequence + 1) & MAX_SEQUENCE;
            if (sequence == 0L) {
                currStmp = getNextTimestamp();
            }
        } else {
            sequence = 0L;
        }
​
        lastStmp = currStmp;
​
        return currStmp << TIMESTMP_LEFT //
                | machineId << MACHINE_LEFT //
                | sequence;
    }
​
    private long getNextTimestamp() {
        long mill = getTimestamp();
        while (mill <= lastStmp) {
            mill = getTimestamp();
        }
        return mill;
    }
​
    private long getTimestamp() {
        // per 10ms
        return System.currentTimeMillis() / 10;// 10ms
    }
​
    public static Date parseIdTimestamp(long id) {
        return new Date((id >>> TIMESTMP_LEFT) * 10);
    }
​
    public static String uuid() {
        return UUID.randomUUID().toString().replaceAll("-", "");
    }
}
​

 

package com.from.mybatis.config;
​
​
import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator;
import org.springframework.stereotype.Component;
​
@Component
public class CustomerIdGenerator implements IdentifierGenerator {
    @Override
    public Long nextId(Object entity) {
        // 填充自己的Id生成器,
        return IdGenerator.generateId();
    }
}

 


具体代理配置:

package com.from.seata.config;
import com.alibaba.druid.pool.DruidDataSource;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.autoconfigure.MybatisPlusProperties;
import com.baomidou.mybatisplus.core.MybatisConfiguration;
import com.baomidou.mybatisplus.core.config.GlobalConfig;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import com.from.mybatis.config.CustomerIdGenerator;
import com.from.mybatis.handler.MyBatisMetaObjectHandler;
import io.seata.rm.datasource.DataSourceProxy;
import org.mybatis.spring.transaction.SpringManagedTransactionFactory;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import javax.sql.DataSource;
import java.io.IOException;
@Configuration
@EnableConfigurationProperties({MybatisPlusProperties.class})
public class DataSourcesProxyConfig {
    //自动填充注入
    @Bean
    public MyBatisMetaObjectHandler myBatisMetaObjectHandler() {
        return new MyBatisMetaObjectHandler();
    }
    //id生成器注入
    @Bean
    public CustomerIdGenerator customerIdGenerator() {
        return new CustomerIdGenerator();
    }
    //获取数据源
    @Bean
    @ConfigurationProperties(prefix = "spring.datasource")
    public DataSource druidDataSource() {
        return new DruidDataSource();
    }
​
    //配种数据源
    @Primary//@Primary标识必须配置在代码数据源上,否则本地事务失效
    @Bean
    public DataSourceProxy dataSourceProxy(DataSource druidDataSource) {
        return new DataSourceProxy(druidDataSource);
    }
​
    private MybatisPlusProperties properties;
​
    public DataSourcesProxyConfig(MybatisPlusProperties properties) {
        this.properties = properties;
    }
​
    //配置mybatisplus的数据源,所有插件会失效,所以注入进来,配置给代理数据源
    @Bean
    public MybatisSqlSessionFactoryBean sqlSessionFactory(DataSourceProxy dataSourceProxy) throws Exception {
        // 这里必须用 MybatisSqlSessionFactoryBean 代替了 SqlSessionFactoryBean,否则 MyBatisPlus 不会生效
        MybatisSqlSessionFactoryBean sqlBean = new MybatisSqlSessionFactoryBean();
        sqlBean.setDataSource(dataSourceProxy);
        sqlBean.setTransactionFactory(new SpringManagedTransactionFactory());
        try {
            //注意:!!!!这个如果写的有sql,须有该配置,try cach以下,打开不捕获异常的化,没sql会报错
            sqlBean.setMapperLocations(new PathMatchingResourcePatternResolver()
                    .getResources("classpath:/mapper/**/*.xml"));
        } catch (IOException ignored) {
        }
        MybatisConfiguration configuration = this.properties.getConfiguration();
        if (configuration == null) {
            configuration = new MybatisConfiguration();
        }
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        //向代理数据源添加分页拦截器
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        sqlBean.setPlugins(interceptor);
        //代理数据源添加id生成器,字段自动填充
        sqlBean.setGlobalConfig(new GlobalConfig()
                .setMetaObjectHandler(myBatisMetaObjectHandler())
                .setIdentifierGenerator(customerIdGenerator()));
        sqlBean.setConfiguration(configuration);
        return sqlBean;
    }
}

 

关于seata服务端和客户端集成配置,可以看另一篇文章!