淘先锋技术网

首页 1 2 3 4 5 6 7

第一步导入坐标

 <!--sharding+seata+mp整合开始 第一步-->
  <dependency>
            <groupId>org.postgresql</groupId>
            <artifactId>postgresql</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.apache.shardingsphere</groupId>
            <artifactId>sharding-jdbc-spring-boot-starter</artifactId>
            <version>4.0.0-RC2</version>
        </dependency>
        <!--seata与sharding整合包 -->
        <dependency>
            <groupId>org.apache.shardingsphere</groupId>
            <artifactId>sharding-transaction-base-seata-at</artifactId>
            <version>4.0.0-RC2</version>
        </dependency>
        <!-- mp 依赖 -->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.2.0</version>
        </dependency>

        <!--druid-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.10</version>
        </dependency>


        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-alibaba-seata</artifactId>
            <version>2.2.0.RELEASE</version>
            <exclusions>
                <exclusion>
                    <groupId>io.seata</groupId>
                    <artifactId>seata-spring-boot-starter</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>io.seata</groupId>
            <artifactId>seata-spring-boot-starter</artifactId>
            <version>1.3.0</version>
        </dependency>
        <!--sharding+seata整合结束-->

第二步增加配置类
1)MybatisPlusConfig类

import com.baomidou.mybatisplus.core.incrementer.IKeyGenerator;
import com.baomidou.mybatisplus.extension.incrementer.H2KeyGenerator;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;

/**
 * mybatis-plus配置
 * @author yyj
 */
@Configuration
public class MybatisPlusConfig {

    /**
     * 配置分页
     */
    @Bean
    @Order(0)
    public PaginationInterceptor paginationInterceptor() {
        return new PaginationInterceptor();
    }


    /**
     * 主键生成策略
     * @return
     */
    @Bean
    public IKeyGenerator keyGenerator(){
        return new H2KeyGenerator();
    }
}

2)MybatisPlusAutoConfig类

import com.baomidou.mybatisplus.autoconfigure.ConfigurationCustomizer;
import com.baomidou.mybatisplus.autoconfigure.MybatisPlusProperties;
import com.baomidou.mybatisplus.autoconfigure.SpringBootVFS;
import com.baomidou.mybatisplus.core.MybatisConfiguration;
import com.baomidou.mybatisplus.core.config.GlobalConfig;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import com.baomidou.mybatisplus.core.incrementer.IKeyGenerator;
import com.baomidou.mybatisplus.core.injector.ISqlInjector;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.mapping.DatabaseIdProvider;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.mapper.ClassPathMapperScanner;
import org.mybatis.spring.mapper.MapperFactoryBean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.boot.autoconfigure.AutoConfigurationPackages;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import javax.sql.DataSource;
import java.util.Iterator;
import java.util.List;

/**
 * sharding+seata+mp整合开始 第三步配置数据源
 * @author yyj
 * @date  2020年7月20日16:48:19
 */
@Configuration
@AutoConfigureAfter(MybatisPlusConfig.class)
@EnableConfigurationProperties({MybatisPlusProperties.class})
public class MybatisPlusAutoConfig {

  private static final Logger logger = LoggerFactory.getLogger(MybatisPlusAutoConfig.class);
  private final MybatisPlusProperties properties;
  private final Interceptor[] interceptors;
  private final ResourceLoader resourceLoader;
  private final DatabaseIdProvider databaseIdProvider;
  private final List<ConfigurationCustomizer> configurationCustomizers;
  private final ApplicationContext applicationContext;

  public MybatisPlusAutoConfig(MybatisPlusProperties properties,
                               ObjectProvider<Interceptor[]> interceptorsProvider, ResourceLoader resourceLoader,
                               ObjectProvider<DatabaseIdProvider> databaseIdProvider,
                               ObjectProvider<List<ConfigurationCustomizer>> configurationCustomizersProvider,
                               ApplicationContext applicationContext) {
    this.properties = properties;
    this.interceptors = (Interceptor[]) interceptorsProvider.getIfAvailable();
    this.resourceLoader = resourceLoader;
    this.databaseIdProvider = (DatabaseIdProvider) databaseIdProvider.getIfAvailable();
    this.configurationCustomizers = (List) configurationCustomizersProvider.getIfAvailable();
    this.applicationContext = applicationContext;
  }

  public void afterPropertiesSet() {
    this.checkConfigFileExists();
  }

