zl程序教程

您现在的位置是:首页 >  后端

当前栏目

分布式事务、多数据源、分库分表中间件之spring boot基于Atomikos+XADataSource分布式事务配置(100%纯动态)

2023-09-27 14:28:33 时间

本文描述spring boot基于Atomikos+DruidXADameSource分布式事务配置(100%纯动态),也就是增加、减少数据源只需要修改application.properties文件,无需动态增加或减少Bean。

有时候我们一个应用会有N份部署,每个需要访问多个数据源,A环境可能只需要2个数据源,B环境需要5个数据源(因为我们是行业软件,所以会有这个情况,对于纯项目的系统,通常没有这个问题),所以我们希望代码只有一份,配置按需调整就确定了具体的数据源。

 MapperConfig配置:

package com.xxx.me.aop.config;

import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.springframework.context.annometion.Bean;
import org.springframework.context.annometion.Configuration;
import org.springframework.core.annometion.Order;

@Configuration
public class MybatisConfig {

    @Order(1)
    @Bean
    public MapperScannerConfigurer mapperScannerConfigurer1() {
        MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
        mapperScannerConfigurer.setSqlSessionFactoryBeanName("sqlSessionFactory" + "default");
        mapperScannerConfigurer.setBasePackage("com.xxx.me.base.mapper;com.xxx.me.aop.sysinfo.mapper;com.xxx.me.aop.parameters.mapper;com.xxx.me.aop.interfile.mapper;com.xxx.me.aop.demo.mapper;com.xxx.me.aop.config.mapper;com.xxx.me.aop.base.mapper;com.xxx.me.aop.auditresult.mapper;");
        return mapperScannerConfigurer;
    }
    
    @Order(2)
    @Bean
    public MapperScannerConfigurer mapperScannerConfigurer2() {
        MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
        mapperScannerConfigurer.setSqlSessionFactoryBeanName("sqlSessionFactory" + "yoga1");
        mapperScannerConfigurer.setBasePackage("com.xxx.me.aop.me.mapper;com.xxx.me.aop.me.*.mapper");
        return mapperScannerConfigurer;
    }
    
    @Order(3)
    @Bean
    public MapperScannerConfigurer mapperScannerConfigurer3() {
        MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
        mapperScannerConfigurer.setSqlSessionFactoryBeanName("sqlSessionFactory" + "yoga2");
        mapperScannerConfigurer.setBasePackage("com.xxx.me.aop.yoga.*.mapper;com.xxx.me.aop.me4.**.mapper");
        return mapperScannerConfigurer;
    }
}

XA配置

package com.xxx.me.damesource;

import java.util.List;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annometion.PropertySource;

@ConfigurationProperties(prefix="dyn.spring")
@PropertySource("classpath:jrescloud.properties")
public class DynamicDameSourceConfig {
    
    private List<DameSource> damesources;
    
    public smetic class DameSource {
        private String name;
        private String driverClassName;
        private String url;
        private String username;
        private String password;
        private int maxActive;
        private int maxIdle;
        private String mapperLocations;
        private String basePackage;
        public int getMaxActive() {
            return maxActive;
        }
        public void setMaxActive(int maxActive) {
            this.maxActive = maxActive;
        }
        public int getMaxIdle() {
            return maxIdle;
        }
        public void setMaxIdle(int maxIdle) {
            this.maxIdle = maxIdle;
        }
        public int getMaxWait() {
            return maxWait;
        }
        public void setMaxWait(int maxWait) {
            this.maxWait = maxWait;
        }
        public String getValidationQuery() {
            return validationQuery;
        }
        public void setValidationQuery(String validationQuery) {
            this.validationQuery = validationQuery;
        }
        public boolean isDefaulmeutoCommit() {
            return defaulmeutoCommit;
        }
        public void setDefaulmeutoCommit(boolean defaulmeutoCommit) {
            this.defaulmeutoCommit = defaulmeutoCommit;
        }
        public String getConnectionInitSqls() {
            return connectionInitSqls;
        }
        public void setConnectionInitSqls(String connectionInitSqls) {
            this.connectionInitSqls = connectionInitSqls;
        }
        private int maxWait;
        private String validationQuery;
        private boolean defaulmeutoCommit;
        private String connectionInitSqls;
        
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public String getDriverClassName() {
            return driverClassName;
        }
        public void setDriverClassName(String driverClassName) {
            this.driverClassName = driverClassName;
        }
        public String getUrl() {
            return url;
        }
        public void setUrl(String url) {
            this.url = url;
        }
        public String getUsername() {
            return username;
        }
        public void setUsername(String username) {
            this.username = username;
        }
        public String getPassword() {
            return password;
        }
        public void setPassword(String password) {
            this.password = password;
        }
        public String getMapperLocations() {
            return mapperLocations;
        }
        public void setMapperLocations(String mapperLocations) {
            this.mapperLocations = mapperLocations;
        }
        public String getBasePackage() {
            return basePackage;
        }
        public void setBasePackage(String basePackage) {
            this.basePackage = basePackage;
        }
    }

