Spring4+Atomikos3.9+mysql6.06使用注解实现跨库事务
2017-12-06 14:40
471 查看
maven依赖
atomikos.properties:多个数据源配置
使用注解配置DataSource、JdbcTemplate、UserTransactionManager、UserTransactionImp、JtaTransactionManager
DynamicDataSource:继承了AbstractRoutingDataSource,设置多个数据源,将数据源交给Spring控制
为了使用注解方式进行动态切换数据源,需要定义一个DataSource注解,并且使用AOP方式进行数据源动态切换。DataSourceAspect 切面便是用于数据源切换。
DataSource注解:可作用于方法、class上, 用于class表明当前class的所有方法使用相同的数据源,用于方法上申明当前方法使用的数据源,当同时用于方法和class上时,用于方法上优先级较高。
DataSourceAspect:用于动态切换数据源.
DataSourceContextHolder:数据源切换实现类
MultiTransactional注解:用于跨库事务,仅仅可用于方法上,用于方法上表明当前方法所有操作属于同一个事务。
MultiTransactionalAspect:事务处理,减少重复代码编写。仅当请求方法有MultiTransactional注解时才会进入。
TestServiceImpl:测试将数据保存到不同的库(sakila,library)。
ActorServiceImpl
事务成功日志:
事务失败日志:
SpringContextUtil, SpringContext工具类,用于获取Bean
多数据源报错 :参考http://blog.csdn.net/gudejundd/article/details/52871432
错误原因:
有个DataSourceAutoConfiguration 会初始化DataSourceInitializer 这个类 ,这个类有一个init方法 会去获取DataSource(数据源)
初始化方法中 会获取数据源 需要初始化一些ddl操作 也是就runSchemaScripts()方法 检查初始化时是否需要执行sql script ,当你有多个数据源的时候,程序不知道取哪一个 ,所以报错
解决办法:
1.定义数据源的地方 加个@primary注解, 记得只给其中的一个加, 当多数据源时 标示这个数据源是主要的
2. spring boot 启动类加上 exclude = DataSourceAutoConfiguration.class 代表启动项目的时候 不加载这个类
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.mutil.transaction</groupId> <artifactId>transaction</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>transaction</name> <description>Demo project for Spring Boot</description> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.9.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jta-atomikos</artifactId> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>6.0.6</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
atomikos.properties:多个数据源配置
#####sakilaDataSource spring.datasource.sakila.xaProperties.url=jdbc:mysql://localhost:3306/sakila?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC&useSSL=true spring.datasource.sakila.xaProperties.user=root spring.datasource.sakila.xaProperties.password=root spring.datasource.sakila.driverClassName=com.mysql.cj.jdbc.Driver spring.datasource.sakila.minPoolSize=1 spring.datasource.sakila.maxPoolSize=10 spring.datasource.sakila.maxIdleTime=60 spring.datasource.sakila.uniqueResourceName=sakilaDataSource spring.datasource.sakila.xaDataSourceClassName=com.mysql.cj.jdbc.MysqlXADataSource #####libraryDataSource spring.datasource.library.xaProperties.url=jdbc:mysql://localhost:3306/library?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC&useSSL=true spring.datasource.library.xaProperties.user=root spring.datasource.library.xaProperties.password=root spring.datasource.library.driverClassName=com.mysql.cj.jdbc.Driver spring.datasource.library.minPoolSize=1 spring.datasource.library.maxPoolSize=10 spring.datasource.library.maxIdleTime=60 spring.datasource.library.uniqueResourceName=libraryDataSource spring.datasource.library.xaDataSourceClassName=com.mysql.cj.jdbc.MysqlXADataSource
使用注解配置DataSource、JdbcTemplate、UserTransactionManager、UserTransactionImp、JtaTransactionManager
package com.mutil.transaction.config; import javax.sql.DataSource; import javax.transaction.SystemException; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder; import org.springframework.boot.context.properties.ConfigurationProperties; 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.jdbc.core.JdbcTemplate; import org.springframework.transaction.jta.JtaTransactionManager; import com.atomikos.icatch.jta.UserTransactionImp; import com.atomikos.icatch.jta.UserTransactionManager; import com.atomikos.jdbc.AtomikosDataSourceBean; /** * Created by WuTing on 2017/12/5. */ @Configuration @PropertySource("classpath:atomikos.properties") public class DBConfig { @Primary @Bean("libraryDataSource") @ConfigurationProperties(prefix = "spring.datasource.library") public DataSource sakilaDataSource() { return DataSourceBuilder.create().type(AtomikosDataSourceBean.class).build(); } @Bean("sakilaDataSource") @ConfigurationProperties(prefix = "spring.datasource.sakila") public DataSource libraryDataSource() { return DataSourceBuilder.create().type(AtomikosDataSourceBean.class).build(); } @Bean("dataSource") public DynamicDataSource dataSource() { return new DynamicDataSource("libraryDataSource"); } @Bean("jdbcTemplate") public JdbcTemplate jdbcTemplate(@Qualifier("dataSource") DynamicDataSource dataSource) { return new JdbcTemplate(dataSource); } @Bean(name = "atomikosTransactionManager", initMethod = "init", destroyMethod = "close") public UserTransactionManager atomikosTransactionManager() { UserTransactionManager atomikosTransactionManager = new UserTransactionManager(); atomikosTransactionManager.setForceShutdown(true); return atomikosTransactionManager; } @Bean(name = "atomikosUserTransaction") public UserTransactionImp atomikosUserTransaction() { UserTransactionImp atomikosUserTransaction = new UserTransactionImp(); try { atomikosUserTransaction.setTransactionTimeout(300); } catch (SystemException e) { e.printStackTrace(); } return atomikosUserTransaction; } @Bean(name = "transactionManager") public JtaTransactionManager transactionManager(UserTransactionManager atomikosTransactionManager, UserTransactionImp atomikosUserTransaction) { JtaTransactionManager transactionManager = new JtaTransactionManager(); transactionManager.setTransactionManager(atomikosTransactionManager); transactionManager.setUserTransaction(atomikosUserTransaction); transactionManager.setAllowCustomIsolationLevels(true); return transactionManager; } }
DynamicDataSource:继承了AbstractRoutingDataSource,设置多个数据源,将数据源交给Spring控制
package com.mutil.transaction.config; import java.util.List; import java.util.Map; import java.util.stream.Collectors; import javax.sql.DataSource; import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; import com.atomikos.jdbc.AtomikosDataSourceBean; /** * Created by WuTing on 2017/12/5. */ public class DynamicDataSource extends AbstractRoutingDataSource { public DynamicDataSource(String defaultDataSourceName) { Map<Object, Object> dataSourcs = SpringContextUtil.getBeans(DataSource.class, DynamicDataSource.class); List dataSourceIds = dataSourcs.keySet().stream().collect(Collectors.toList()); DataSourceContextHolder.dataSourceIds.addAll(dataSourceIds); this.setTargetDataSources(dataSourcs); this.setDefaultTargetDataSource(dataSourcs.get(defaultDataSourceName)); } @Override protected Object determineCurrentLookupKey() { return DataSourceContextHolder.getDataSourceType(); } }
为了使用注解方式进行动态切换数据源,需要定义一个DataSource注解,并且使用AOP方式进行数据源动态切换。DataSourceAspect 切面便是用于数据源切换。
DataSource注解:可作用于方法、class上, 用于class表明当前class的所有方法使用相同的数据源,用于方法上申明当前方法使用的数据源,当同时用于方法和class上时,用于方法上优先级较高。
package com.mutil.transaction.config; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Inherited; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * Created by WuTing on 2017/12/5. */ @Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Inherited @Documented public @interface DataSource { String value(); }
DataSourceAspect:用于动态切换数据源.
package com.mutil.transaction.config; import java.lang.reflect.Method; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.reflect.MethodSignature; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; /** * Created by WuTing on 2017/12/5. */ @Component @Aspect @Order(1) public class DataSourceAspect { private static final Logger logger = LoggerFactory.getLogger(DataSourceAspect.class); @Before(value = "execution(* com.mutil.transaction.service.*.*(..))") public void before(JoinPoint point) { DataSource annotation = getDataSourceAnnotation(point); if (annotation != null) { DataSourceContextHolder.setDataSourceType(annotation.value()); logger.debug("Set DataSource : {} > {}", annotation.value(), point.getSignature()); } } @After(value = "execution(* com.mutil.transaction.service.*.*(..))") public void restoreDataSource(JoinPoint point) { DataSource annotation = getDataSourceAnnotation(point); if (annotation != null) { logger.debug("Revert DataSource : {} > {}", annotation.value(), point.getSignature()); } DataSourceContextHolder.clearDataSourceType(); } private DataSource getDataSourceAnnotation(JoinPoint point) { DataSource annotation = null; Class[] parameterTypes = ((MethodSignature)point.getSignature()).getMethod().getParameterTypes(); String methodName = point.getSignature().getName(); try { Method method = point.getTarget().getClass().getMethod(methodName, parameterTypes); if (method.isAnnotationPresent(DataSource.class)) { annotation = method.getAnnotation(DataSource.class); } else { annotation = point.getTarget().getClass().getAnnotation(DataSource.class); } } catch (NoSuchMethodException e) { e.printStackTrace(); } return annotation; } }
DataSourceContextHolder:数据源切换实现类
package com.mutil.transaction.config; import java.util.ArrayList; import java.util.List; /** * Created by WuTing on 2017/12/5. */ public class DataSourceContextHolder { private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>(); public static List<String> dataSourceIds = new ArrayList<>(); public static void setDataSourceType(String dataSourceType) { contextHolder.set(dataSourceType); } public static String getDataSourceType() { return contextHolder.get(); } public static void clearDataSourceType() { contextHolder.remove(); } public static boolean containsDataSource(String dataSourceId) { return dataSourceIds.contains(dataSourceId); } }
MultiTransactional注解:用于跨库事务,仅仅可用于方法上,用于方法上表明当前方法所有操作属于同一个事务。
package com.mutil.transaction.config; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Inherited; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import org.springframework.core.annotation.AliasFor; import org.springframework.transaction.annotation.Isolation; import org.springframework.transaction.annotation.Propagation; /** * Created by WuTing on 2017/12/6. */ @Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Inherited @Documented public @interface MultiTransactional { @AliasFor("transactionManager") String value() default ""; @AliasFor("value") String transactionManager() default ""; Class<? extends Throwable>[] rollbackFor() default {}; Class<? extends Throwable>[] noRollbackFor() default {}; }
MultiTransactionalAspect:事务处理,减少重复代码编写。仅当请求方法有MultiTransactional注解时才会进入。
package com.mutil.transaction.config; import java.lang.reflect.Method; import java.util.Arrays; import javax.transaction.UserTransaction; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.reflect.MethodSignature; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; import org.springframework.transaction.jta.JtaTransactionManager; /** * Created by WuTing on 2017/12/6. */ @Aspect @Component public class MultiTransactionalAspect { private static final Logger logger = LoggerFactory.getLogger(MultiTransactionalAspect.class); @Around(value = "@annotation(com.mutil.transaction.config.MultiTransactional)") public Object transactional(ProceedingJoinPoint point) throws Exception { String methodName = point.getSignature().getName(); Class[] parameterTypes = ((MethodSignature)point.getSignature()).getMethod().getParameterTypes(); UserTransaction tran = null; Object result = null; MultiTransactional multiTransactional = null; try { Method method = point.getTarget().getClass().getMethod(methodName, parameterTypes); if (method.isAnnotationPresent(MultiTransactional.class)) { multiTransactional = method.getAnnotation(MultiTransactional.class); JtaTransactionManager transactionManager = SpringContextUtil.getBean(JtaTransactionManager.class); tran = transactionManager.getUserTransaction(); tran.begin(); logger.warn(methodName + ", transaction begin"); result = point.proceed(); tran.commit(); logger.warn(methodName + ", transaction commit"); } } catch (Throwable e) { logger.error(e.getMessage(), e); if (tran != null) { Class<? extends Throwable>[] rollbackExcptions = multiTransactional.rollbackFor(); Class<? extends Throwable>[] noRollbackExcptions = multiTransactional.noRollbackFor(); boolean rollback = isPresent(e, rollbackExcptions); boolean noRollback = isPresent(e, noRollbackExcptions); if (rollback || !noRollback) { tran.rollback(); logger.warn(methodName + ", transaction rollback"); } else { tran.commit(); logger.warn(methodName + ", transaction commit"); } } } return result; } private boolean isPresent(Throwable e, Class<? extends Throwable>[] excptions) { return Arrays.stream(excptions) .filter(exception -> e.getClass().isAssignableFrom(exception) || e.getClass().equals(exception)) .findAny() .isPresent(); } }
TestServiceImpl:测试将数据保存到不同的库(sakila,library)。
package com.mutil.transaction.service; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.jta.JtaTransactionManager; import com.mutil.transaction.config.MultiTransactional; import com.mutil.transaction.model.Actor; import com.mutil.transaction.model.Author; /** * Created by WuTing on 2017/12/5. */ @Service public class TestServiceImpl implements TestService { @Autowired private ActorService actorService; @Autowired private AuthorService authorService; @Autowired @Qualifier("transactionManager") private JtaTransactionManager transactionManager; @MultiTransactional(rollbackFor = RuntimeException.class) @Override public Boolean saveDatas() { authorService.saveAuthor(); //library库 actorService.saveActor(); //sakila库 // 重构到MultiTransactionalAspect中 // UserTransaction tran = transactionManager.getUserTransaction(); // try { // tran.begin(); // authorService.saveAuthor(); // actorService.saveActor(); // tran.commit(); // } catch (Exception e) { // e.printStackTrace(); // try { // tran.rollback(); // } catch (SystemException e1) { // e1.printStackTrace(); // } // } return true; } }
ActorServiceImpl
package com.mutil.transaction.service; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Service; import com.mutil.transaction.config.DataSource; /** * Created by WuTing on 2017/12/5. */ @Service @DataSource("sakilaDataSource") //切库 public class ActorServiceImpl implements ActorService { @Autowired private JdbcTemplate jdbcTemplate; @Override public boolean saveActor() { jdbcTemplate.execute( "insert into actor(actor_id, first_name, last_name, last_update) values(999, 'wwww', 'baidu', '2017-12-05 00:00:00')"); // throw new RuntimeException(); return true; } }
package com.mutil.transaction.service; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Service; import com.mutil.transaction.config.DataSource; /** * Created by WuTing on 2017/12/5. */ @Service @DataSource("libraryDataSource") //切库 public class AuthorServiceImpl implements AuthorService { @Autowired private JdbcTemplate jdbcTemplate; @Override public boolean saveAuthor() { jdbcTemplate.execute("insert into author(id, first_name, last_name) values(999, 'wwww', 'baidu')"); return true; } }
事务成功日志:
2017-12-06 14:12:18.132 INFO 6748 --- [ main] c.a.icatch.imp.thread.TaskManager : THREADS: using JDK thread pooling... 2017-12-06 14:12:18.140 INFO 6748 --- [ main] c.a.icatch.imp.BaseTransactionManager : createCompositeTransaction ( 300000 ): created new ROOT transaction with id 10.34.135.125.tm0000100069 2017-12-06 14:12:18.141 WARN 6748 --- [ main] c.m.t.config.MultiTransactionalAspect : saveDatas, transaction begin 2017-12-06 14:12:18.158 INFO 6748 --- [ main] c.atomikos.jdbc.AbstractDataSourceBean : AtomikosDataSoureBean 'libraryDataSource': getConnection ( null )... 2017-12-06 14:12:18.158 INFO 6748 --- [ main] c.atomikos.jdbc.AbstractDataSourceBean : AtomikosDataSoureBean 'libraryDataSource': init... 2017-12-06 14:12:18.158 WARN 6748 --- [ main] c.atomikos.jdbc.AbstractDataSourceBean : AtomikosDataSoureBean 'libraryDataSource': poolSize equals default - this may cause performance problems! 2017-12-06 14:12:18.172 INFO 6748 --- [ main] c.atomikos.jdbc.AtomikosDataSourceBean : AtomikosDataSoureBean 'libraryDataSource': initializing with [ xaDataSourceClassName=com.mysql.cj.jdbc.MysqlXADataSource, uniqueResourceName=libraryDataSource, maxPoolSize=10, minPoolSize=1, borrowConnectionTimeout=30, maxIdleTime=60, reapTimeout=0, maintenanceInterval=60, testQuery=null, xaProperties=[user=root,password=root,url=jdbc:mysql://localhost:3306/library?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC&useSSL=true], loginTimeout=0, maxLifetime=0] 2017-12-06 14:12:18.349 INFO 6748 --- [ main] c.a.d.xa.XATransactionalResource : libraryDataSource: refreshed XAResource 2017-12-06 14:12:18.384 INFO 6748 --- [ main] c.a.icatch.imp.CompositeTransactionImp : addParticipant ( XAResourceTransaction: 31302E33342E3133352E3132352E746D30303030313030303639:31302E33342E3133352E3132352E746D31 ) for transaction 10.34.135.125.tm0000100069 2017-12-06 14:12:18.384 INFO 6748 --- [ main] c.a.datasource.xa.XAResourceTransaction : XAResource.start ( 31302E33342E3133352E3132352E746D30303030313030303639:31302E33342E3133352E3132352E746D31 , XAResource.TMNOFLAGS ) on resource libraryDataSource represented by XAResource instance com.mysql.cj.jdbc.MysqlXAConnection@4d8539de 2017-12-06 14:12:18.386 INFO 6748 --- [ main] c.a.icatch.imp.CompositeTransactionImp : registerSynchronization ( com.atomikos.jdbc.AtomikosConnectionProxy$JdbcRequeueSynchronization@da8cecee ) for transaction 10.34.135.125.tm0000100069 2017-12-06 14:12:18.386 INFO 6748 --- [ main] c.atomikos.jdbc.AtomikosConnectionProxy : atomikos connection proxy for com.mysql.cj.jdbc.ConnectionWrapper@a619c2: calling createStatement... 2017-12-06 14:12:18.392 INFO 6748 --- [ main] c.atomikos.jdbc.AtomikosConnectionProxy : atomikos connection proxy for com.mysql.cj.jdbc.ConnectionWrapper@a619c2: close()... 2017-12-06 14:12:18.392 INFO 6748 --- [ main] c.a.datasource.xa.XAResourceTransaction : XAResource.end ( 31302E33342E3133352E3132352E746D30303030313030303639:31302E33342E3133352E3132352E746D31 , XAResource.TMSUCCESS ) on resource libraryDataSource represented by XAResource instance com.mysql.cj.jdbc.MysqlXAConnection@4d8539de 2017-12-06 14:12:18.397 INFO 6748 --- [ main] c.atomikos.jdbc.AbstractDataSourceBean : AtomikosDataSoureBean 'sakilaDataSource': getConnection ( null )... 2017-12-06 14:12:18.397 INFO 6748 --- [ main] c.atomikos.jdbc.AbstractDataSourceBean : AtomikosDataSoureBean 'sakilaDataSource': init... 2017-12-06 14:12:18.397 WARN 6748 --- [ main] c.atomikos.jdbc.AbstractDataSourceBean : AtomikosDataSoureBean 'sakilaDataSource': poolSize equals default - this may cause performance problems! 2017-12-06 14:12:18.398 INFO 6748 --- [ main] c.atomikos.jdbc.AtomikosDataSourceBean : AtomikosDataSoureBean 'sakilaDataSource': initializing with [ xaDataSourceClassName=com.mysql.cj.jdbc.MysqlXADataSource, uniqueResourceName=sakilaDataSource, maxPoolSize=10, minPoolSize=1, borrowConnectionTimeout=30, maxIdleTime=60, reapTimeout=0, maintenanceInterval=60, testQuery=null, xaProperties=[user=root,password=root,url=jdbc:mysql://localhost:3306/sakila?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC&useSSL=true], loginTimeout=0, maxLifetime=0] 2017-12-06 14:12:18.405 INFO 6748 --- [ main] c.a.d.xa.XATransactionalResource : sakilaDataSource: refreshed XAResource 2017-12-06 14:12:18.411 INFO 6748 --- [ main] c.a.icatch.imp.CompositeTransactionImp : addParticipant ( XAResourceTransaction: 31302E33342E3133352E3132352E746D30303030313030303639:31302E33342E3133352E3132352E746D32 ) for transaction 10.34.135.125.tm0000100069 2017-12-06 14:12:18.411 INFO 6748 --- [ main] c.a.datasource.xa.XAResourceTransaction : XAResource.start ( 31302E33342E3133352E3132352E746D30303030313030303639:31302E33342E3133352E3132352E746D32 , XAResource.TMNOFLAGS ) on resource sakilaDataSource represented by XAResource instance com.mysql.cj.jdbc.MysqlXAConnection@18fdb6cf 2017-12-06 14:12:18.412 INFO 6748 --- [ main] c.a.icatch.imp.CompositeTransactionImp : registerSynchronization ( com.atomikos.jdbc.AtomikosConnectionProxy$JdbcRequeueSynchronization@da8cecee ) for transaction 10.34.135.125.tm0000100069 2017-12-06 14:12:18.412 INFO 6748 --- [ main] c.atomikos.jdbc.AtomikosConnectionProxy : atomikos connection proxy for com.mysql.cj.jdbc.ConnectionWrapper@61533ae: calling createStatement... 2017-12-06 14:12:18.413 INFO 6748 --- [ main] c.atomikos.jdbc.AtomikosConnectionProxy : atomikos connection proxy for com.mysql.cj.jdbc.ConnectionWrapper@61533ae: close()... 2017-12-06 14:12:18.413 INFO 6748 --- [ main] c.a.datasource.xa.XAResourceTransaction : XAResource.end ( 31302E33342E3133352E3132352E746D30303030313030303639:31302E33342E3133352E3132352E746D32 , XAResource.TMSUCCESS ) on resource sakilaDataSource represented by XAResource instance com.mysql.cj.jdbc.MysqlXAConnection@18fdb6cf 2017-12-06 14:12:18.415 INFO 6748 --- [ main] c.a.icatch.imp.CompositeTransactionImp : commit() done (by application) of transaction 10.34.135.125.tm0000100069 2017-12-06 14:12:18.418 INFO 6748 --- [ main] c.a.datasource.xa.XAResourceTransaction : XAResource.prepare ( 31302E33342E3133352E3132352E746D30303030313030303639:31302E33342E3133352E3132352E746D31 ) returning OK on resource libraryDataSource represented by XAResource instance com.mysql.cj.jdbc.MysqlXAConnection@4d8539de 2017-12-06 14:12:18.421 INFO 6748 --- [ main] c.a.datasource.xa.XAResourceTransaction : XAResource.prepare ( 31302E33342E3133352E3132352E746D30303030313030303639:31302E33342E3133352E3132352E746D32 ) returning OK on resource sakilaDataSource represented by XAResource instance com.mysql.cj.jdbc.MysqlXAConnection@18fdb6cf 2017-12-06 14:12:18.458 INFO 6748 --- [ main] c.a.datasource.xa.XAResourceTransaction : XAResource.commit ( 31302E33342E3133352E3132352E746D30303030313030303639:31302E33342E3133352E3132352E746D31 , false ) on resource libraryDataSource represented by XAResource instance com.mysql.cj.jdbc.MysqlXAConnection@4d8539de 2017-12-06 14:12:18.461 INFO 6748 --- [ main] c.a.datasource.xa.XAResourceTransaction : XAResource.commit ( 31302E33342E3133352E3132352E746D30303030313030303639:31302E33342E3133352E3132352E746D32 , false ) on resource sakilaDataSource represented by XAResource instance com.mysql.cj.jdbc.MysqlXAConnection@18fdb6cf 2017-12-06 14:12:18.463 WARN 6748 --- [ main] c.m.t.config.MultiTransactionalAspect : saveDatas, transaction commit 2017-12-06 14:12:18.467 INFO 6748 --- [ Thread-2] s.c.a.AnnotationConfigApplicationContext : Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@2cd76f31: startup date [Wed Dec 06 14:12:16 CST 2017]; root of context hierarchy 2017-12-06 14:12:18.469 INFO 6748 --- [ Thread-2] c.a.persistence.imp.AbstractLogStream : Logfile closed: F:\code\transaction\.\tmlog68.log 2017-12-06 14:12:18.475 INFO 6748 --- [ Thread-2] c.atomikos.jdbc.AbstractDataSourceBean : AtomikosDataSoureBean 'sakilaDataSource': close... 2017-12-06 14:12:18.476 INFO 6748 --- [ Thread-2] c.a.datasource.pool.ConnectionPool : atomikos connection pool 'sakilaDataSource': destroying pool... 2017-12-06 14:12:18.477 INFO 6748 --- [ Thread-2] c.atomikos.jdbc.AbstractDataSourceBean : AtomikosDataSoureBean 'libraryDataSource': close... 2017-12-06 14:12:18.477 INFO 6748 --- [ Thread-2] c.a.datasource.pool.ConnectionPool : atomikos connection pool 'libraryDataSource': destroying pool...
事务失败日志:
2017-12-06 14:13:20.888 INFO 27904 --- [ main] c.a.icatch.imp.thread.TaskManager : THREADS: using JDK thread pooling... 2017-12-06 14:13:20.897 INFO 27904 --- [ main] c.a.icatch.imp.BaseTransactionManager : createCompositeTransaction ( 300000 ): created new ROOT transaction with id 10.34.135.125.tm0000100070 2017-12-06 14:13:20.898 WARN 27904 --- [ main] c.m.t.config.MultiTransactionalAspect : saveDatas, transaction begin 2017-12-06 14:13:20.914 INFO 27904 --- [ main] c.atomikos.jdbc.AbstractDataSourceBean : AtomikosDataSoureBean 'libraryDataSource': getConnection ( null )... 2017-12-06 14:13:20.914 INFO 27904 --- [ main] c.atomikos.jdbc.AbstractDataSourceBean : AtomikosDataSoureBean 'libraryDataSource': init... 2017-12-06 14:13:20.915 WARN 27904 --- [ main] c.atomikos.jdbc.AbstractDataSourceBean : AtomikosDataSoureBean 'libraryDataSource': poolSize equals default - this may cause performance problems! 2017-12-06 14:13:20.927 INFO 27904 --- [ main] c.atomikos.jdbc.AtomikosDataSourceBean : AtomikosDataSoureBean 'libraryDataSource': initializing with [ xaDataSourceClassName=com.mysql.cj.jdbc.MysqlXADataSource, uniqueResourceName=libraryDataSource, maxPoolSize=10, minPoolSize=1, borrowConnectionTimeout=30, maxIdleTime=60, reapTimeout=0, maintenanceInterval=60, testQuery=null, xaProperties=[user=root,password=root,url=jdbc:mysql://localhost:3306/library?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC&useSSL=true], loginTimeout=0, maxLifetime=0] 2017-12-06 14:13:21.083 INFO 27904 --- [ main] c.a.d.xa.XATransactionalResource : libraryDataSource: refreshed XAResource 2017-12-06 14:13:21.116 INFO 27904 --- [ main] c.a.icatch.imp.CompositeTransactionImp : addParticipant ( XAResourceTransaction: 31302E33342E3133352E3132352E746D30303030313030303730:31302E33342E3133352E3132352E746D31 ) for transaction 10.34.135.125.tm0000100070 2017-12-06 14:13:21.116 INFO 27904 --- [ main] c.a.datasource.xa.XAResourceTransaction : XAResource.start ( 31302E33342E3133352E3132352E746D30303030313030303730:31302E33342E3133352E3132352E746D31 , XAResource.TMNOFLAGS ) on resource libraryDataSource represented by XAResource instance com.mysql.cj.jdbc.MysqlXAConnection@1a411233 2017-12-06 14:13:21.118 INFO 27904 --- [ main] c.a.icatch.imp.CompositeTransactionImp : registerSynchronization ( com.atomikos.jdbc.AtomikosConnectionProxy$JdbcRequeueSynchronization@da8ced04 ) for transaction 10.34.135.125.tm0000100070 2017-12-06 14:13:21.118 INFO 27904 --- [ main] c.atomikos.jdbc.AtomikosConnectionProxy : atomikos connection proxy for com.mysql.cj.jdbc.ConnectionWrapper@3605c4d3: calling createStatement... 2017-12-06 14:13:21.127 INFO 27904 --- [ main] c.atomikos.jdbc.AtomikosConnectionProxy : atomikos connection proxy for com.mysql.cj.jdbc.ConnectionWrapper@3605c4d3: close()... 2017-12-06 14:13:21.127 INFO 27904 --- [ main] c.a.datasource.xa.XAResourceTransaction : XAResource.end ( 31302E33342E3133352E3132352E746D30303030313030303730:31302E33342E3133352E3132352E746D31 , XAResource.TMSUCCESS ) on resource libraryDataSource represented by XAResource instance com.mysql.cj.jdbc.MysqlXAConnection@1a411233 2017-12-06 14:13:21.132 INFO 27904 --- [ main] o.s.b.f.xml.XmlBeanDefinitionReader : Loading XML bean definitions from class path resource [org/springframework/jdbc/support/sql-error-codes.xml] 2017-12-06 14:13:21.190 INFO 27904 --- [ main] o.s.jdbc.support.SQLErrorCodesFactory : SQLErrorCodes loaded: [DB2, Derby, H2, HSQL, Informix, MS-SQL, MySQL, Oracle, PostgreSQL, Sybase, Hana] 2017-12-06 14:13:21.190 INFO 27904 --- [ main] c.atomikos.jdbc.AbstractDataSourceBean : AtomikosDataSoureBean 'libraryDataSource': getConnection ( null )... 2017-12-06 14:13:21.191 INFO 27904 --- [ main] c.atomikos.jdbc.AbstractDataSourceBean : AtomikosDataSoureBean 'libraryDataSource': init... 2017-12-06 14:13:21.191 INFO 27904 --- [ main] c.atomikos.jdbc.AtomikosConnectionProxy : atomikos connection proxy for com.mysql.cj.jdbc.ConnectionWrapper@3605c4d3: calling getMetaData... 2017-12-06 14:13:21.191 INFO 27904 --- [ main] c.atomikos.jdbc.AtomikosConnectionProxy : atomikos connection proxy for com.mysql.cj.jdbc.ConnectionWrapper@3605c4d3: close()... 2017-12-06 14:13:21.196 ERROR 27904 --- [ main] c.m.t.config.MultiTransactionalAspect : StatementCallback; SQL [insert into author(id, first_name, last_name) values(999, 'wwww', 'baidu')]; Duplicate entry '999' for key 'PRIMARY'; nested exception is java.sql.SQLIntegrityConstraintViolationException: Duplicate entry '999' for key 'PRIMARY' org.springframework.dao.DuplicateKeyException: StatementCallback; SQL [insert into author(id, first_name, last_name) values(999, 'wwww', 'baidu')]; Duplicate entry '999' for key 'PRIMARY'; nested exception is java.sql.SQLIntegrityConstraintViolationException: Duplicate entry '999' for key 'PRIMARY' at org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator.doTranslate(SQLErrorCodeSQLExceptionTranslator.java:239) ~[spring-jdbc-4.3.13.RELEASE.jar:4.3.13.RELEASE] at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:73) ~[spring-jdbc-4.3.13.RELEASE.jar:4.3.13.RELEASE] at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:419) ~[spring-jdbc-4.3.13.RELEASE.jar:4.3.13.RELEASE] at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:445) ~[spring-jdbc-4.3.13.RELEASE.jar:4.3.13.RELEASE] at com.mutil.transaction.service.AuthorServiceImpl.saveAuthor(AuthorServiceImpl.java:20) ~[classes/:na] at com.mutil.transaction.service.AuthorServiceImpl$$FastClassBySpringCGLIB$$156f1815.invoke(<generated>) ~[classes/:na] at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) ~[spring-core-4.3.13.RELEASE.jar:4.3.13.RELEASE] at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:738) ~[spring-aop-4.3.13.RELEASE.jar:4.3.13.RELEASE] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157) [spring-aop-4.3.13.RELEASE.jar:4.3.13.RELEASE] at org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor.invoke(MethodBeforeAdviceInterceptor.java:52) [spring-aop-4.3.13.RELEASE.jar:4.3.13.RELEASE] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) [spring-aop-4.3.13.RELEASE.jar:4.3.13.RELEASE] at org.springframework.aop.aspectj.AspectJAfterAdvice.invoke(AspectJAfterAdvice.java:47) [spring-aop-4.3.13.RELEASE.jar:4.3.13.RELEASE] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) [spring-aop-4.3.13.RELEASE.jar:4.3.13.RELEASE] at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92) [spring-aop-4.3.13.RELEASE.jar:4.3.13.RELEASE] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) [spring-aop-4.3.13.RELEASE.jar:4.3.13.RELEASE] at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:673) [spring-aop-4.3.13.RELEASE.jar:4.3.13.RELEASE] at com.mutil.transaction.service.AuthorServiceImpl$$EnhancerBySpringCGLIB$$a3ec647.saveAuthor(<generated>) ~[classes/:na] at com.mutil.transaction.service.TestServiceImpl.saveDatas(TestServiceImpl.java:70) ~[classes/:na] at com.mutil.transaction.service.TestServiceImpl$$FastClassBySpringCGLIB$$f5a0a96e.invoke(<generated>) ~[classes/:na] at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) ~[spring-core-4.3.13.RELEASE.jar:4.3.13.RELEASE] at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:738) ~[spring-aop-4.3.13.RELEASE.jar:4.3.13.RELEASE] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157) [spring-aop-4.3.13.RELEASE.jar:4.3.13.RELEASE] at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:85) ~[spring-aop-4.3.13.RELEASE.jar:4.3.13.RELEASE] at com.mutil.transaction.config.MultiTransactionalAspect.transactional(MultiTransactionalAspect.java:42) ~[classes/:na] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_131] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_131] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_131] at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_131] at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:629) [spring-aop-4.3.13.RELEASE.jar:4.3.13.RELEASE] at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:618) [spring-aop-4.3.13.RELEASE.jar:4.3.13.RELEASE] at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:70) [spring-aop-4.3.13.RELEASE.jar:4.3.13.RELEASE] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:168) [spring-aop-4.3.13.RELEASE.jar:4.3.13.RELEASE] at org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor.invoke(MethodBeforeAdviceInterceptor.java:52) [spring-aop-4.3.13.RELEASE.jar:4.3.13.RELEASE] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) [spring-aop-4.3.13.RELEASE.jar:4.3.13.RELEASE] at org.springframework.aop.aspectj.AspectJAfterAdvice.invoke(AspectJAfterAdvice.java:47) [spring-aop-4.3.13.RELEASE.jar:4.3.13.RELEASE] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) [spring-aop-4.3.13.RELEASE.jar:4.3.13.RELEASE] at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92) [spring-aop-4.3.13.RELEASE.jar:4.3.13.RELEASE] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) [spring-aop-4.3.13.RELEASE.jar:4.3.13.RELEASE] at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:673) [spring-aop-4.3.13.RELEASE.jar:4.3.13.RELEASE] at com.mutil.transaction.service.TestServiceImpl$$EnhancerBySpringCGLIB$$e95da300.saveDatas(<generated>) [classes/:na] at com.mutil.transaction.TransactionApplicationTests.saveDatas(TransactionApplicationTests.java:55) [test-classes/:na] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_131] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_131] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_131] at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_131] at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50) [junit-4.12.jar:4.12] at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) [junit-4.12.jar:4.12] at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47) [junit-4.12.jar:4.12] at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) [junit-4.12.jar:4.12] at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75) [spring-test-4.3.13.RELEASE.jar:4.3.13.RELEASE] at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86) [spring-test-4.3.13.RELEASE.jar:4.3.13.RELEASE] at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84) [spring-test-4.3.13.RELEASE.jar:4.3.13.RELEASE] at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325) [junit-4.12.jar:4.12] at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:252) [spring-test-4.3.13.RELEASE.jar:4.3.13.RELEASE] at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:94) [spring-test-4.3.13.RELEASE.jar:4.3.13.RELEASE] at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) [junit-4.12.jar:4.12] at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) [junit-4.12.jar:4.12] at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) [junit-4.12.jar:4.12] at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) [junit-4.12.jar:4.12] at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) [junit-4.12.jar:4.12] at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61) [spring-test-4.3.13.RELEASE.jar:4.3.13.RELEASE] at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70) [spring-test-4.3.13.RELEASE.jar:4.3.13.RELEASE] at org.junit.runners.ParentRunner.run(ParentRunner.java:363) [junit-4.12.jar:4.12] at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191) [spring-test-4.3.13.RELEASE.jar:4.3.13.RELEASE] at org.junit.runner.JUnitCore.run(JUnitCore.java:137) [junit-4.12.jar:4.12] at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68) [junit-rt.jar:na] at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47) [junit-rt.jar:na] at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242) [junit-rt.jar:na] at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70) [junit-rt.jar:na] Caused by: java.sql.SQLIntegrityConstraintViolationException: Duplicate entry '999' for key 'PRIMARY' at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:533) ~[mysql-connector-java-6.0.6.jar:6.0.6] at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:513) ~[mysql-connector-java-6.0.6.jar:6.0.6] at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:115) ~[mysql-connector-java-6.0.6.jar:6.0.6] at com.mysql.cj.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:1983) ~[mysql-connector-java-6.0.6.jar:6.0.6] at com.mysql.cj.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:1936) ~[mysql-connector-java-6.0.6.jar:6.0.6] at com.mysql.cj.jdbc.StatementImpl.executeInternal(StatementImpl.java:891) ~[mysql-connector-java-6.0.6.jar:6.0.6] at com.mysql.cj.jdbc.StatementImpl.execute(StatementImpl.java:795) ~[mysql-connector-java-6.0.6.jar:6.0.6] at com.mysql.cj.jdbc.StatementWrapper.execute(StatementWrapper.java:461) ~[mysql-connector-java-6.0.6.jar:6.0.6] at org.springframework.jdbc.core.JdbcTemplate$1ExecuteStatementCallback.doInStatement(JdbcTemplate.java:436) ~[spring-jdbc-4.3.13.RELEASE.jar:4.3.13.RELEASE] at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:408) ~[spring-jdbc-4.3.13.RELEASE.jar:4.3.13.RELEASE] ... 66 common frames omitted 2017-12-06 14:13:21.201 INFO 27904 --- [ main] c.a.datasource.xa.XAResourceTransaction : XAResource.rollback ( 31302E33342E3133352E3132352E746D30303030313030303730:31302E33342E3133352E3132352E746D31 ) on resource libraryDataSource represented by XAResource instance com.mysql.cj.jdbc.MysqlXAConnection@1a411233 2017-12-06 14:13:21.203 INFO 27904 --- [ main] c.a.icatch.imp.CompositeTransactionImp : rollback() done of transaction 10.34.135.125.tm0000100070 2017-12-06 14:13:21.203 WARN 27904 --- [ main] c.m.t.config.MultiTransactionalAspect : saveDatas, transaction rollback 2017-12-06 14:13:21.206 INFO 27904 --- [ Thread-2] s.c.a.AnnotationConfigApplicationContext : Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@2cd76f31: startup date [Wed Dec 06 14:13:19 CST 2017]; root of context hierarchy 2017-12-06 14:13:21.208 INFO 27904 --- [ Thread-2] c.a.persistence.imp.AbstractLogStream : Logfile closed: F:\code\transaction\.\tmlog69.log 2017-12-06 14:13:21.213 INFO 27904 --- [ Thread-2] c.atomikos.jdbc.AbstractDataSourceBean : AtomikosDataSoureBean 'sakilaDataSource': close... 2017-12-06 14:13:21.213 INFO 27904 --- [ Thread-2] c.atomikos.jdbc.AbstractDataSourceBean : AtomikosDataSoureBean 'libraryDataSource': close... 2017-12-06 14:13:21.213 INFO 27904 --- [ Thread-2] c.a.datasource.pool.ConnectionPool : atomikos connection pool 'libraryDataSource': destroying pool...
SpringContextUtil, SpringContext工具类,用于获取Bean
package com.mutil.transaction.config; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.Map; import org.springframework.beans.BeansException; import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.stereotype.Component; import com.atomikos.jdbc.AtomikosDataSourceBean; /** * Created by WuTing on 2017/12/5. */ @Component public class SpringContextUtil implements ApplicationContextAware { private static ApplicationContext applicationContext; @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { SpringContextUtil.applicationContext = applicationContext; } public static ApplicationContext getApplicationContext() { return applicationContext; } public static <T> T getBean(String name) throws BeansException { return (T)applicationContext.getBean(name); } public static <T> T getBean(String name, Class<?> requiredType) throws BeansException { return applicationContext.getBean(name, (Class<T>)requiredType); } public static <T> T getBean(Class<?> requiredType) throws BeansException { String[] names = applicationContext.getBeanNamesForType(requiredType); if (names == null || names.length == 0) { throw new IllegalArgumentException("没有找到Bean,类型:" + requiredType.getName()); } return (T)applicationContext.getBean(names[0]); } public static <T> Collection<T> getBeans(String... names) throws BeansException { Collection<T> beans = new ArrayList<>(); for (String name : names) { beans.add((T)applicationContext.getBean(name)); } return beans; } public static <T> Map<Object, T> getBeans(Class<?> requiredType) throws BeansException { Map<Object, T> beans = new HashMap<>(); String[] names = applicationContext.getBeanNamesForType(requiredType); for (String name : names) { beans.put(name, (T)applicationContext.getBean(name)); } return beans; } public static <T> Map<Object, T> getBeans(Class<?> requiredType, Class<?>... excludeTypes) throws BeansException { Map<Object, T> beans = new HashMap<>(); String[] names = applicationContext.getBeanNamesForType(requiredType); for (String name : names) { Class type = applicationContext.getType(name); if (excludeTypes != null) { boolean flag = Arrays.stream(excludeTypes) .filter(excludeType -> excludeType.equals(type)) .findAny() .isPresent(); if (flag) { continue; } } beans.put(name, (T)applicationContext.getBean(name)); } return beans; } public static boolean containsBean(String name) { return applicationContext.containsBean(name); } public static boolean isSingleton(String name) throws NoSuchBeanDefinitionException { return applicationContext.isSingleton(name); } public static Class<?> getType(String name) throws NoSuchBeanDefinitionException { return applicationContext.getType(name); } public static String[] getAliases(String name) throws NoSuchBeanDefinitionException { return applicationContext.getAliases(name); } }
多数据源报错 :参考http://blog.csdn.net/gudejundd/article/details/52871432
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'javax.sql.DataSource' available: expected single matching bean but found 3: libraryDataSource,sakilaDataSource,dataSource at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveNamedBean(DefaultListableBeanFactory.java:1041) at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:345) at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:340) at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1092) at org.springframework.boot.autoconfigure.jdbc.DataSourceInitializer.init(DataSourceInitializer.java:77) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleElement.invoke(InitDestroyAnnotationBeanPostProcessor.java:366) at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleMetadata.invokeInitMethods(InitDestroyAnnotationBeanPostProcessor.java:311) at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:134) ... 104 more
错误原因:
有个DataSourceAutoConfiguration 会初始化DataSourceInitializer 这个类 ,这个类有一个init方法 会去获取DataSource(数据源)
初始化方法中 会获取数据源 需要初始化一些ddl操作 也是就runSchemaScripts()方法 检查初始化时是否需要执行sql script ,当你有多个数据源的时候,程序不知道取哪一个 ,所以报错
解决办法:
1.定义数据源的地方 加个@primary注解, 记得只给其中的一个加, 当多数据源时 标示这个数据源是主要的
2. spring boot 启动类加上 exclude = DataSourceAutoConfiguration.class 代表启动项目的时候 不加载这个类
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
相关文章推荐
- Spring4+dbcp+mysql6.06使用注解实现动态切库(不支持跨库事务)
- Spring 使用注解方式进行事务管理 /==/ Spring分布式事务实现
- 使用Spring注解方试实现AOP1--前后通知与后置通知
- 使用Spring注解方式管理事务与传播行为详解
- 使用Spring的注解方式实现AOP入门
- Spring2.0用注解实现事务管理
- 使用Spring注解方试实现AOP2--环绕通知(周围通知)
- ITCAST视频-Spring学习笔记(使用Spring的注解方式实现AOP的细节)
- Spring学习笔记(15)----使用Spring注解方式管理事务
- flex4 + spring + blazeds , 使用anonation(注解)机制,利用push技术的实现例子和过程。
- Spring 使用Spring注解方式管理事务与传播行为
- Spring 下事务管理-使用AOP @Transactional注解管理
- 使用Spring 2.0 新特性实现声明式事务管理-基于XML Schema
- Spring学习笔记(16)----使用Spring配置文件实现事务管理
- flex4 + spring + blazeds , 使用anonation(注解)机制,利用push技术的实现例子和过程。
- 使用Spring 2.0 新特性实现声明式事务管理-基于XML Schema
- Spring视频学习(九)使用Spring注解方式管理事务与传播行为详解
- 使用注解,实现ssh项目中spring配置文件的零配置,约定优于配置
- Spring2.0用注解实现事务管理
- Spring学习笔记(14)----使用Spring的注解方式实现AOP