From 5d14433073ce4ecd902c05ed740a1b37c4ff886b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=BD=97=E7=A5=A5?= <1366971433@qq.com> Date: Fri, 25 Jan 2019 15:21:09 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=A4=9A=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E6=BA=90=E7=94=A8=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pictures/multi-console.png | Bin 0 -> 55009 bytes pictures/multi-db-show.png | Bin 0 -> 13547 bytes pictures/multi-db1-show.png | Bin 0 -> 11161 bytes pictures/multi-db1.png | Bin 0 -> 12326 bytes pictures/multi-db2-show.png | Bin 0 -> 11350 bytes pictures/multi-db2.png | Bin 0 -> 12114 bytes pictures/multi-tran-fail.png | Bin 0 -> 12355 bytes .../springboot-druid-mybatis-multi/pom.xml | 91 +++ .../DruidMybatisMultiApplication.java | 15 + .../aop/DynamicDataSourceAspect.java | 40 + .../springboot/bean/Programmer.java | 34 + .../config/AbstractDataSourceConfig.java | 47 ++ .../config/CustomSqlSessionTemplate.java | 739 ++++++++++++++++++ .../springboot/config/DataSourceConfig.java | 145 ++++ .../config/DataSourceContextHolder.java | 25 + .../springboot/config/DynamicDataSource.java | 16 + .../config/XATransactionManagerConfig.java | 42 + .../heibaiying/springboot/constant/Data.java | 11 + .../springboot/controller/TestController.java | 61 ++ .../controller/TransactionController.java | 40 + .../controller/XATransactionController.java | 44 ++ .../springboot/dao/ProgrammerMapper.java | 24 + .../src/main/resources/application.yml | 113 +++ .../resources/mappers/ProgrammerMapper.xml | 27 + ...bootDruidMybatisMultiApplicationTests.java | 17 + .../springboot-druid-mybatis-multi/tmlog.lck | 0 .../tmlog101.log | 9 + 27 files changed, 1540 insertions(+) create mode 100644 pictures/multi-console.png create mode 100644 pictures/multi-db-show.png create mode 100644 pictures/multi-db1-show.png create mode 100644 pictures/multi-db1.png create mode 100644 pictures/multi-db2-show.png create mode 100644 pictures/multi-db2.png create mode 100644 pictures/multi-tran-fail.png create mode 100644 spring-boot/springboot-druid-mybatis-multi/pom.xml create mode 100644 spring-boot/springboot-druid-mybatis-multi/src/main/java/com/heibaiying/springboot/DruidMybatisMultiApplication.java create mode 100644 spring-boot/springboot-druid-mybatis-multi/src/main/java/com/heibaiying/springboot/aop/DynamicDataSourceAspect.java create mode 100644 spring-boot/springboot-druid-mybatis-multi/src/main/java/com/heibaiying/springboot/bean/Programmer.java create mode 100644 spring-boot/springboot-druid-mybatis-multi/src/main/java/com/heibaiying/springboot/config/AbstractDataSourceConfig.java create mode 100644 spring-boot/springboot-druid-mybatis-multi/src/main/java/com/heibaiying/springboot/config/CustomSqlSessionTemplate.java create mode 100644 spring-boot/springboot-druid-mybatis-multi/src/main/java/com/heibaiying/springboot/config/DataSourceConfig.java create mode 100644 spring-boot/springboot-druid-mybatis-multi/src/main/java/com/heibaiying/springboot/config/DataSourceContextHolder.java create mode 100644 spring-boot/springboot-druid-mybatis-multi/src/main/java/com/heibaiying/springboot/config/DynamicDataSource.java create mode 100644 spring-boot/springboot-druid-mybatis-multi/src/main/java/com/heibaiying/springboot/config/XATransactionManagerConfig.java create mode 100644 spring-boot/springboot-druid-mybatis-multi/src/main/java/com/heibaiying/springboot/constant/Data.java create mode 100644 spring-boot/springboot-druid-mybatis-multi/src/main/java/com/heibaiying/springboot/controller/TestController.java create mode 100644 spring-boot/springboot-druid-mybatis-multi/src/main/java/com/heibaiying/springboot/controller/TransactionController.java create mode 100644 spring-boot/springboot-druid-mybatis-multi/src/main/java/com/heibaiying/springboot/controller/XATransactionController.java create mode 100644 spring-boot/springboot-druid-mybatis-multi/src/main/java/com/heibaiying/springboot/dao/ProgrammerMapper.java create mode 100644 spring-boot/springboot-druid-mybatis-multi/src/main/resources/application.yml create mode 100644 spring-boot/springboot-druid-mybatis-multi/src/main/resources/mappers/ProgrammerMapper.xml create mode 100644 spring-boot/springboot-druid-mybatis-multi/src/test/java/com/heibaiying/springboot/SpringbootDruidMybatisMultiApplicationTests.java create mode 100644 spring-boot/springboot-druid-mybatis-multi/tmlog.lck create mode 100644 spring-boot/springboot-druid-mybatis-multi/tmlog101.log diff --git a/pictures/multi-console.png b/pictures/multi-console.png new file mode 100644 index 0000000000000000000000000000000000000000..876c645aad43403c118f05bb4d845051b5313c7b GIT binary patch literal 55009 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 literal 0 HcmV?d00001 diff --git a/pictures/multi-db-show.png b/pictures/multi-db-show.png new file mode 100644 index 0000000000000000000000000000000000000000..384d34c3c8d51d140996deb1888ef5ed012bd70f GIT binary patch literal 13547 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 Fe*gemVsZcg literal 0 HcmV?d00001 diff --git a/pictures/multi-db1-show.png b/pictures/multi-db1-show.png new file mode 100644 index 0000000000000000000000000000000000000000..2c70db14ab998dcc8583389a0f266bdc68c1be86 GIT binary patch literal 11161 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 T`&po@7NjJvCig?eB=r9QwOFao literal 0 HcmV?d00001 diff --git a/pictures/multi-db1.png b/pictures/multi-db1.png new file mode 100644 index 0000000000000000000000000000000000000000..7953cebc37882d96ec4f1c26123a82fab19c262e GIT binary patch literal 12326 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 literal 0 HcmV?d00001 diff --git a/pictures/multi-db2.png b/pictures/multi-db2.png new file mode 100644 index 0000000000000000000000000000000000000000..312bbc4199cd6138f0c8e3fb047da3f9e3a4c49c GIT binary patch literal 12114 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 DUz-Rl literal 0 HcmV?d00001 diff --git a/spring-boot/springboot-druid-mybatis-multi/pom.xml b/spring-boot/springboot-druid-mybatis-multi/pom.xml new file mode 100644 index 0000000..cc44259 --- /dev/null +++ b/spring-boot/springboot-druid-mybatis-multi/pom.xml @@ -0,0 +1,91 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.1.2.RELEASE + + + com.heibaiying + springboot-druid-mybatis-multi + 0.0.1-SNAPSHOT + springBoot-druid-mybatis-multi + Demo project for Spring Boot + + + 1.8 + + + + + org.mybatis.spring.boot + mybatis-spring-boot-starter + 1.3.2 + + + + + mysql + mysql-connector-java + 6.0.6 + + + + com.alibaba + druid-spring-boot-starter + 1.1.10 + + + + org.springframework.boot + spring-boot-starter-aop + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-jta-atomikos + + + org.projectlombok + lombok + true + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/spring-boot/springboot-druid-mybatis-multi/src/main/java/com/heibaiying/springboot/DruidMybatisMultiApplication.java b/spring-boot/springboot-druid-mybatis-multi/src/main/java/com/heibaiying/springboot/DruidMybatisMultiApplication.java new file mode 100644 index 0000000..078e1d0 --- /dev/null +++ b/spring-boot/springboot-druid-mybatis-multi/src/main/java/com/heibaiying/springboot/DruidMybatisMultiApplication.java @@ -0,0 +1,15 @@ +package com.heibaiying.springboot; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; + +@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class}) +public class DruidMybatisMultiApplication { + + public static void main(String[] args) { + SpringApplication.run(DruidMybatisMultiApplication.class, args); + } + +} + diff --git a/spring-boot/springboot-druid-mybatis-multi/src/main/java/com/heibaiying/springboot/aop/DynamicDataSourceAspect.java b/spring-boot/springboot-druid-mybatis-multi/src/main/java/com/heibaiying/springboot/aop/DynamicDataSourceAspect.java new file mode 100644 index 0000000..a7f9f14 --- /dev/null +++ b/spring-boot/springboot-druid-mybatis-multi/src/main/java/com/heibaiying/springboot/aop/DynamicDataSourceAspect.java @@ -0,0 +1,40 @@ +package com.heibaiying.springboot.aop; + +import com.heibaiying.springboot.config.DataSourceContextHolder; +import com.heibaiying.springboot.constant.Data; +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.annotation.Pointcut; +import org.springframework.stereotype.Component; + +/** + * @author : heibaiying + * @description : 动态方式去切换数据源 + */ +@Aspect +@Component +public class DynamicDataSourceAspect { + + @Pointcut(value = "execution(* com.heibaiying.springboot.dao.*.*(..))") + public void dataSourcePointCut() { + } + + @Before(value = "dataSourcePointCut()") + public void beforeSwitchDS(JoinPoint point) { + + Object[] args = point.getArgs(); + + if (args == null || args.length < 1 || !Data.DATASOURCE2.equals(args[0])) { + DataSourceContextHolder.setDataKey(Data.DATASOURCE1); + } else { + DataSourceContextHolder.setDataKey(Data.DATASOURCE2); + } + } + + @After(value = "dataSourcePointCut()") + public void afterSwitchDS(JoinPoint point) { + DataSourceContextHolder.clearDataKey(); + } +} diff --git a/spring-boot/springboot-druid-mybatis-multi/src/main/java/com/heibaiying/springboot/bean/Programmer.java b/spring-boot/springboot-druid-mybatis-multi/src/main/java/com/heibaiying/springboot/bean/Programmer.java new file mode 100644 index 0000000..f5fb33e --- /dev/null +++ b/spring-boot/springboot-druid-mybatis-multi/src/main/java/com/heibaiying/springboot/bean/Programmer.java @@ -0,0 +1,34 @@ +package com.heibaiying.springboot.bean; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.Date; + +/** + * @author : heibaiying + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class Programmer { + + private int id; + + private String name; + + private int age; + + private float salary; + + private Date birthday; + + public Programmer(String name, int age, float salary, Date birthday) { + this.name = name; + this.age = age; + this.salary = salary; + this.birthday = birthday; + } + +} diff --git a/spring-boot/springboot-druid-mybatis-multi/src/main/java/com/heibaiying/springboot/config/AbstractDataSourceConfig.java b/spring-boot/springboot-druid-mybatis-multi/src/main/java/com/heibaiying/springboot/config/AbstractDataSourceConfig.java new file mode 100644 index 0000000..62f3cb7 --- /dev/null +++ b/spring-boot/springboot-druid-mybatis-multi/src/main/java/com/heibaiying/springboot/config/AbstractDataSourceConfig.java @@ -0,0 +1,47 @@ +package com.heibaiying.springboot.config; + +import com.atomikos.jdbc.AtomikosDataSourceBean; +import org.springframework.core.env.Environment; + +import javax.sql.DataSource; +import java.util.Properties; + +/** + * @author : heibaiying + * @description : + */ +public class AbstractDataSourceConfig { + + public DataSource getDataSource(Environment env, String prefix, String dataSourceName){ + Properties prop = build(env,prefix); + AtomikosDataSourceBean ds = new AtomikosDataSourceBean(); + ds.setXaDataSourceClassName("com.alibaba.druid.pool.xa.DruidXADataSource"); + ds.setUniqueResourceName(dataSourceName); + ds.setXaProperties(prop); + return ds; + } + + public Properties build(Environment env, String prefix) { + Properties prop = new Properties(); + prop.put("url", env.getProperty(prefix + "url")); + prop.put("username", env.getProperty(prefix + "username")); + prop.put("password", env.getProperty(prefix + "password")); + prop.put("driverClassName", env.getProperty(prefix + "driver-class-name", "")); + prop.put("initialSize", env.getProperty(prefix + "initialSize", Integer.class)); + prop.put("maxActive", env.getProperty(prefix + "maxActive", Integer.class)); + prop.put("minIdle", env.getProperty(prefix + "minIdle", Integer.class)); + prop.put("maxWait", env.getProperty(prefix + "maxWait", Integer.class)); + //prop.put("poolPreparedStatements", env.getProperty(prefix + "poolPreparedStatements", Boolean.class)); + //prop.put("maxPoolPreparedStatementPerConnectionSize",env.getProperty(prefix + "maxPoolPreparedStatementPerConnectionSize", Integer.class)); + prop.put("validationQuery", env.getProperty(prefix + "validationQuery")); + //prop.put("validationQueryTimeout", env.getProperty(prefix + "validationQueryTimeout", Integer.class)); + prop.put("testOnBorrow", env.getProperty(prefix + "testOnBorrow", Boolean.class)); + prop.put("testOnReturn", env.getProperty(prefix + "testOnReturn", Boolean.class)); + prop.put("testWhileIdle", env.getProperty(prefix + "testWhileIdle", Boolean.class)); + prop.put("timeBetweenEvictionRunsMillis", env.getProperty(prefix + "timeBetweenEvictionRunsMillis", Integer.class)); + prop.put("minEvictableIdleTimeMillis", env.getProperty(prefix + "minEvictableIdleTimeMillis", Integer.class)); + //prop.put("useGlobalDataSourceStat",env.getProperty(prefix + "useGlobalDataSourceStat", Boolean.class)); + //prop.put("filters", env.getProperty(prefix + "filters")); + return prop; + } +} diff --git a/spring-boot/springboot-druid-mybatis-multi/src/main/java/com/heibaiying/springboot/config/CustomSqlSessionTemplate.java b/spring-boot/springboot-druid-mybatis-multi/src/main/java/com/heibaiying/springboot/config/CustomSqlSessionTemplate.java new file mode 100644 index 0000000..759c552 --- /dev/null +++ b/spring-boot/springboot-druid-mybatis-multi/src/main/java/com/heibaiying/springboot/config/CustomSqlSessionTemplate.java @@ -0,0 +1,739 @@ +package com.heibaiying.springboot.config; + +import lombok.extern.slf4j.Slf4j; +import org.apache.ibatis.exceptions.PersistenceException; +import org.apache.ibatis.executor.BatchResult; +import org.apache.ibatis.session.*; +import org.mybatis.spring.MyBatisExceptionTranslator; +import org.mybatis.spring.SqlSessionTemplate; +import org.springframework.dao.support.PersistenceExceptionTranslator; +import org.springframework.util.Assert; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.sql.Connection; +import java.util.List; +import java.util.Map; + +import static java.lang.reflect.Proxy.newProxyInstance; +import static org.apache.ibatis.reflection.ExceptionUtil.unwrapThrowable; +import static org.mybatis.spring.SqlSessionUtils.*; + +/*** + * @description: 自定义 sqlSessionTemplate 实现 + * 这个方法继承自sqlSessionTemplate,主要是重写了getSqlSessionFactory方法,并在getSqlSession时候传入我们用此方法得到的SqlSessionFactory + */ + +@Slf4j +public class CustomSqlSessionTemplate extends SqlSessionTemplate { +/* + + + private final SqlSessionFactory sqlSessionFactory; + private final ExecutorType executorType; + private final SqlSession sqlSessionProxy; + private final PersistenceExceptionTranslator exceptionTranslator; + + private Map targetSqlSessionFactories; + private SqlSessionFactory defaultTargetSqlSessionFactory; + + + public CustomSqlSessionTemplate(SqlSessionFactory sqlSessionFactory) { + this(sqlSessionFactory, sqlSessionFactory.getConfiguration().getDefaultExecutorType()); + } + + public CustomSqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType) { + this(sqlSessionFactory, executorType, new MyBatisExceptionTranslator(sqlSessionFactory.getConfiguration() + .getEnvironment().getDataSource(), true)); + } + + public CustomSqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType, + PersistenceExceptionTranslator exceptionTranslator) { + + super(sqlSessionFactory, executorType, exceptionTranslator); + + this.sqlSessionFactory = sqlSessionFactory; + this.executorType = executorType; + this.exceptionTranslator = exceptionTranslator; + + this.sqlSessionProxy = (SqlSession) newProxyInstance( + SqlSessionFactory.class.getClassLoader(), + new Class[]{SqlSession.class}, + new SqlSessionInterceptor()); + + this.defaultTargetSqlSessionFactory = sqlSessionFactory; + } + + public void setTargetSqlSessionFactories(Map targetSqlSessionFactories) { + this.targetSqlSessionFactories = targetSqlSessionFactories; + } + + public void setDefaultTargetSqlSessionFactory(SqlSessionFactory defaultTargetSqlSessionFactory) { + this.defaultTargetSqlSessionFactory = defaultTargetSqlSessionFactory; + } + + */ +/*** + * 获取当前使用数据源对应的会话工厂 + *//* + + @Override + public SqlSessionFactory getSqlSessionFactory() { + + String dataSourceKey = DataSourceContextHolder.getDataKey(); + log.info("SqlSessionFactory key : {}",dataSourceKey); + SqlSessionFactory targetSqlSessionFactory = targetSqlSessionFactories.get(dataSourceKey); + if (targetSqlSessionFactory != null) { + return targetSqlSessionFactory; + } else if (defaultTargetSqlSessionFactory != null) { + return defaultTargetSqlSessionFactory; + } else { + Assert.notNull(targetSqlSessionFactories, "Property 'targetSqlSessionFactories' or 'defaultTargetSqlSessionFactory' are required"); + Assert.notNull(defaultTargetSqlSessionFactory, "Property 'defaultTargetSqlSessionFactory' or 'targetSqlSessionFactories' are required"); + } + return this.sqlSessionFactory; + } + + + */ +/** + * 这个方法的实现和父类的实现是基本一致的,唯一不同的就是在getSqlSession方法传参中获取会话工厂的方式 + *//* + + private class SqlSessionInterceptor implements InvocationHandler { + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + //在getSqlSession传参时候,用我们重写的getSqlSessionFactory获取当前数据源对应的会话工厂 + final SqlSession sqlSession = getSqlSession( + CustomSqlSessionTemplate.this.getSqlSessionFactory(), + CustomSqlSessionTemplate.this.executorType, + CustomSqlSessionTemplate.this.exceptionTranslator); + try { + Object result = method.invoke(sqlSession, args); + if (!isSqlSessionTransactional(sqlSession, CustomSqlSessionTemplate.this.getSqlSessionFactory())) { + sqlSession.commit(true); + } + return result; + } catch (Throwable t) { + Throwable unwrapped = unwrapThrowable(t); + if (CustomSqlSessionTemplate.this.exceptionTranslator != null && unwrapped instanceof PersistenceException) { + Throwable translated = CustomSqlSessionTemplate.this.exceptionTranslator + .translateExceptionIfPossible((PersistenceException) unwrapped); + if (translated != null) { + unwrapped = translated; + } + } + throw unwrapped; + } finally { + closeSqlSession(sqlSession, CustomSqlSessionTemplate.this.getSqlSessionFactory()); + } + } + } + + public ExecutorType getExecutorType() { + return this.executorType; + } + + public PersistenceExceptionTranslator getPersistenceExceptionTranslator() { + return this.exceptionTranslator; + } + + */ +/** + * {@inheritDoc} + *//* + + @Override + public T selectOne(String statement) { + return this.sqlSessionProxy. selectOne(statement); + } + + */ +/** + * {@inheritDoc} + *//* + + @Override + public T selectOne(String statement, Object parameter) { + return this.sqlSessionProxy. selectOne(statement, parameter); + } + + */ +/** + * {@inheritDoc} + *//* + + @Override + public Map selectMap(String statement, String mapKey) { + return this.sqlSessionProxy. selectMap(statement, mapKey); + } + + */ +/** + * {@inheritDoc} + *//* + + @Override + public Map selectMap(String statement, Object parameter, String mapKey) { + return this.sqlSessionProxy. selectMap(statement, parameter, mapKey); + } + + */ +/** + * {@inheritDoc} + *//* + + @Override + public Map selectMap(String statement, Object parameter, String mapKey, RowBounds rowBounds) { + return this.sqlSessionProxy. selectMap(statement, parameter, mapKey, rowBounds); + } + + */ +/** + * {@inheritDoc} + *//* + + @Override + public Cursor selectCursor(String statement) { + return this.sqlSessionProxy.selectCursor(statement); + } + + */ +/** + * {@inheritDoc} + *//* + + @Override + public Cursor selectCursor(String statement, Object parameter) { + return this.sqlSessionProxy.selectCursor(statement, parameter); + } + + */ +/** + * {@inheritDoc} + *//* + + @Override + public Cursor selectCursor(String statement, Object parameter, RowBounds rowBounds) { + return this.sqlSessionProxy.selectCursor(statement, parameter, rowBounds); + } + + */ +/** + * {@inheritDoc} + *//* + + @Override + public List selectList(String statement) { + return this.sqlSessionProxy. selectList(statement); + } + + */ +/** + * {@inheritDoc} + *//* + + @Override + public List selectList(String statement, Object parameter) { + return this.sqlSessionProxy. selectList(statement, parameter); + } + + */ +/** + * {@inheritDoc} + *//* + + @Override + public List selectList(String statement, Object parameter, RowBounds rowBounds) { + return this.sqlSessionProxy. selectList(statement, parameter, rowBounds); + } + + */ +/** + * {@inheritDoc} + *//* + + @Override + public void select(String statement, ResultHandler handler) { + this.sqlSessionProxy.select(statement, handler); + } + + */ +/** + * {@inheritDoc} + *//* + + @Override + public void select(String statement, Object parameter, ResultHandler handler) { + this.sqlSessionProxy.select(statement, parameter, handler); + } + + */ +/** + * {@inheritDoc} + *//* + + @Override + public void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) { + this.sqlSessionProxy.select(statement, parameter, rowBounds, handler); + } + + */ +/** + * {@inheritDoc} + *//* + + @Override + public int insert(String statement) { + return this.sqlSessionProxy.insert(statement); + } + + */ +/** + * {@inheritDoc} + *//* + + @Override + public int insert(String statement, Object parameter) { + return this.sqlSessionProxy.insert(statement, parameter); + } + + */ +/** + * {@inheritDoc} + *//* + + @Override + public int update(String statement) { + return this.sqlSessionProxy.update(statement); + } + + */ +/** + * {@inheritDoc} + *//* + + @Override + public int update(String statement, Object parameter) { + return this.sqlSessionProxy.update(statement, parameter); + } + + */ +/** + * {@inheritDoc} + *//* + + @Override + public int delete(String statement) { + return this.sqlSessionProxy.delete(statement); + } + + */ +/** + * {@inheritDoc} + *//* + + @Override + public int delete(String statement, Object parameter) { + return this.sqlSessionProxy.delete(statement, parameter); + } + + */ +/** + * {@inheritDoc} + *//* + + @Override + public T getMapper(Class type) { + return getConfiguration().getMapper(type, this); + } + + */ +/** + * {@inheritDoc} + *//* + + @Override + public void commit() { + throw new UnsupportedOperationException("Manual commit is not allowed over a Spring managed SqlSession"); + } + + */ +/** + * {@inheritDoc} + *//* + + @Override + public void commit(boolean force) { + throw new UnsupportedOperationException("Manual commit is not allowed over a Spring managed SqlSession"); + } + + */ +/** + * {@inheritDoc} + *//* + + @Override + public void rollback() { + throw new UnsupportedOperationException("Manual rollback is not allowed over a Spring managed SqlSession"); + } + + */ +/** + * {@inheritDoc} + *//* + + @Override + public void rollback(boolean force) { + throw new UnsupportedOperationException("Manual rollback is not allowed over a Spring managed SqlSession"); + } + + */ +/** + * {@inheritDoc} + *//* + + @Override + public void close() { + throw new UnsupportedOperationException("Manual close is not allowed over a Spring managed SqlSession"); + } + + */ +/** + * {@inheritDoc} + *//* + + @Override + public void clearCache() { + this.sqlSessionProxy.clearCache(); + } + + */ +/** + * {@inheritDoc} + * + *//* + + @Override + public Configuration getConfiguration() { + return this.sqlSessionFactory.getConfiguration(); + } + + */ +/** + * {@inheritDoc} + *//* + + @Override + public Connection getConnection() { + return this.sqlSessionProxy.getConnection(); + } + + */ +/** + * {@inheritDoc} + * + * @since 1.0.2 + * + *//* + + @Override + public List flushStatements() { + return this.sqlSessionProxy.flushStatements(); + } + + @Override + public void destroy() throws Exception { + //This method forces spring disposer to avoid call of SqlSessionTemplate.close() which gives UnsupportedOperationException + } +*/ +private final SqlSessionFactory sqlSessionFactory; + private final ExecutorType executorType; + private final SqlSession sqlSessionProxy; + private final PersistenceExceptionTranslator exceptionTranslator; + + private Map targetSqlSessionFactorys; + private SqlSessionFactory defaultTargetSqlSessionFactory; + + public void setTargetSqlSessionFactorys(Map targetSqlSessionFactorys) { + this.targetSqlSessionFactorys = targetSqlSessionFactorys; + } + + public void setDefaultTargetSqlSessionFactory(SqlSessionFactory defaultTargetSqlSessionFactory) { + this.defaultTargetSqlSessionFactory = defaultTargetSqlSessionFactory; + } + + public CustomSqlSessionTemplate(SqlSessionFactory sqlSessionFactory) { + this(sqlSessionFactory, sqlSessionFactory.getConfiguration().getDefaultExecutorType()); + } + + public CustomSqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType) { + this(sqlSessionFactory, executorType, new MyBatisExceptionTranslator(sqlSessionFactory.getConfiguration() + .getEnvironment().getDataSource(), true)); + } + + public CustomSqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType, + PersistenceExceptionTranslator exceptionTranslator) { + + super(sqlSessionFactory, executorType, exceptionTranslator); + + this.sqlSessionFactory = sqlSessionFactory; + this.executorType = executorType; + this.exceptionTranslator = exceptionTranslator; + + this.sqlSessionProxy = (SqlSession) newProxyInstance( + SqlSessionFactory.class.getClassLoader(), + new Class[] { SqlSession.class }, + new SqlSessionInterceptor()); + + this.defaultTargetSqlSessionFactory = sqlSessionFactory; + } + + @Override + public SqlSessionFactory getSqlSessionFactory() { + + String dataSourceKey = DataSourceContextHolder.getDataKey(); + System.out.println("当前会话工厂 : "+dataSourceKey); + SqlSessionFactory targetSqlSessionFactory = targetSqlSessionFactorys.get(dataSourceKey); + if (targetSqlSessionFactory != null) { + return targetSqlSessionFactory; + } else if (defaultTargetSqlSessionFactory != null) { + return defaultTargetSqlSessionFactory; + } else { + Assert.notNull(targetSqlSessionFactorys, "Property 'targetSqlSessionFactorys' or 'defaultTargetSqlSessionFactory' are required"); + Assert.notNull(defaultTargetSqlSessionFactory, "Property 'defaultTargetSqlSessionFactory' or 'targetSqlSessionFactorys' are required"); + } + return this.sqlSessionFactory; + } + + @Override + public Configuration getConfiguration() { + return this.getSqlSessionFactory().getConfiguration(); + } + + public ExecutorType getExecutorType() { + return this.executorType; + } + + public PersistenceExceptionTranslator getPersistenceExceptionTranslator() { + return this.exceptionTranslator; + } + + /** + * {@inheritDoc} + */ + public T selectOne(String statement) { + return this.sqlSessionProxy. selectOne(statement); + } + + /** + * {@inheritDoc} + */ + public T selectOne(String statement, Object parameter) { + return this.sqlSessionProxy. selectOne(statement, parameter); + } + + /** + * {@inheritDoc} + */ + public Map selectMap(String statement, String mapKey) { + return this.sqlSessionProxy. selectMap(statement, mapKey); + } + + /** + * {@inheritDoc} + */ + public Map selectMap(String statement, Object parameter, String mapKey) { + return this.sqlSessionProxy. selectMap(statement, parameter, mapKey); + } + + /** + * {@inheritDoc} + */ + public Map selectMap(String statement, Object parameter, String mapKey, RowBounds rowBounds) { + return this.sqlSessionProxy. selectMap(statement, parameter, mapKey, rowBounds); + } + + /** + * {@inheritDoc} + */ + public List selectList(String statement) { + return this.sqlSessionProxy. selectList(statement); + } + + /** + * {@inheritDoc} + */ + public List selectList(String statement, Object parameter) { + return this.sqlSessionProxy. selectList(statement, parameter); + } + + /** + * {@inheritDoc} + */ + public List selectList(String statement, Object parameter, RowBounds rowBounds) { + return this.sqlSessionProxy. selectList(statement, parameter, rowBounds); + } + + /** + * {@inheritDoc} + */ + public void select(String statement, ResultHandler handler) { + this.sqlSessionProxy.select(statement, handler); + } + + /** + * {@inheritDoc} + */ + public void select(String statement, Object parameter, ResultHandler handler) { + this.sqlSessionProxy.select(statement, parameter, handler); + } + + /** + * {@inheritDoc} + */ + public void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) { + this.sqlSessionProxy.select(statement, parameter, rowBounds, handler); + } + + /** + * {@inheritDoc} + */ + public int insert(String statement) { + return this.sqlSessionProxy.insert(statement); + } + + /** + * {@inheritDoc} + */ + public int insert(String statement, Object parameter) { + return this.sqlSessionProxy.insert(statement, parameter); + } + + /** + * {@inheritDoc} + */ + public int update(String statement) { + return this.sqlSessionProxy.update(statement); + } + + /** + * {@inheritDoc} + */ + public int update(String statement, Object parameter) { + return this.sqlSessionProxy.update(statement, parameter); + } + + /** + * {@inheritDoc} + */ + public int delete(String statement) { + return this.sqlSessionProxy.delete(statement); + } + + /** + * {@inheritDoc} + */ + public int delete(String statement, Object parameter) { + return this.sqlSessionProxy.delete(statement, parameter); + } + + /** + * {@inheritDoc} + */ + public T getMapper(Class type) { + return getConfiguration().getMapper(type, this); + } + + /** + * {@inheritDoc} + */ + public void commit() { + throw new UnsupportedOperationException("Manual commit is not allowed over a Spring managed SqlSession"); + } + + /** + * {@inheritDoc} + */ + public void commit(boolean force) { + throw new UnsupportedOperationException("Manual commit is not allowed over a Spring managed SqlSession"); + } + + /** + * {@inheritDoc} + */ + public void rollback() { + throw new UnsupportedOperationException("Manual rollback is not allowed over a Spring managed SqlSession"); + } + + /** + * {@inheritDoc} + */ + public void rollback(boolean force) { + throw new UnsupportedOperationException("Manual rollback is not allowed over a Spring managed SqlSession"); + } + + /** + * {@inheritDoc} + */ + public void close() { + throw new UnsupportedOperationException("Manual close is not allowed over a Spring managed SqlSession"); + } + + /** + * {@inheritDoc} + */ + public void clearCache() { + this.sqlSessionProxy.clearCache(); + } + + /** + * {@inheritDoc} + */ + public Connection getConnection() { + return this.sqlSessionProxy.getConnection(); + } + + /** + * {@inheritDoc} + * @since 1.0.2 + */ + public List flushStatements() { + return this.sqlSessionProxy.flushStatements(); + } + + /** + * Proxy needed to route MyBatis method calls to the proper SqlSession got from Spring's Transaction Manager It also + * unwraps exceptions thrown by {@code Method#invoke(Object, Object...)} to pass a {@code PersistenceException} to + * the {@code PersistenceExceptionTranslator}. + */ + private class SqlSessionInterceptor implements InvocationHandler { + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + final SqlSession sqlSession = getSqlSession( + CustomSqlSessionTemplate.this.getSqlSessionFactory(), + CustomSqlSessionTemplate.this.executorType, + CustomSqlSessionTemplate.this.exceptionTranslator); + try { + Object result = method.invoke(sqlSession, args); + if (!isSqlSessionTransactional(sqlSession, CustomSqlSessionTemplate.this.getSqlSessionFactory())) { + // force commit even on non-dirty sessions because some databases require + // a commit/rollback before calling close() + sqlSession.commit(true); + } + return result; + } catch (Throwable t) { + Throwable unwrapped = unwrapThrowable(t); + if (CustomSqlSessionTemplate.this.exceptionTranslator != null && unwrapped instanceof PersistenceException) { + Throwable translated = CustomSqlSessionTemplate.this.exceptionTranslator + .translateExceptionIfPossible((PersistenceException) unwrapped); + if (translated != null) { + unwrapped = translated; + } + } + throw unwrapped; + } finally { + closeSqlSession(sqlSession, CustomSqlSessionTemplate.this.getSqlSessionFactory()); + } + } + } + +} diff --git a/spring-boot/springboot-druid-mybatis-multi/src/main/java/com/heibaiying/springboot/config/DataSourceConfig.java b/spring-boot/springboot-druid-mybatis-multi/src/main/java/com/heibaiying/springboot/config/DataSourceConfig.java new file mode 100644 index 0000000..d33673e --- /dev/null +++ b/spring-boot/springboot-druid-mybatis-multi/src/main/java/com/heibaiying/springboot/config/DataSourceConfig.java @@ -0,0 +1,145 @@ +package com.heibaiying.springboot.config; + +import com.alibaba.druid.pool.xa.DruidXADataSource; +import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder; +import com.heibaiying.springboot.constant.Data; +import org.apache.ibatis.logging.stdout.StdOutImpl; +import org.apache.ibatis.session.SqlSessionFactory; +import org.mybatis.spring.SqlSessionFactoryBean; +import org.mybatis.spring.annotation.MapperScan; +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.core.env.Environment; +import org.springframework.core.io.support.PathMatchingResourcePatternResolver; + +import javax.sql.DataSource; +import java.util.HashMap; +import java.util.Map; + +/** + * @author : heibaiying + * @description : 多数据源配置 + * 需要特别强调的是以下任意的DataSource的bean都不要用@Primary去修饰,包括动态数据源。原因是在事务下,spring在DataSourceUtils类中doGetConnection方法中判断获取当前数据源是否持有连接的时候, + * 总是会传入用@Primary修饰的数据源,如果一个事务下有多个数据源,这种情况下就会出现connection复用,无法切换数据源, 源码截图详见README.md + */ +@Configuration +@MapperScan(basePackages = DataSourceConfig.BASE_PACKAGES, sqlSessionTemplateRef = "sqlSessionTemplate") +public class DataSourceConfig extends AbstractDataSourceConfig { + + static final String BASE_PACKAGES = "com.heibaiying.springboot.dao"; + + private static final String MAPPER_LOCATION = "classpath:mappers/*.xml"; + + /** + * 创建数据源1,不要用@Primary去修饰 + */ + @Bean + public DataSource dataSourceOne(Environment env) { + String prefix = "spring.datasource.druid.db1."; + return getDataSource(env, prefix, "one"); + } + + /** + * 创建数据源2,不要用@Primary去修饰 + */ + @Bean + public DataSource dataSourceTwo(Environment env) { + String prefix = "spring.datasource.druid.db2."; + return getDataSource(env, prefix, "two"); + } + + + /* @Bean + @ConfigurationProperties("spring.datasource.druid.db1") + public DataSource dataSourceOne() { + return new DruidXADataSource(); + } + + @Bean + @ConfigurationProperties("spring.datasource.druid.db2") + public DataSource dataSourceTwo() { + return new DruidXADataSource(); + }*/ + + /** + * 设置多数据源,不要用@Primary去修饰 + */ + @Bean + public DataSource dynamicDataSource(DataSource dataSourceOne, DataSource dataSourceTwo) { + DynamicDataSource dynamicDataSource = new DynamicDataSource(); + // 设置默认数据源 + dynamicDataSource.setDefaultTargetDataSource(dataSourceOne); + // 设置多数据源 + Map dsMap = new HashMap<>(); + dsMap.put(Data.DATASOURCE1, dataSourceOne); + dsMap.put(Data.DATASOURCE2, dataSourceTwo); + + dynamicDataSource.setTargetDataSources(dsMap); + return dynamicDataSource; + } + + + /** + * @param dataSourceOne 数据源1 + * @return 数据源1的会话工厂 + */ + @Bean + public SqlSessionFactory sqlSessionFactoryOne(DataSource dataSourceOne) + throws Exception { + return createSqlSessionFactory(dataSourceOne); + } + + + /** + * @param dataSourceTwo 数据源2 + * @return 数据源2的会话工厂 + */ + @Bean + public SqlSessionFactory sqlSessionFactoryTwo(DataSource dataSourceTwo) + throws Exception { + return createSqlSessionFactory(dataSourceTwo); + } + + + /*** + * sqlSessionTemplate与Spring事务管理一起使用,以确保使用的实际SqlSession是与当前Spring事务关联的, + * 此外它还管理会话生命周期,包括根据Spring事务配置根据需要关闭,提交或回滚会话 + * @param sqlSessionFactoryOne 数据源1 + * @param sqlSessionFactoryTwo 数据源2 + */ + @Bean + public CustomSqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactoryOne, + SqlSessionFactory sqlSessionFactoryTwo) { + Map sqlSessionFactoryMap = new HashMap<>(); + sqlSessionFactoryMap.put(Data.DATASOURCE1, sqlSessionFactoryOne); + sqlSessionFactoryMap.put(Data.DATASOURCE2, sqlSessionFactoryTwo); + + CustomSqlSessionTemplate customSqlSessionTemplate = new CustomSqlSessionTemplate(sqlSessionFactoryOne); + customSqlSessionTemplate.setTargetSqlSessionFactorys(sqlSessionFactoryMap); + return customSqlSessionTemplate; + } + + /*** + * 自定义会话工厂 + * @param dataSource 数据源 + * @return :自定义的会话工厂 + */ + private SqlSessionFactory createSqlSessionFactory(DataSource dataSource) throws Exception { + SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean(); + factoryBean.setDataSource(dataSource); + factoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(MAPPER_LOCATION)); + // 其他可配置项(包括是否打印sql,是否开启驼峰命名等) + org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration(); + configuration.setMapUnderscoreToCamelCase(true); + configuration.setLogImpl(StdOutImpl.class); + factoryBean.setConfiguration(configuration); + /* * + * 采用个如下方式配置属性的时候一定要保证已经进行数据源的配置(setDataSource)和数据源和MapperLocation配置(setMapperLocations) + * factoryBean.getObject().getConfiguration().setMapUnderscoreToCamelCase(true); + * factoryBean.getObject().getConfiguration().setLogImpl(StdOutImpl.class); + **/ + return factoryBean.getObject(); + } +} diff --git a/spring-boot/springboot-druid-mybatis-multi/src/main/java/com/heibaiying/springboot/config/DataSourceContextHolder.java b/spring-boot/springboot-druid-mybatis-multi/src/main/java/com/heibaiying/springboot/config/DataSourceContextHolder.java new file mode 100644 index 0000000..fcc4d01 --- /dev/null +++ b/spring-boot/springboot-druid-mybatis-multi/src/main/java/com/heibaiying/springboot/config/DataSourceContextHolder.java @@ -0,0 +1,25 @@ +package com.heibaiying.springboot.config; + +/** + * @author : heibaiying + * @description : 保证数据源切换的线程隔离 + */ +public class DataSourceContextHolder { + + private static final ThreadLocal contextHolder = new ThreadLocal<>(); + + // 设置数据源名 + public static void setDataKey(String dbName) { + contextHolder.set(dbName); + } + + // 获取数据源名 + public static String getDataKey() { + return (contextHolder.get()); + } + + // 清除数据源名 + public static void clearDataKey() { + contextHolder.remove(); + } +} diff --git a/spring-boot/springboot-druid-mybatis-multi/src/main/java/com/heibaiying/springboot/config/DynamicDataSource.java b/spring-boot/springboot-druid-mybatis-multi/src/main/java/com/heibaiying/springboot/config/DynamicDataSource.java new file mode 100644 index 0000000..185ca0a --- /dev/null +++ b/spring-boot/springboot-druid-mybatis-multi/src/main/java/com/heibaiying/springboot/config/DynamicDataSource.java @@ -0,0 +1,16 @@ +package com.heibaiying.springboot.config; + +import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; + +/** + * @author : heibaiying + * @description : 动态数据源配置 + */ + +public class DynamicDataSource extends AbstractRoutingDataSource { + @Override + protected Object determineCurrentLookupKey() { + System.out.println("当前数据库:"+DataSourceContextHolder.getDataKey()); + return DataSourceContextHolder.getDataKey(); + } +} diff --git a/spring-boot/springboot-druid-mybatis-multi/src/main/java/com/heibaiying/springboot/config/XATransactionManagerConfig.java b/spring-boot/springboot-druid-mybatis-multi/src/main/java/com/heibaiying/springboot/config/XATransactionManagerConfig.java new file mode 100644 index 0000000..180cd4a --- /dev/null +++ b/spring-boot/springboot-druid-mybatis-multi/src/main/java/com/heibaiying/springboot/config/XATransactionManagerConfig.java @@ -0,0 +1,42 @@ +package com.heibaiying.springboot.config; + +import com.atomikos.icatch.jta.UserTransactionImp; +import com.atomikos.icatch.jta.UserTransactionManager; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.annotation.EnableTransactionManagement; +import org.springframework.transaction.jta.JtaTransactionManager; + +import javax.transaction.TransactionManager; +import javax.transaction.UserTransaction; + +/** + * @author : heibaiying + * @description : 分布式事务配置 + */ +@Configuration +@EnableTransactionManagement +public class XATransactionManagerConfig { + + @Bean + public UserTransaction userTransaction() throws Throwable { + UserTransactionImp userTransactionImp = new UserTransactionImp(); + userTransactionImp.setTransactionTimeout(10000); + return userTransactionImp; + } + + @Bean(initMethod = "init", destroyMethod = "close") + public TransactionManager atomikosTransactionManager() { + UserTransactionManager userTransactionManager = new UserTransactionManager(); + userTransactionManager.setForceShutdown(false); + return userTransactionManager; + } + + @Bean + public PlatformTransactionManager transactionManager(UserTransaction userTransaction, + TransactionManager transactionManager) { + return new JtaTransactionManager(userTransaction, transactionManager); + } +} + diff --git a/spring-boot/springboot-druid-mybatis-multi/src/main/java/com/heibaiying/springboot/constant/Data.java b/spring-boot/springboot-druid-mybatis-multi/src/main/java/com/heibaiying/springboot/constant/Data.java new file mode 100644 index 0000000..5a714ec --- /dev/null +++ b/spring-boot/springboot-druid-mybatis-multi/src/main/java/com/heibaiying/springboot/constant/Data.java @@ -0,0 +1,11 @@ +package com.heibaiying.springboot.constant; + +/** + * @author : heibaiying + * @description : + */ +public class Data { + + public static final String DATASOURCE1="DATASOURCE1"; + public static final String DATASOURCE2="DATASOURCE2"; +} diff --git a/spring-boot/springboot-druid-mybatis-multi/src/main/java/com/heibaiying/springboot/controller/TestController.java b/spring-boot/springboot-druid-mybatis-multi/src/main/java/com/heibaiying/springboot/controller/TestController.java new file mode 100644 index 0000000..558995f --- /dev/null +++ b/spring-boot/springboot-druid-mybatis-multi/src/main/java/com/heibaiying/springboot/controller/TestController.java @@ -0,0 +1,61 @@ +package com.heibaiying.springboot.controller; + +import com.heibaiying.springboot.bean.Programmer; +import com.heibaiying.springboot.constant.Data; +import com.heibaiying.springboot.dao.ProgrammerMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +/** + * @author : heibaiying + * @description : 测试controller + */ + +@RestController +public class TestController { + + + @Autowired + private ProgrammerMapper programmerDao; + + /** + * 查询全部数据源的数据 + */ + @GetMapping("/db/programmers") + public List getAllProgrammers() { + List programmers = programmerDao.selectAll(Data.DATASOURCE1); + programmers.addAll(programmerDao.selectAll(Data.DATASOURCE2)); + return programmers; + } + + @GetMapping("ts/db/programmers") + @Transactional + public List getAllProgrammersTs() { + List programmers = programmerDao.selectAll(Data.DATASOURCE1); + programmers.addAll(programmerDao.selectAll(Data.DATASOURCE2)); + return programmers; + } + + /** + * 不指定就使用默认的数据源 + */ + @GetMapping("/db1/programmers") + public List getDB1Programmers() { + + return programmerDao.selectAll(null); + } + + /** + * 从指定数据源查询 + */ + @GetMapping("/db2/programmers") + public List getDB2Programmers() { + return programmerDao.selectAll(Data.DATASOURCE2); + } + + +} diff --git a/spring-boot/springboot-druid-mybatis-multi/src/main/java/com/heibaiying/springboot/controller/TransactionController.java b/spring-boot/springboot-druid-mybatis-multi/src/main/java/com/heibaiying/springboot/controller/TransactionController.java new file mode 100644 index 0000000..9c09fab --- /dev/null +++ b/spring-boot/springboot-druid-mybatis-multi/src/main/java/com/heibaiying/springboot/controller/TransactionController.java @@ -0,0 +1,40 @@ +package com.heibaiying.springboot.controller; + +import com.heibaiying.springboot.bean.Programmer; +import com.heibaiying.springboot.constant.Data; +import com.heibaiying.springboot.dao.ProgrammerMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.Date; + +/** + * @author : heibaiying + * @description : 测试单数据库事务 + */ +@RestController +public class TransactionController { + + @Autowired + private ProgrammerMapper programmerDao; + + + @RequestMapping("db1/change") + @Transactional + public void changeDb1() { + Programmer programmer = new Programmer(1, "xiaolandb1", 99, 6662.32f, new Date()); + programmerDao.modify(Data.DATASOURCE1, programmer); + } + + @RequestMapping("ts/db1/change") + @Transactional + public void changeTsDb1() { + Programmer programmer = new Programmer(1, "xiaolandb1", 88, 6662.32f, new Date()); + programmerDao.modify(Data.DATASOURCE1, programmer); + // 抛出异常 查看回滚 + int j = 1 / 0; + } + +} diff --git a/spring-boot/springboot-druid-mybatis-multi/src/main/java/com/heibaiying/springboot/controller/XATransactionController.java b/spring-boot/springboot-druid-mybatis-multi/src/main/java/com/heibaiying/springboot/controller/XATransactionController.java new file mode 100644 index 0000000..997a106 --- /dev/null +++ b/spring-boot/springboot-druid-mybatis-multi/src/main/java/com/heibaiying/springboot/controller/XATransactionController.java @@ -0,0 +1,44 @@ +package com.heibaiying.springboot.controller; + +import com.heibaiying.springboot.bean.Programmer; +import com.heibaiying.springboot.constant.Data; +import com.heibaiying.springboot.dao.ProgrammerMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.Date; + +/** + * @author : heibaiying + * @description : 测试分布式事务 + */ +@RestController +public class XATransactionController { + + @Autowired + private ProgrammerMapper programmerDao; + + + @RequestMapping("/db/change") + @Transactional + public void changeDb() { + Programmer programmer01 = new Programmer(1, "xiaolandb1", 100, 6662.32f, new Date()); + Programmer programmer02 = new Programmer(1, "xiaohongdb2", 100, 6662.32f, new Date()); + programmerDao.modify(Data.DATASOURCE1, programmer01); + programmerDao.modify(Data.DATASOURCE2, programmer02); + } + + @RequestMapping("ts/db/change") + @Transactional + public void changeTsDb() { + Programmer programmer01 = new Programmer(1, "xiaolandb1", 99, 6662.32f, new Date()); + Programmer programmer02 = new Programmer(1, "xiaohongdb2", 99, 6662.32f, new Date()); + programmerDao.modify(Data.DATASOURCE1, programmer01); + programmerDao.modify(Data.DATASOURCE2, programmer02); + int i = 1 / 0; + } + + +} diff --git a/spring-boot/springboot-druid-mybatis-multi/src/main/java/com/heibaiying/springboot/dao/ProgrammerMapper.java b/spring-boot/springboot-druid-mybatis-multi/src/main/java/com/heibaiying/springboot/dao/ProgrammerMapper.java new file mode 100644 index 0000000..79a97ba --- /dev/null +++ b/spring-boot/springboot-druid-mybatis-multi/src/main/java/com/heibaiying/springboot/dao/ProgrammerMapper.java @@ -0,0 +1,24 @@ +package com.heibaiying.springboot.dao; + +import com.heibaiying.springboot.bean.Programmer; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * @author : heibaiying + */ +@Mapper +public interface ProgrammerMapper { + + List selectAll(String dataSource); + + void save(Programmer programmer); + + Programmer selectById(int id); + + int modify(String dataSource,@Param("pro") Programmer programmer); + + void delete(int id); +} diff --git a/spring-boot/springboot-druid-mybatis-multi/src/main/resources/application.yml b/spring-boot/springboot-druid-mybatis-multi/src/main/resources/application.yml new file mode 100644 index 0000000..cd311b8 --- /dev/null +++ b/spring-boot/springboot-druid-mybatis-multi/src/main/resources/application.yml @@ -0,0 +1,113 @@ +spring: + datasource: + druid: + db1: + url: jdbc:mysql://127.0.0.1:3306/mysql?characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&useSSL=false + username: root + password: root + driver-class-name: com.mysql.cj.jdbc.Driver + # 使用 druid 作为连接池 + type: com.alibaba.druid.pool.DruidDataSource + + # 初始化时建立物理连接的个数。初始化发生在显示调用init方法,或者第一次getConnection时 + initialSize: 5 + # 最小连接池数量 + minIdle: 5 + # 最大连接池数量 + maxActive: 10 + # 获取连接时最大等待时间,单位毫秒。配置了maxWait之后,缺省启用公平锁,并发效率会有所下降,如果需要可以通过配置useUnfairLock属性为true使用非公平锁。 + maxWait: 60000 + # Destroy线程会检测连接的间隔时间,如果连接空闲时间大于等于minEvictableIdleTimeMillis则关闭物理连接。 + timeBetweenEvictionRunsMillis: 60000 + # 连接保持空闲而不被驱逐的最小时间 + minEvictableIdleTimeMillis: 300000 + # 用来检测连接是否有效的sql 因数据库方言而异, 例如 oracle 应该写成 SELECT 1 FROM DUAL + validationQuery: SELECT 9 + # 建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。 + testWhileIdle: true + # 申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。 + testOnBorrow: false + # 归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。 + testOnReturn: false + # 是否自动回收超时连接 + removeAbandoned: true + # 超时时间(以秒数为单位) + remove-abandoned-timeout: 180 + # WebStatFilter用于采集web-jdbc关联监控的数据。 + web-stat-filter: + # 是否开启 WebStatFilter 默认是true + enabled: true + # 需要拦截的url + url-pattern: /* + # 排除静态资源的请求 + exclusions: "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*" + + # Druid内置提供了一个StatViewServlet用于展示Druid的统计信息。 + stat-view-servlet: + #是否启用StatViewServlet 默认值true + enabled: true + # 需要拦截的url + url-pattern: /druid/* + # 允许清空统计数据 + reset-enable: true + login-username: druid + login-password: druid + db2: + url: jdbc:mysql://127.0.0.1:3306/mysql02?characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&useSSL=false + username: root + password: root + driver-class-name: com.mysql.cj.jdbc.Driver + # 使用 druid 作为连接池 + type: com.alibaba.druid.pool.DruidDataSource + + # 初始化时建立物理连接的个数。初始化发生在显示调用init方法,或者第一次getConnection时 + initialSize: 5 + # 最小连接池数量 + minIdle: 5 + # 最大连接池数量 + maxActive: 10 + # 获取连接时最大等待时间,单位毫秒。配置了maxWait之后,缺省启用公平锁,并发效率会有所下降,如果需要可以通过配置useUnfairLock属性为true使用非公平锁。 + maxWait: 60000 + # Destroy线程会检测连接的间隔时间,如果连接空闲时间大于等于minEvictableIdleTimeMillis则关闭物理连接。 + timeBetweenEvictionRunsMillis: 60000 + # 连接保持空闲而不被驱逐的最小时间 + minEvictableIdleTimeMillis: 300000 + # 用来检测连接是否有效的sql 因数据库方言而异, 例如 oracle 应该写成 SELECT 1 FROM DUAL + validationQuery: SELECT 9 + # 建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。 + testWhileIdle: true + # 申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。 + testOnBorrow: false + # 归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。 + testOnReturn: false + # 是否自动回收超时连接 + removeAbandoned: true + # 超时时间(以秒数为单位) + remove-abandoned-timeout: 180 + # WebStatFilter用于采集web-jdbc关联监控的数据。 + web-stat-filter: + # 是否开启 WebStatFilter 默认是true + enabled: true + # 需要拦截的url + url-pattern: /* + # 排除静态资源的请求 + exclusions: "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*" + + # Druid内置提供了一个StatViewServlet用于展示Druid的统计信息。 + stat-view-servlet: + #是否启用StatViewServlet 默认值true + enabled: true + # 需要拦截的url + url-pattern: /druid/* + # 允许清空统计数据 + reset-enable: true + login-username: druid + login-password: druid +# mybatis 相关配置 +mybatis: + configuration: + # 当没有为参数提供特定的 JDBC 类型时,为空值指定 JDBC 类型。 + # oracle数据库建议配置为JdbcType.NULL, 默认是Other + jdbc-type-for-null: 'null' + # 是否打印sql语句 调试的时候可以开启 + log-impl: org.apache.ibatis.logging.stdout.StdOutImpl \ No newline at end of file diff --git a/spring-boot/springboot-druid-mybatis-multi/src/main/resources/mappers/ProgrammerMapper.xml b/spring-boot/springboot-druid-mybatis-multi/src/main/resources/mappers/ProgrammerMapper.xml new file mode 100644 index 0000000..e14af21 --- /dev/null +++ b/spring-boot/springboot-druid-mybatis-multi/src/main/resources/mappers/ProgrammerMapper.xml @@ -0,0 +1,27 @@ + + + + + + + + + insert into programmer (name, age, salary, birthday) VALUES (#{name}, #{age}, #{salary}, #{birthday}) + + + + + + update programmer set name=#{pro.name},age=#{pro.age},salary=#{pro.salary},birthday=#{pro.birthday} where id=#{pro.id} + + + + delete from programmer where id = #{id} + + + \ No newline at end of file diff --git a/spring-boot/springboot-druid-mybatis-multi/src/test/java/com/heibaiying/springboot/SpringbootDruidMybatisMultiApplicationTests.java b/spring-boot/springboot-druid-mybatis-multi/src/test/java/com/heibaiying/springboot/SpringbootDruidMybatisMultiApplicationTests.java new file mode 100644 index 0000000..6571538 --- /dev/null +++ b/spring-boot/springboot-druid-mybatis-multi/src/test/java/com/heibaiying/springboot/SpringbootDruidMybatisMultiApplicationTests.java @@ -0,0 +1,17 @@ +package com.heibaiying.springboot; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +@RunWith(SpringRunner.class) +@SpringBootTest +public class SpringbootDruidMybatisMultiApplicationTests { + + @Test + public void contextLoads() { + } + +} + diff --git a/spring-boot/springboot-druid-mybatis-multi/tmlog.lck b/spring-boot/springboot-druid-mybatis-multi/tmlog.lck new file mode 100644 index 0000000..e69de29 diff --git a/spring-boot/springboot-druid-mybatis-multi/tmlog101.log b/spring-boot/springboot-druid-mybatis-multi/tmlog101.log new file mode 100644 index 0000000..f48e578 --- /dev/null +++ b/spring-boot/springboot-druid-mybatis-multi/tmlog101.log @@ -0,0 +1,9 @@ +{"id":"10.0.75.1.tm154840078074100001","wasCommitted":true,"participants":[{"uri":"10.0.75.1.tm1","state":"COMMITTING","expires":1548400791454,"resourceName":"one"},{"uri":"10.0.75.1.tm2","state":"COMMITTING","expires":1548400791454,"resourceName":"two"}]} +{"id":"10.0.75.1.tm154840078074100001","wasCommitted":true,"participants":[{"uri":"10.0.75.1.tm1","state":"TERMINATED","expires":1548400791469,"resourceName":"one"},{"uri":"10.0.75.1.tm2","state":"TERMINATED","expires":1548400791469,"resourceName":"two"}]} +{"id":"10.0.75.1.tm154840078467900002","wasCommitted":true,"participants":[{"uri":"10.0.75.1.tm3","state":"COMMITTING","expires":1548400794622,"resourceName":"one"},{"uri":"10.0.75.1.tm4","state":"COMMITTING","expires":1548400794622,"resourceName":"two"}]} +{"id":"10.0.75.1.tm154840078467900002","wasCommitted":true,"participants":[{"uri":"10.0.75.1.tm3","state":"TERMINATED","expires":1548400794642,"resourceName":"one"},{"uri":"10.0.75.1.tm4","state":"TERMINATED","expires":1548400794642,"resourceName":"two"}]} +{"id":"10.0.75.1.tm154840078978400003","wasCommitted":false,"participants":[{"uri":"10.0.75.1.tm5","state":"TERMINATED","expires":1548400799772,"resourceName":"one"},{"uri":"10.0.75.1.tm6","state":"TERMINATED","expires":1548400799772,"resourceName":"two"}]} +{"id":"10.0.75.1.tm154840079364000004","wasCommitted":true,"participants":[{"uri":"10.0.75.1.tm7","state":"COMMITTING","expires":1548400803592,"resourceName":"one"},{"uri":"10.0.75.1.tm8","state":"COMMITTING","expires":1548400803592,"resourceName":"two"}]} +{"id":"10.0.75.1.tm154840079364000004","wasCommitted":true,"participants":[{"uri":"10.0.75.1.tm7","state":"TERMINATED","expires":1548400803609,"resourceName":"one"},{"uri":"10.0.75.1.tm8","state":"TERMINATED","expires":1548400803609,"resourceName":"two"}]} +{"id":"10.0.75.1.tm154840079686400005","wasCommitted":true,"participants":[{"uri":"10.0.75.1.tm9","state":"COMMITTING","expires":1548400806814,"resourceName":"one"},{"uri":"10.0.75.1.tm10","state":"COMMITTING","expires":1548400806814,"resourceName":"two"}]} +{"id":"10.0.75.1.tm154840079686400005","wasCommitted":true,"participants":[{"uri":"10.0.75.1.tm9","state":"TERMINATED","expires":1548400806831,"resourceName":"one"},{"uri":"10.0.75.1.tm10","state":"TERMINATED","expires":1548400806831,"resourceName":"two"}]}