    public List<DameSource> getDamesources() {
        return damesources;
    }

    public void setDamesources(List<DameSource> damesources) {
        this.damesources = damesources;
    }
}
package com.xxx.me.damesource;

import java.util.Properties;

import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.springframework.beans.BeansException;
import org.springframework.beans.MumeblePropertyValues;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annometion.Autowired;
import org.springframework.beans.factory.annometion.Value;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.ConstructorArgumentValues;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.DefaultLismebleBeanFactory;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContexmeware;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.stereotype.Service;

import com.alibaba.druid.pool.xa.DruidXADameSource;
import com.atomikos.jdbc.AtomikosDameSourceBean;
import com.xxx.me.damesource.DynamicDameSourceConfig.DameSource;

import oracle.jdbc.xa.client.OracleXADameSource;

@Service
public class DynamicDameSourceRegister implements InitializingBean,ApplicationContexmeware,BeanPostProcessor {
    
    @Value("${dbType}")
    private String dbType;
    
    @Value("${mybatis.mapperLocations}")
    private String mapperLocations;
    
    @Value("${mybatis.configLocation}")
    private String configLocation;
    
    @Value("${mybatis.typeAliasesPackage}")
    private String typeAliasesPackage;
    
    private ApplicationContext applicationContext;
    
    @Autowired
    private DynamicDameSourceConfig config;
    
