如何解决多数据源分包分布式事务
多数据源项目中如何解决分布式事务问题
分布式领域中的如何解决分布式事务问题
TCC分布式事务
基于MQ解决分布式事务
多数据源怎么解决分布式事务?
org.springframework.boot
spring-boot-starter-parent
2.0.0.RELEASE
org.springframework.boot
spring-boot-starter
org.springframework.boot
spring-boot-starter-test
test
org.mybatis.spring.boot
mybatis-spring-boot-starter
1.1.1
mysql
mysql-connector-java
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-jta-atomikos
org.projectlombok
lombok
1.16.20
###springboot2.0名称url在多数据源的情况下变成jdbc-url,否则出现debug
###准备两个数据库连接:mumber/order
spring:
datasource:
##会员数据库连接
member:
url: jdbc:mysql://localhost:3306/user
username: root
password: 123123
borrowConnectionTimeout: 30
loginTimeout: 30
maintenanceInterval: 60
maxIdleTime: 60
minPoolSize: 3
maxPoolSize: 25
maxLifetime: 20000
uniqueResourceName: memberDatasource
##订单数据库连接
order:
url: jdbc:mysql://localhost:3306/order
username: root
password: 123123
borrowConnectionTimeout: 30
loginTimeout: 30
maintenanceInterval: 60
maxIdleTime: 60
minPoolSize: 3
maxPoolSize: 25
maxLifetime: 20000
uniqueResourceName: orderDatasource
package com.xyt.springboot.config.member;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
@Data
@ConfigurationProperties(prefix = "spring.datasource.member")
public class MemberConfig {
private String url;
private String username;
private String password;
private int minPoolSize;
private int maxPoolSize;
private int maxLifetime;
private int borrowConnectionTimeout;
private int loginTimeout;
private int maintenanceInterval;
private int maxIdleTime;
private String testQuery;
private String uniqueResourceName;
}
package com.xyt.springboot.config.order;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
@Data
@ConfigurationProperties(prefix = "spring.datasource.order")//记得在启动项目的时候开启@EnableConfigurationProperties({MemberConfig.class, OrderConfig.class})
public class OrderConfig {
private String url;
private String username;
private String password;
private int minPoolSize;
private int maxPoolSize;
private int maxLifetime;
private int borrowConnectionTimeout;
private int loginTimeout;
private int maintenanceInterval;
private int maxIdleTime;
private String testQuery;
private String uniqueResourceName;
}
package com.xyt.springboot.config.member;
import com.mysql.jdbc.jdbc2.optional.MysqlXADataSource;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.jta.atomikos.AtomikosDataSourceBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import javax.sql.DataSource;
import java.sql.SQLException;
@Configuration
@MapperScan(basePackages = "com.xyt.springboot.member.mapper", sqlSessionFactoryRef = "memberSqlSessionFactory")
public class MemberDatasourceConfig {
/**
* 创建我们的datasource
*
* @return
*/
@Bean("memberDataSource")//spring容器注入
public DataSource memberDataSource(MemberConfig memberConfig) {
//1.创建xaDatasource
MysqlXADataSource mysqlXaDataSource = new MysqlXADataSource();
mysqlXaDataSource.setUrl(memberConfig.getUrl());
mysqlXaDataSource.setPinGlobalTxToPhysicalConnection(true);
mysqlXaDataSource.setPassword(memberConfig.getPassword());
mysqlXaDataSource.setUser(memberConfig.getUsername());
mysqlXaDataSource.setPinGlobalTxToPhysicalConnection(true);
//注册到全局事务上
AtomikosDataSourceBean xaDataSource = new AtomikosDataSourceBean();
xaDataSource.setXaDataSource(mysqlXaDataSource);
xaDataSource.setUniqueResourceName(memberConfig.getUniqueResourceName());
xaDataSource.setMinPoolSize(memberConfig.getMinPoolSize());
xaDataSource.setMaxPoolSize(memberConfig.getMaxPoolSize());
xaDataSource.setMaxLifetime(memberConfig.getMaxLifetime());
xaDataSource.setBorrowConnectionTimeout(memberConfig.getBorrowConnectionTimeout());
try {
xaDataSource.setLoginTimeout(memberConfig.getLoginTimeout());
} catch (SQLException e) {
e.printStackTrace();
}
xaDataSource.setMaintenanceInterval(memberConfig.getMaintenanceInterval());
xaDataSource.setMaxIdleTime(memberConfig.getMaxIdleTime());
xaDataSource.setTestQuery(memberConfig.getTestQuery());
return xaDataSource;
}
@Bean(name = "memberSqlSessionFactory")
public SqlSessionFactory memberSqlSessionFactory(@Qualifier("memberDataSource") DataSource dataSource)
throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource);//注入Datasource
// bean.setMapperLocations(
// new
// PathMatchingResourcePatternResolver().getResources("classpath:mybatis/mapper/test2/*.xml"));
return bean.getObject();
}
// /**
// * 事务管理
// *
// * @param dataSource * @return
// */
// @Primary
// @Bean(name = "memberTransactionManager")
// public DataSourceTransactionManager memberTransactionManager(@Qualifier("memberDataSource") DataSource dataSource) {
// return new DataSourceTransactionManager(dataSource);
// }
@Bean(name = "memberSqlSessionTemplate")
public SqlSessionTemplate memberSqlSessionTemplate(
@Qualifier("memberSqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
return new SqlSessionTemplate(sqlSessionFactory);
}
}
package com.xyt.springboot.config.order;
import com.mysql.jdbc.jdbc2.optional.MysqlXADataSource;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.boot.jta.atomikos.AtomikosDataSourceBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import javax.sql.DataSource;
import java.sql.SQLException;
@Configuration//@Configuration等同于OrderDatasourceConfig.xml
@MapperScan(basePackages = "com.xyt.springboot.order.mapper", sqlSessionFactoryRef = "orderSqlSessionFactory")//com.xyt.springboot.order.mapper是mapper路径
public class OrderDatasourceConfig {
/**
* 创建我们的datasource
*
* @return
*/
@Bean("orderDataSource")//spring容器注入
public DataSource orderDataSource(OrderConfig orderConfig) {
//1.创建xaDatasource
MysqlXADataSource mysqlXaDataSource = new MysqlXADataSource();
mysqlXaDataSource.setUrl(orderConfig.getUrl());
mysqlXaDataSource.setPinGlobalTxToPhysicalConnection(true);
mysqlXaDataSource.setPassword(orderConfig.getPassword());
mysqlXaDataSource.setUser(orderConfig.getUsername());
mysqlXaDataSource.setPinGlobalTxToPhysicalConnection(true);
//注册到全局事务上
AtomikosDataSourceBean xaDataSource = new AtomikosDataSourceBean();
xaDataSource.setXaDataSource(mysqlXaDataSource);
xaDataSource.setUniqueResourceName(orderConfig.getUniqueResourceName());
xaDataSource.setMinPoolSize(orderConfig.getMinPoolSize());
xaDataSource.setMaxPoolSize(orderConfig.getMaxPoolSize());
xaDataSource.setMaxLifetime(orderConfig.getMaxLifetime());
xaDataSource.setBorrowConnectionTimeout(orderConfig.getBorrowConnectionTimeout());
try {
xaDataSource.setLoginTimeout(orderConfig.getLoginTimeout());
} catch (SQLException e) {
e.printStackTrace();
}
xaDataSource.setMaintenanceInterval(orderConfig.getMaintenanceInterval());
xaDataSource.setMaxIdleTime(orderConfig.getMaxIdleTime());
xaDataSource.setTestQuery(orderConfig.getTestQuery());
return xaDataSource;
}
@Bean(name = "orderSqlSessionFactory")
public SqlSessionFactory orderSqlSessionFactory(@Qualifier("orderDataSource") DataSource dataSource)
throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource);
// bean.setMapperLocations(
// new
// PathMatchingResourcePatternResolver().getResources("classpath:mybatis/mapper/test2/*.xml"));
return bean.getObject();
}
// /**
// * 事务管理
// *
// * @param dataSource
// * @return
// */
// @Bean(name = "orderTransactionManager")
// public DataSourceTransactionManager orderTransactionManager(@Qualifier("orderDataSource") DataSource dataSource) {
// return new DataSourceTransactionManager(dataSource);
// }
@Bean(name = "orderSqlSessionTemplate")
public SqlSessionTemplate orderSqlSessionTemplate(
@Qualifier("orderSqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
return new SqlSessionTemplate(sqlSessionFactory);
}
}
服务层代码Service
package com.xyt.springboot.service;
import com.xyt.springboot.member.mapper.UserMapper;
import com.xyt.springboot.order.mapper.OrderMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
@Autowired
private OrderMapper orderMapper;
/**
* 调用User数据库
*
* @param name
* @param age
* @return
* @Transactional事务底层采用Aop技术 增强
*/
@Transactional//开启事务
public int addUser(String name, int age) {
//操作会员数据库
int i = userMapper.addUser(name, age);
//操作订单数据库
int b = orderMapper.addOrder(name);
int j = 1 / age;
return i;
}
/**
* 调用Order数据库
*
* @param order_no
* @return
*/
public int addOrder(String order_no) {
return orderMapper.addOrder(order_no);
}
}
package com.xyt.springboot.member.mapper;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
public interface UserMapper {
@Insert("insert into users values(null,#{name},#{age});")
public int addUser(@Param("name") String name, @Param("age") Integer age);
}
package com.xyt.springboot.order.mapper;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
public interface OrderMapper {
@Insert("insert into orders values(null,#{order_no});")
public int addOrder(@Param("order_no") String order_no);
}
package com.xyt.springboot;
import com.xyt.springboot.config.member.MemberConfig;
import com.xyt.springboot.config.member.MemberDatasourceConfig;
import com.xyt.springboot.config.order.OrderConfig;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
@SpringBootApplication
@MapperScan("com.xyt.springboot.mapper")
@EnableConfigurationProperties({MemberConfig.class, OrderConfig.class})//开启让@ConfigurationProperties生效
public class AppSpringBootMybatis {
public static void main(String[] args) {
SpringApplication.run(AppSpringBootMybatis.class, args);
}
}