  private void checkConfigFileExists() {
    if (this.properties.isCheckConfigLocation() && StringUtils
        .hasText(this.properties.getConfigLocation())) {
      Resource resource = this.resourceLoader.getResource(this.properties.getConfigLocation());
      Assert.state(resource.exists(), "Cannot find config location: " + resource
          + " (please add config file or check your Mybatis configuration)");
    }

  }

  @Bean
  @ConditionalOnMissingBean
  public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
    MybatisSqlSessionFactoryBean factory = new MybatisSqlSessionFactoryBean();
    factory.setDataSource(dataSource);
    factory.setVfs(SpringBootVFS.class);
    if (StringUtils.hasText(this.properties.getConfigLocation())) {
      factory
          .setConfigLocation(this.resourceLoader.getResource(this.properties.getConfigLocation()));
    }

    this.applyConfiguration(factory);
    if (this.properties.getConfigurationProperties() != null) {
      factory.setConfigurationProperties(this.properties.getConfigurationProperties());
    }

    if (!ObjectUtils.isEmpty(this.interceptors)) {
      factory.setPlugins(this.interceptors);
    }

    if (this.databaseIdProvider != null) {
      factory.setDatabaseIdProvider(this.databaseIdProvider);
    }

    if (StringUtils.hasLength(this.properties.getTypeAliasesPackage())) {
      factory.setTypeAliasesPackage(this.properties.getTypeAliasesPackage());
    }

    if (StringUtils.hasLength(this.properties.getTypeEnumsPackage())) {
      factory.setTypeEnumsPackage(this.properties.getTypeEnumsPackage());
    }

    if (this.properties.getTypeAliasesSuperType() != null) {
      factory.setTypeAliasesSuperType(this.properties.getTypeAliasesSuperType());
    }

    if (StringUtils.hasLength(this.properties.getTypeHandlersPackage())) {
      factory.setTypeHandlersPackage(this.properties.getTypeHandlersPackage());
    }

    if (!ObjectUtils.isEmpty(this.properties.resolveMapperLocations())) {
      factory.setMapperLocations(this.properties.resolveMapperLocations());
    }

    GlobalConfig globalConfig = this.properties.getGlobalConfig();
    if (this.applicationContext.getBeanNamesForType(MetaObjectHandler.class, false, false).length
        > 0) {
      MetaObjectHandler metaObjectHandler = (MetaObjectHandler) this.applicationContext
          .getBean(MetaObjectHandler.class);
      globalConfig.setMetaObjectHandler(metaObjectHandler);
    }

    if (this.applicationContext.getBeanNamesForType(IKeyGenerator.class, false, false).length > 0) {
      IKeyGenerator keyGenerator = (IKeyGenerator) this.applicationContext
          .getBean(IKeyGenerator.class);
      globalConfig.getDbConfig().setKeyGenerator(keyGenerator);
    }

    if (this.applicationContext.getBeanNamesForType(ISqlInjector.class, false, false).length > 0) {
      ISqlInjector iSqlInjector = (ISqlInjector) this.applicationContext
          .getBean(ISqlInjector.class);
      globalConfig.setSqlInjector(iSqlInjector);
    }