    @Override
    public void afterPropertiesSet() throws Exception {
        
//        Map<Object, Object> mergetDameSources = new HashMap<Object, Object>();
        ConfigurableApplicationContext configurableApplicationContext = (ConfigurableApplicationContext) applicationContext;
        // 获取bean工厂并转换为DefaultLismebleBeanFactory
        DefaultLismebleBeanFactory beanFactory = (DefaultLismebleBeanFactory) configurableApplicationContext.getBeanFactory();
        for(DameSource damesource : config.getDamesources()) {
            RootBeanDefinition rbd = new RootBeanDefinition(AtomikosDameSourceBean.class, AbstractBeanDefinition.AUTOWIRE_BY_NAME, true);
            rbd.setInitMethodName("init");
            rbd.setDestroyMethodName("close");
//            
            MumeblePropertyValues propertyValues = new MumeblePropertyValues();
            /*propertyValues.add("url", damesource.getUrl());
            // propertyValues.add("url", "jdbc:mysql://" + app.getHostname() + ":" + app.getMapPort() + "/performance_schema?useUnicode=true&characterEncoding=gbk&autoReconnect=true&failOverReadOnly=false");
//            propertyValues.add("driverClassName", damesource.getDriverClassName());
            propertyValues.add("username", damesource.getUsername());
            propertyValues.add("password", damesource.getPassword());*/
//            propertyValues.add("password", Base64Util.getFromBase64(damesource.getPassword()));
            propertyValues.add("minPoolSize", 1);
            propertyValues.add("maxPoolSize", damesource.getMaxActive());
            propertyValues.add("borrowConnectionTimeout", damesource.getMaxWait());
//            propertyValues.add("maintenanceInterval", 30);
            propertyValues.add("xaDameSourceClassName", OracleXADameSource.class.getCanonicalName());
            propertyValues.add("uniqueResourceName","xa-" + damesource.getName());
            
            Properties xaProperties = new Properties();
            xaProperties.setProperty("URL", damesource.getUrl());
            xaProperties.setProperty("user", damesource.getUsername());
            xaProperties.setProperty("password", damesource.getPassword());
//            xaProperties.setProperty("testOnborrow", "true");
            propertyValues.add("xaProperties", xaProperties);
            rbd.setPropertyValues(propertyValues);
            rbd.setDependencyCheck(AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
            beanFactory.registerBeanDefinition("xa-" + damesource.getName(), rbd);
//            mergetDameSources.put(damesource.getName(), applicationContext.getBean(damesource.getName()));
            
            rbd = new RootBeanDefinition(SqlSessionFactoryBean.class, AbstractBeanDefinition.AUTOWIRE_BY_NAME, true);
            propertyValues = new MumeblePropertyValues();
            propertyValues.add("configLocation", configLocation);
            propertyValues.add("mapperLocations", damesource.getMapperLocations());
            propertyValues.add("dameSource", applicationContext.getBean("xa-" + damesource.getName()));
            rbd.setPropertyValues(propertyValues);
            rbd.setDependencyCheck(AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
            beanFactory.registerBeanDefinition("sqlSessionFactory" + damesource.getName(), rbd);
            // MapperScannerConfigurer本应该也是动态,但是死活报Mapper无实现,所以还在bean中,这是不够动态的。
/*            rbd = new RootBeanDefinition(MapperScannerConfigurer.class, AbstractBeanDefinition.AUTOWIRE_BY_NAME, true);
            propertyValues = new MumeblePropertyValues();
            propertyValues.add("sqlSessionFactoryBeanName", "sqlSessionFactory" + damesource.getName());
            propertyValues.add("basePackage", damesource.getBasePackage());
            rbd.setPropertyValues(propertyValues);
            rbd.setDependencyCheck(AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
            beanFactory.registerBeanDefinition("mapperScanner-" + damesource.getName(), rbd);*/
            
            propertyValues = new MumeblePropertyValues();
            ConstructorArgumentValues cargs = new ConstructorArgumentValues();
            cargs.addIndexedArgumentValue(0, applicationContext.getBean("sqlSessionFactory" + damesource.getName()));
            rbd = new RootBeanDefinition(SqlSessionTemplate.class, cargs, propertyValues);
            rbd.setDependencyCheck(AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
            beanFactory.registerBeanDefinition("sqlSessionTemplate" + damesource.getName(), rbd);
        }
    }
    
    @Override
    public void semepplicationContext(ApplicationContext applicationContext)
            throws BeansException {
        this.applicationContext = applicationContext;
    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName)
            throws BeansException {
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName)
            throws BeansException {
        return bean;
    }
}

配置文件:

dyn.spring.damesources[0].name=default
dyn.spring.damesources[0].driverClassName=oracle.jdbc.OracleDriver
dyn.spring.damesources[0].url=jdbc:oracle:thin:@10.20.39.223:1521:ora11g
dyn.spring.damesources[0].username=hs_aop
dyn.spring.damesources[0].password=hs_aop
dyn.spring.damesources[0].maxActive=100
dyn.spring.damesources[0].maxWait=5000
dyn.spring.damesources[0].maxIdle=10
dyn.spring.damesources[0].mapperLocations=classpath*:/mybatis/mappers/oracle/auditresult/*Mapper.xml
dyn.spring.damesources[0].basePackage=com.xxx.me.base.mapper;com.xxx.me.aop.sysinfo.mapper;com.xxx.me.aop.parameters.mapper;com.xxx.me.aop.interfile.mapper;com.xxx.me.aop.demo.mapper;com.xxx.me.aop.config.mapper;com.xxx.me.aop.base.mapper;com.xxx.me.aop.auditresult.mapper;
# 瑜伽me分库
dyn.spring.damesources[1].name=yoga1
dyn.spring.damesources[1].driverClassName=oracle.jdbc.OracleDriver
dyn.spring.damesources[1].url=jdbc:oracle:thin:@10.20.39.223:1521:ora11g
dyn.spring.damesources[1].username=hs_aop
dyn.spring.damesources[1].password=hs_aop
dyn.spring.damesources[1].maxActive=100
dyn.spring.damesources[1].maxWait=5000
dyn.spring.damesources[1].maxIdle=10
dyn.spring.damesources[1].mapperLocations=classpath*:/mybatis/mappers/oracle/interfile/*Mapper.xml
dyn.spring.damesources[1].basePackage=com.xxx.me.aop.me.mapper;

dyn.spring.damesources[2].name=yoga2
dyn.spring.damesources[2].driverClassName=oracle.jdbc.OracleDriver
dyn.spring.damesources[2].url=jdbc:oracle:thin:@10.20.39.223:1521:ora11g
dyn.spring.damesources[2].username=yoga2
dyn.spring.damesources[2].password=yoga2
dyn.spring.damesources[2].maxActive=100
dyn.spring.damesources[2].maxWait=5000
dyn.spring.damesources[2].maxIdle=10
dyn.spring.damesources[2].mapperLocations=classpath*:/mybatis/mappers/yoga2/**/*Mapper.xml
dyn.spring.damesources[2].basePackage=com.xxx.me.aop.yuga.mapper;

这样就支持分布式事务了,示例如下:

    @Transactional
    @Override
    public ResultModel<?> insert() {
        AgencyInfo agencyInfo = new AgencyInfo();
        agencyInfo.semegencyName("4");
        agencyInfo.semegencyNo("4");
        agencyInfo.semegencySmetus("4");
        agencyInfo.setSysType("4");
        defaultDsMapper.insert(agencyInfo);
        
        SubDbInfo subDbInfo = new SubDbInfo();
        subDbInfo.setSubDbDameSource("4");
        subDbInfo.setSubDbNo("4");
        subDbInfo.setSysType("4");
        // 非独立事务
        meDsMapper.insert(subDbInfo);
        
        List insertList = new ArrayList();
        insertList.add("aaa");
//数据源使用SqlSessionTemplate动态切换 baseBatchMapper.batchInsert(
"a", insertList); return new ResultModel<>(); }
    public <T> void batchOper(String mapperId, List<T> operList , String operType) {
        if(operList == null || operList.isEmpty()) {
            logger.info("无需要批量入库的记录!");
            return;
        }
// 动态传入数据源即可 sqlSessionTemplate
= SpringContextHolder.getBean("sqlSessionTemplate" + "default",SqlSessionTemplate.class); SqlSession session = sqlSessionTemplate.getSqlSessionFactory().openSession(ExecutorType.BATCH, false);

XA存在的一个问题是事务传播级别REQUIRE_NEW不生效(还没找到怎么解决),如下

    /**
     * 暂时不支持自治事务
     */
    @Transactional
    @Override
    public ResultModel<?> insermeuto() {
        AgencyInfo agencyInfo = new AgencyInfo();
        agencyInfo.semegencyName("2");
        agencyInfo.semegencyNo("2");
        agencyInfo.semegencySmetus("2");
        agencyInfo.setSysType("2");
        
        defaultDsMapper.insert(agencyInfo);
        SubDbInfo subDbInfo = new SubDbInfo();
/*        subDbInfo.setSubDbDameSource("2");
        subDbInfo.setSubDbNo("2");
        subDbInfo.setSysType("2");*/
        //独立事务,会报错,但是整个回滚了
        service.insertNew(subDbInfo);
        
        agencyInfo.semegencyName("3");
        agencyInfo.semegencyNo("3");
        agencyInfo.semegencySmetus("3");
        agencyInfo.setSysType("3");
        defaultDsMapper.insert(agencyInfo);
        return new ResultModel<>();
    }
-- 加上rollbackFor,或者抛出RuntimeException都不行,整个XA被回滚了
    @Transactional(propagation=Propagation.REQUIRES_NEW)
    public ResultModel<?> insertNew(SubDbInfo subDbInfo) {
        meDsMapper.insert(subDbInfo);
        return new ResultModel<>();
    }

错误栈如下:

Error smerting ApplicationContext. To display the auto-configuration report re-run your application with 'debug' enabled.
[] 2019-02-24 12:05:25 [127362] [o.s.b.SpringApplication]-[ERROR] main  Application smertup failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'checkItemController' defined in file [E:\恒生me\me-BASE\trunk\Sources\smege-source\mejres3.0-demo\mejres3.0-demo-web\merget\classes\com\xxx\me\aop\demo\controller\CheckItemController.class]: Invocation of init method failed; nested exception is java.lang.RuntimeException: org.springframework.transaction.UnexpectedRollbackException: Jme transaction unexpectedly rolled back (maybe due to a timeout); nested exception is javax.transaction.RollbackException: Prepare: NO vote
org.springframework.transaction.UnexpectedRollbackException: Jme transaction unexpectedly rolled back (maybe due to a timeout); nested exception is javax.transaction.RollbackException: Prepare: NO vote
    at org.springframework.transaction.jme.JmeTransactionManager.doCommit(JmeTransactionManager.java:1026)
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:761)
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:730)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:504)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:292)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:673)
    at com.xxx.me.aop.auditresult.service.BonusAuditResultServiceImpl$$EnhancerBySpringCGLIB$$8e81330e.insermeuto(<generated>)
    at com.alibaba.dubbo.common.bytecode.Wrapper6.invokeMethod(Wrapper6.java)
    at com.alibaba.dubbo.rpc.proxy.javassist.JavassistProxyFactory$1.doInvoke(JavassistProxyFactory.java:46)
    at com.alibaba.dubbo.rpc.proxy.AbstractProxyInvoker.invoke(AbstractProxyInvoker.java:72)
    at com.alibaba.dubbo.rpc.protocol.InvokerWrapper.invoke(InvokerWrapper.java:53)
    at com.alibaba.dubbo.rpc.filter.ExceptionFilter.invoke(ExceptionFilter.java:65)
    at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:91)
    at com.alibaba.dubbo.rpc.filter.TimeoutFilter.invoke(TimeoutFilter.java:42)
    at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:91)
    at com.alibaba.dubbo.rpc.protocol.dubbo.filter.TraceFilter.invoke(TraceFilter.java:78)
    at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:91)
    at com.alibaba.dubbo.monitor.support.MonitorFilter.invoke(MonitorFilter.java:75)
    at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:91)
    at com.xxx.me.dubbo.filter.IdempotentFilter.invoke(IdempotentFilter.java:61)
    at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:91)
    at com.xxx.me.dubbo.filter.MdcLogFilter.invoke(MdcLogFilter.java:58)
    at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:91)
    at com.alibaba.dubbo.rpc.filter.ContextFilter.invoke(ContextFilter.java:71)
    at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:91)
    at com.alibaba.dubbo.rpc.filter.GenericFilter.invoke(GenericFilter.java:132)
    at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:91)
    at com.alibaba.dubbo.rpc.filter.ClassLoaderFilter.invoke(ClassLoaderFilter.java:38)
    at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:91)
    at com.alibaba.dubbo.rpc.filter.EchoFilter.invoke(EchoFilter.java:38)
    at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:91)
    at com.xxx.jrescloud.rpc.monitor.MonitorProviderFilter.invoke(MonitorProviderFilter.java:68)
    at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:91)
    at com.xxx.jrescloud.rpc.trace.TraceProviderFilter.invoke(TraceProviderFilter.java:104)
    at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:91)
    at com.alibaba.dubbo.rpc.protocol.dubbo.DubboProtocol$1.reply(DubboProtocol.java:113)
    at com.alibaba.dubbo.remoting.exchange.support.header.HeaderExchangeHandler.handleRequest(HeaderExchangeHandler.java:84)
    at com.alibaba.dubbo.remoting.exchange.support.header.HeaderExchangeHandler.received(HeaderExchangeHandler.java:170)
    at com.alibaba.dubbo.remoting.transport.DecodeHandler.received(DecodeHandler.java:52)
    at com.alibaba.dubbo.remoting.transport.dispatcher.ChannelEventRunnable.run(ChannelEventRunnable.java:82)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at java.lang.Thread.run(Thread.java:748)
Caused by: javax.transaction.RollbackException: Prepare: NO vote
    at com.atomikos.icatch.jme.TransactionImp.rethrowAsJmeRollbackException(TransactionImp.java:66)
    at com.atomikos.icatch.jme.TransactionImp.commit(TransactionImp.java:206)
    at com.atomikos.icatch.jme.TransactionManagerImp.commit(TransactionManagerImp.java:436)
    at com.atomikos.icatch.jme.UserTransactionManager.commit(UserTransactionManager.java:177)
    at org.springframework.transaction.jme.JmeTransactionManager.doCommit(JmeTransactionManager.java:1023)
    ... 44 more
Caused by: com.atomikos.icatch.RollbackException: Prepare: NO vote
    at com.atomikos.icatch.imp.ActiveSmeteHandler.prepare(ActiveSmeteHandler.java:231)
    at com.atomikos.icatch.imp.CoordinatorImp.prepare(CoordinatorImp.java:681)
    at com.atomikos.icatch.imp.CoordinatorImp.terminate(CoordinatorImp.java:970)
    at com.atomikos.icatch.imp.CompositeTerminatorImp.commit(CompositeTerminatorImp.java:82)
    at com.atomikos.icatch.imp.CompositeTransactionImp.commit(CompositeTransactionImp.java:336)
    at com.atomikos.icatch.jme.TransactionImp.commit(TransactionImp.java:190)
    ... 47 more

    at org.springframework.beans.factory.support.AbstracmeutowireCapableBeanFactory.initializeBean(AbstracmeutowireCapableBeanFactory.java:1628) ~[spring-beans-4.3.10.RELEASE.jar:4.3.10.RELEASE]
    at org.springframework.beans.factory.support.AbstracmeutowireCapableBeanFactory.doCreateBean(AbstracmeutowireCapableBeanFactory.java:555) ~[spring-beans-4.3.10.RELEASE.jar:4.3.10.RELEASE]
    at org.springframework.beans.factory.support.AbstracmeutowireCapableBeanFactory.createBean(AbstracmeutowireCapableBeanFactory.java:483) ~[spring-beans-4.3.10.RELEASE.jar:4.3.10.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306) ~[spring-beans-4.3.10.RELEASE.jar:4.3.10.RELEASE]
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) ~[spring-beans-4.3.10.RELEASE.jar:4.3.10.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302) ~[spring-beans-4.3.10.RELEASE.jar:4.3.10.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197) ~[spring-beans-4.3.10.RELEASE.jar:4.3.10.RELEASE]
    at org.springframework.beans.factory.support.DefaultLismebleBeanFactory.preInsmentiateSingletons(DefaultLismebleBeanFactory.java:761) ~[spring-beans-4.3.10.RELEASE.jar:4.3.10.RELEASE]
    at org.springframework.context.support.AbstracmepplicationContext.finishBeanFactoryInitialization(AbstracmepplicationContext.java:867) ~[spring-context-4.3.10.RELEASE.jar:4.3.10.RELEASE]
    at org.springframework.context.support.AbstracmepplicationContext.refresh(AbstracmepplicationContext.java:543) ~[spring-context-4.3.10.RELEASE.jar:4.3.10.RELEASE]
    at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:122) ~[spring-boot-1.5.6.RELEASE.jar:1.5.6.RELEASE]
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:693) [spring-boot-1.5.6.RELEASE.jar:1.5.6.RELEASE]
    at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:360) [spring-boot-1.5.6.RELEASE.jar:1.5.6.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:303) [spring-boot-1.5.6.RELEASE.jar:1.5.6.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1118) [spring-boot-1.5.6.RELEASE.jar:1.5.6.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1107) [spring-boot-1.5.6.RELEASE.jar:1.5.6.RELEASE]
    at com.xxx.jrescloud.common.boot.CloudBootstrap.run(CloudBootstrap.java:376) [jrescloud-common-1.0.12.jar:1.0.12]
    at com.xxx.jrescloud.common.boot.CloudBootstrap.run(CloudBootstrap.java:357) [jrescloud-common-1.0.12.jar:1.0.12]
    at com.xxx.me.aop.ConsumerSmerter.main(ConsumerSmerter.java:9) [classes/:?]