    factory.setGlobalConfig(globalConfig);
    return factory.getObject();
  }

  private void applyConfiguration(MybatisSqlSessionFactoryBean factory) {
    MybatisConfiguration configuration = this.properties.getConfiguration();
    if (configuration == null && !StringUtils.hasText(this.properties.getConfigLocation())) {
      configuration = new MybatisConfiguration();
    }

    if (configuration != null && !CollectionUtils.isEmpty(this.configurationCustomizers)) {
      Iterator var3 = this.configurationCustomizers.iterator();

      while (var3.hasNext()) {
        ConfigurationCustomizer customizer = (ConfigurationCustomizer) var3.next();
        customizer.customize(configuration);
      }
    }

    factory.setConfiguration(configuration);
  }

  @Bean
  @ConditionalOnMissingBean
  public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
    ExecutorType executorType = this.properties.getExecutorType();
    return executorType != null ? new SqlSessionTemplate(sqlSessionFactory, executorType)
        : new SqlSessionTemplate(sqlSessionFactory);
  }

  @Configuration
  @Import({AutoConfiguredMapperScannerRegistrar.class})
  @ConditionalOnMissingBean({MapperFactoryBean.class})
  public static class MapperScannerRegistrarNotFoundConfiguration implements InitializingBean {

    public MapperScannerRegistrarNotFoundConfiguration() {
    }

    @Override
    public void afterPropertiesSet() {
      MybatisPlusAutoConfig.logger.debug("No {} found.", MapperFactoryBean.class.getName());
    }
  }

  public static class AutoConfiguredMapperScannerRegistrar implements BeanFactoryAware,
          ImportBeanDefinitionRegistrar, ResourceLoaderAware {

    private BeanFactory beanFactory;
    private ResourceLoader resourceLoader;

    public AutoConfiguredMapperScannerRegistrar() {
    }

    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
                                        BeanDefinitionRegistry registry) {
      if (!AutoConfigurationPackages.has(this.beanFactory)) {
        MybatisPlusAutoConfig.logger.debug(
            "Could not determine auto-configuration package, automatic mapper scanning disabled.");
      } else {
        MybatisPlusAutoConfig.logger.debug("Searching for mappers annotated with @Mapper");
        List<String> packages = AutoConfigurationPackages.get(this.beanFactory);
        if (MybatisPlusAutoConfig.logger.isDebugEnabled()) {
          packages.forEach((pkg) -> {
            MybatisPlusAutoConfig.logger.debug("Using auto-configuration base package '{}'", pkg);
          });
        }

        ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
        if (this.resourceLoader != null) {
          scanner.setResourceLoader(this.resourceLoader);
        }

        scanner.setAnnotationClass(Mapper.class);
        scanner.registerFilters();
        scanner.doScan(StringUtils.toStringArray(packages));
      }
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
      this.beanFactory = beanFactory;
    }

    @Override
    public void setResourceLoader(ResourceLoader resourceLoader) {
      this.resourceLoader = resourceLoader;
    }
  }

}

第三步排除数据源

@SpringBootApplication(exclude = {
        DruidDataSourceAutoConfigure.class,
        DataSourceAutoConfiguration.class,
        MybatisPlusAutoConfiguration.class
})

第四步seata配置

### 这里很重要
#    异常:Could not register branch into global session xid = status = Rollbacked(还有Rollbacking、AsyncCommitting等等二阶段状态) while expecting Begin
#    描述:分支事务注册时,全局事务状态需是一阶段状态begin,非begin不允许注册。属于seata框架层面正常的处理,用户可以从自身业务层面解决。
#    出现场景(可继续补充)
#
#    1. 分支事务是异步,全局事务无法感知它的执行进度,全局事务已进入二阶段,该异步分支才来注册
#    2. 服务a rpc 服务b超时(dubbo、feign等默认1秒超时),a上抛异常给tm,tm通知tc回滚,但是b还是收到了请求(网络延迟或rpc框架重试),然后去tc注册时发现全局事务已在回滚
#    3. tc感知全局事务超时(@GlobalTransactional(timeoutMills = 默认60秒)),主动变更状态并通知各分支事务回滚,此时有新的分支事务来注册
ribbon:
  # 连接超时
  ConnectTimeout: 5000
  # 响应超时  设置超时时间设置长一点。应为回滚需要时间
  ReadTimeout: 10000

seata:
  enabled: true
  application-id: data-api
  tx-service-group: my_test_tx_group
  enable-auto-data-source-proxy: true
  config:
    type: nacos
    nacos:
      namespace:
      server-addr: 192.168.101.50:8848
      group: SEATA_GROUP
      username: nacos
      password: nacos
  registry:
    type: nacos
    nacos:
      application: seata-server
      server-addr: 192.168.101.50:8848
      namespace:
      username: nacos
      password: nacos

第五步resources增加seata.conf文件

## ---------------------------------------------------------------------------
## Licensed to the Apache Software Foundation (ASF) under one or more
## contributor license agreements.  See the NOTICE file distributed with
## this work for additional information regarding copyright ownership.
## The ASF licenses this file to You under the Apache License, Version 2.0
## (the "License"); you may not use this file except in compliance with
## the License.  You may obtain a copy of the License at
##
##      http://www.apache.org/licenses/LICENSE-2.0
##
## Unless required by applicable law or agreed to in writing, software
## distributed under the License is distributed on an "AS IS" BASIS,
## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
## See the License for the specific language governing permissions and
## limitations under the License.
## ---------------------------------------------------------------------------

client {
    ##这个是唯一的和项目名称一致
    application.id = data-api
    transaction.service.group = my_test_tx_group
}

注意
seata1.3.0和sharding整合会报一个错误 Can not find columnLabel INDEX_NAME
这个问题我已经给官方修复了。只需要把ResultSet列名改为小写就可以了。
等官方发新版本就可以了。 或者自己改下源码 重新打包。