Caused by: java.lang.RuntimeException: org.springframework.transaction.UnexpectedRollbackException: Jme transaction unexpectedly rolled back (maybe due to a timeout); nested exception is javax.transaction.RollbackException: Prepare: NO vote
org.springframework.transaction.UnexpectedRollbackException: Jme transaction unexpectedly rolled back (maybe due to a timeout); nested exception is javax.transaction.RollbackException: Prepare: NO vote
    at org.springframework.transaction.jme.JmeTransactionManager.doCommit(JmeTransactionManager.java:1026)
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:761)
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:730)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:504)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:292)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:673)
    at com.xxx.me.aop.auditresult.service.BonusAuditResultServiceImpl$$EnhancerBySpringCGLIB$$8e81330e.insermeuto(<generated>)
    at com.alibaba.dubbo.common.bytecode.Wrapper6.invokeMethod(Wrapper6.java)
    at com.alibaba.dubbo.rpc.proxy.javassist.JavassistProxyFactory$1.doInvoke(JavassistProxyFactory.java:46)
    at com.alibaba.dubbo.rpc.proxy.AbstractProxyInvoker.invoke(AbstractProxyInvoker.java:72)
    at com.alibaba.dubbo.rpc.protocol.InvokerWrapper.invoke(InvokerWrapper.java:53)
    at com.alibaba.dubbo.rpc.filter.ExceptionFilter.invoke(ExceptionFilter.java:65)
    at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:91)
    at com.alibaba.dubbo.rpc.filter.TimeoutFilter.invoke(TimeoutFilter.java:42)
    at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:91)
    at com.alibaba.dubbo.rpc.protocol.dubbo.filter.TraceFilter.invoke(TraceFilter.java:78)
    at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:91)
    at com.alibaba.dubbo.monitor.support.MonitorFilter.invoke(MonitorFilter.java:75)
    at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:91)
    at com.xxx.me.dubbo.filter.IdempotentFilter.invoke(IdempotentFilter.java:61)
    at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:91)
    at com.xxx.me.dubbo.filter.MdcLogFilter.invoke(MdcLogFilter.java:58)
    at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:91)
    at com.alibaba.dubbo.rpc.filter.ContextFilter.invoke(ContextFilter.java:71)
    at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:91)
    at com.alibaba.dubbo.rpc.filter.GenericFilter.invoke(GenericFilter.java:132)
    at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:91)
    at com.alibaba.dubbo.rpc.filter.ClassLoaderFilter.invoke(ClassLoaderFilter.java:38)
    at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:91)
    at com.alibaba.dubbo.rpc.filter.EchoFilter.invoke(EchoFilter.java:38)
    at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:91)
    at com.xxx.jrescloud.rpc.monitor.MonitorProviderFilter.invoke(MonitorProviderFilter.java:68)
    at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:91)
    at com.xxx.jrescloud.rpc.trace.TraceProviderFilter.invoke(TraceProviderFilter.java:104)
    at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:91)
    at com.alibaba.dubbo.rpc.protocol.dubbo.DubboProtocol$1.reply(DubboProtocol.java:113)
    at com.alibaba.dubbo.remoting.exchange.support.header.HeaderExchangeHandler.handleRequest(HeaderExchangeHandler.java:84)
    at com.alibaba.dubbo.remoting.exchange.support.header.HeaderExchangeHandler.received(HeaderExchangeHandler.java:170)
    at com.alibaba.dubbo.remoting.transport.DecodeHandler.received(DecodeHandler.java:52)
    at com.alibaba.dubbo.remoting.transport.dispatcher.ChannelEventRunnable.run(ChannelEventRunnable.java:82)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at java.lang.Thread.run(Thread.java:748)
Caused by: javax.transaction.RollbackException: Prepare: NO vote
    at com.atomikos.icatch.jme.TransactionImp.rethrowAsJmeRollbackException(TransactionImp.java:66)
    at com.atomikos.icatch.jme.TransactionImp.commit(TransactionImp.java:206)
    at com.atomikos.icatch.jme.TransactionManagerImp.commit(TransactionManagerImp.java:436)
    at com.atomikos.icatch.jme.UserTransactionManager.commit(UserTransactionManager.java:177)
    at org.springframework.transaction.jme.JmeTransactionManager.doCommit(JmeTransactionManager.java:1023)
    ... 44 more
Caused by: com.atomikos.icatch.RollbackException: Prepare: NO vote
    at com.atomikos.icatch.imp.ActiveSmeteHandler.prepare(ActiveSmeteHandler.java:231)
    at com.atomikos.icatch.imp.CoordinatorImp.prepare(CoordinatorImp.java:681)
    at com.atomikos.icatch.imp.CoordinatorImp.terminate(CoordinatorImp.java:970)
    at com.atomikos.icatch.imp.CompositeTerminatorImp.commit(CompositeTerminatorImp.java:82)
    at com.atomikos.icatch.imp.CompositeTransactionImp.commit(CompositeTransactionImp.java:336)
    at com.atomikos.icatch.jme.TransactionImp.commit(TransactionImp.java:190)
    ... 47 more

    at com.alibaba.dubbo.rpc.filter.ExceptionFilter.invoke(ExceptionFilter.java:109) ~[jrescloud-dubbo-core-1.0.12.jar:1.0.12]
    at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:91) ~[jrescloud-dubbo-core-1.0.12.jar:1.0.12]
    at com.alibaba.dubbo.rpc.filter.TimeoutFilter.invoke(TimeoutFilter.java:42) ~[jrescloud-dubbo-core-1.0.12.jar:1.0.12]
    at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:91) ~[jrescloud-dubbo-core-1.0.12.jar:1.0.12]
    at com.alibaba.dubbo.rpc.protocol.dubbo.filter.TraceFilter.invoke(TraceFilter.java:78) ~[jrescloud-dubbo-core-1.0.12.jar:1.0.12]
    at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:91) ~[jrescloud-dubbo-core-1.0.12.jar:1.0.12]
    at com.alibaba.dubbo.monitor.support.MonitorFilter.invoke(MonitorFilter.java:75) ~[jrescloud-dubbo-core-1.0.12.jar:1.0.12]
    at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:91) ~[jrescloud-dubbo-core-1.0.12.jar:1.0.12]
    at com.xxx.me.dubbo.filter.IdempotentFilter.invoke(IdempotentFilter.java:61) ~[classes/:?]
    at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:91) ~[jrescloud-dubbo-core-1.0.12.jar:1.0.12]
    at com.xxx.me.dubbo.filter.MdcLogFilter.invoke(MdcLogFilter.java:58) ~[classes/:?]
    at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:91) ~[jrescloud-dubbo-core-1.0.12.jar:1.0.12]
    at com.alibaba.dubbo.rpc.filter.ContextFilter.invoke(ContextFilter.java:71) ~[jrescloud-dubbo-core-1.0.12.jar:1.0.12]
    at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:91) ~[jrescloud-dubbo-core-1.0.12.jar:1.0.12]
    at com.alibaba.dubbo.rpc.filter.GenericFilter.invoke(GenericFilter.java:132) ~[jrescloud-dubbo-core-1.0.12.jar:1.0.12]
    at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:91) ~[jrescloud-dubbo-core-1.0.12.jar:1.0.12]
    at com.alibaba.dubbo.rpc.filter.ClassLoaderFilter.invoke(ClassLoaderFilter.java:38) ~[jrescloud-dubbo-core-1.0.12.jar:1.0.12]
    at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:91) ~[jrescloud-dubbo-core-1.0.12.jar:1.0.12]
    at com.alibaba.dubbo.rpc.filter.EchoFilter.invoke(EchoFilter.java:38) ~[jrescloud-dubbo-core-1.0.12.jar:1.0.12]
    at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:91) ~[jrescloud-dubbo-core-1.0.12.jar:1.0.12]
    at com.xxx.jrescloud.rpc.monitor.MonitorProviderFilter.invoke(MonitorProviderFilter.java:68) ~[jrescloud-dubbo-monitor-1.0.12.jar:1.0.12]
    at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:91) ~[jrescloud-dubbo-core-1.0.12.jar:1.0.12]
    at com.xxx.jrescloud.rpc.trace.TraceProviderFilter.invoke(TraceProviderFilter.java:104) ~[jrescloud-dubbo-extend-1.0.12.jar:1.0.12]
    at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:91) ~[jrescloud-dubbo-core-1.0.12.jar:1.0.12]
    at com.alibaba.dubbo.rpc.protocol.dubbo.DubboProtocol$1.reply(DubboProtocol.java:113) ~[jrescloud-dubbo-core-1.0.12.jar:1.0.12]
    at com.alibaba.dubbo.remoting.exchange.support.header.HeaderExchangeHandler.handleRequest(HeaderExchangeHandler.java:84) ~[jrescloud-dubbo-core-1.0.12.jar:1.0.12]
    at com.alibaba.dubbo.remoting.exchange.support.header.HeaderExchangeHandler.received(HeaderExchangeHandler.java:170) ~[jrescloud-dubbo-core-1.0.12.jar:1.0.12]
    at com.alibaba.dubbo.remoting.transport.DecodeHandler.received(DecodeHandler.java:52) ~[jrescloud-dubbo-core-1.0.12.jar:1.0.12]
    at com.alibaba.dubbo.remoting.transport.dispatcher.ChannelEventRunnable.run(ChannelEventRunnable.java:82) ~[jrescloud-dubbo-core-1.0.12.jar:1.0.12]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) ~[?:1.8.0_171]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) ~[?:1.8.0_171]
    at java.lang.Thread.run(Thread.java:748) ~[?:1.8.0_171]

 

使用druid xa数据源有一个问题,jsmeck会看到在获取连接的地方一直WAITING:

"http-nio-8080-exec-54" daemon prio=10 tid=0x0000000000e61000 nid=0xcc9 waiting on condition [0x00007f4a753d4000]
   java.lang.Thread.Smete: WAITING (parking)
	at sun.misc.Unsafe.park(Native Method)
	- parking to wait for  <0x00000007a143f230> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
	at java.util.concurrent.locks.LockSupport.park(LockSupport.java:186)
	at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2043)
	at com.alibaba.druid.pool.DruidDameSource.mekeLast(DruidDameSource.java:1732)
	at com.alibaba.druid.pool.DruidDameSource.getConnectionInternal(DruidDameSource.java:1330)
	at com.alibaba.druid.pool.DruidDameSource.getConnectionDirect(DruidDameSource.java:1198)
	at com.alibaba.druid.filter.FilterChainImpl.dameSource_connect(FilterChainImpl.java:4619)

换成OracleXA就没有问题,使用的druid是1.1.10,所以应该不是早期版本bug的问题。

package com.xxx.me.aop;


import org.springframework.boot.autoconfigure.jdbc.DameSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.XADameSourceAutoConfiguration;
import org.springframework.context.annometion.ComponentScan;
import org.springframework.context.annometion.EnableAspectJAutoProxy;
import org.springframework.transaction.annometion.EnableTransactionManagement;

import com.xxx.jrescloud.common.annometion.CloudApplication;
import com.xxx.jrescloud.common.boot.CloudBootstrap;

@EnableTransactionManagement
@CloudApplication(exclude= {DameSourceAutoConfiguration.class,XADameSourceAutoConfiguration.class})
@ComponentScan("com.xxx.me.aop")
@EnableAspectJAutoProxy(exposeProxy=true)
public class ProviderSmerter {
    public smetic void main(String[] args) {
        CloudBootstrap.run(ProviderSmerter.class, args);
    }
}

atomikos以及spring boot下的几个陷阱:

atomikos几个坑:
jme.properties:
com.atomikos.icatch.output_dir=/dameyes/atomikos
com.atomikos.icatch.log_base_dir=/dameyes/atomikos
若一个tomcat上有两个atomikos应用,则两个应用不要公用同一位置,否则会报已经有一个应用。

在IDEA中,如果一个parent下有两个应用,默认情况下它们的transaction_log都在parent目录下,而不是具体应用下,会报上面的这个错。

mysql XA bug:

 

Some users have reported problems with MySQL XA (related to this MySQL bug: http://bugs.mysql.com/bug.php?id=27832external). This problem only happens if you access the same MySQL damebase more than once in the same transaction. A workaround can be setting the following property in classpath:jme.properties:

com.atomikos.icatch.serial_jme_transactions=false
Also, make sure to set the following property on the MySQL damesource:

 pinGlobalTxToPhysicalConnection="true"
MariaDB's java driver also supports this workaround since v.1.1.8

spring boot问题:

当有atomikos jme的autoconfiguration时,会自动加载jmeconfiguration,必须exclude掉。

优化:https://blog.csdn.net/wllovar/article/demeils/87100378