项目application.yml配置
seata:
enabled: true
application-id: tmccloud-server-biz #应用名称,一般配置为与 ${spring.application.name}相同即可
enable-auto-data-source-proxy: false #使用了baomidou多数据源则配置为false,单数据源则配置为true
tx-service-group: default_tx_group
service:
vgroup-mapping:
default_tx_group: default
registry:
type: nacos #注册中心 nacos
nacos:
application: seata-server
server-addr: localhost:8848
namespace: seata
group: DEFAULT_GROUP
username: nacos
password: nacos
config:
type: nacos # 配置中心 nacos
nacos:
server-addr: localhost:8848
namespace: seata
group: DEFAULT_GROUP
data-id: seataServer.properties
username: nacos
password: nacos
多数据源配置(spring.datasource.dynamic)
spring:
datasource:
#配置hikari连接池
hikari:
minimum-idle: 5 #最小连接数
maximum-pool-size: 10 #池中最大连接数
connection-timeout: 20000 #连接超时时间
idle-timeout: 30000 # 空闲等待时间 ms
max-lifetime: 1800000 #30分钟
#动态数据源配置
dynamic:
primary: business
strict: true #接入seata需要此参数
seata: true #接入seata需要此参数
seata-mode: AT #接入seata需要此参数
baomidou多数据源引入pom依赖
<!-- 实现对dynamic-datasource的自动化配置, 版本需升级到3.5.1及以上 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
<version>3.5.1</version>
</dependency>
配置seata的XID请求头拦截器
import feign.RequestInterceptor;
import feign.RequestTemplate;
import io.seata.core.context.RootContext;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
@Slf4j
@Component
public class SeataFeignRequestInterceptor implements RequestInterceptor {
@Override
public void apply(RequestTemplate template) {
String xid = RootContext.getXID();
if (StringUtils.isNotBlank(xid)) {
template.header(RootContext.KEY_XID, xid);
log.debug("Seata XID {} added to Feign request header", xid);
}
}
}
接入seata的客户端服务的数据库表中,需要新增undo_log日志表
CREATE TABLE `undo_log` (
`branch_id` bigint NOT NULL COMMENT 'branch transaction id',
`xid` varchar(128) NOT NULL COMMENT 'global transaction id',
`context` varchar(128) NOT NULL COMMENT 'undo_log context,such as serialization',
`rollback_info` longblob NOT NULL COMMENT 'rollback info',
`log_status` int NOT NULL COMMENT '0:normal status,1:defense status',
`log_created` datetime(6) NOT NULL COMMENT 'create datetime',
`log_modified` datetime(6) NOT NULL COMMENT 'modify datetime',
UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='AT transaction mode undo table'
全局异常处理器改造
package com.riskmage.rmccloud.baseserver.web.exception;
import com.riskmage.rmcbase.BusinessException;
import com.riskmage.rmcbase.Resp;
import com.riskmage.rmccloud.baseserver.base.exception.DistributedTransactionException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.validation.BindException;
import org.springframework.validation.ObjectError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.List;
/**
* 全局异常处理器
*/
@ControllerAdvice
@ResponseBody
@Slf4j
public class GlobalExceptionHandler {
/**
* JSR303 异常
* @param e
* @param request
* @return
*/
@ExceptionHandler({BindException.class})
public Resp<?> handleBindException(BindException e, HttpServletRequest request) {
log.error(e.getMessage());//记录完整错误信息
List<ObjectError> errors = e.getBindingResult().getAllErrors();
ObjectError err= errors.get(0);
String msg = err.getDefaultMessage();
return Resp.failure("999999",msg);
}
/**
* JSR303 异常
* @param e
* @param request
* @return
*/
@ExceptionHandler({MethodArgumentNotValidException.class})
public Resp<?> handleMethodArgumentNotValidException(MethodArgumentNotValidException e, HttpServletRequest request) {
log.error(e.getMessage());//记录完整错误信息
List<ObjectError> errors = e.getBindingResult().getAllErrors();
ObjectError err= errors.get(0);
String msg = err.getDefaultMessage();
return Resp.failure("999999",msg);
}
/**
* JSR303 异常
* @param e
* @param request
* @return
*/
@ExceptionHandler({ConstraintViolationException.class})
public Resp<?> handleConstraintViolationExceptionException(ConstraintViolationException e, HttpServletRequest request) {
log.error(e.getMessage());
ConstraintViolation c = (ConstraintViolation)e.getConstraintViolations().toArray()[0];
String msg =c.getMessage();
return Resp.failure("999999",msg);
}
/**
* BusinessException 自定义业务异常处理
* @param e
* @param request
* @return
*/
@ExceptionHandler({BusinessException.class})
public Resp<?> handleBusinessException(BusinessException e, HttpServletRequest request) {
log.error(e.getMsg());
// 检查是否在分布式事务上下文中
String xid = request.getHeader("TX_XID");
if (StringUtils.isNotEmpty(xid)) {
log.error("handleBusinessException得到TX_XID:{}",xid);
throw new DistributedTransactionException(e.getMsg(), e);
}
return new Resp<>(e.getCode(), e.getMsg(), e.getData());
}
/**
* Exception 异常
* @param e
* @param request
* @return
*/
@ExceptionHandler({Exception.class})
public Resp<?> handleException(Exception e, HttpServletRequest request) {
log.error(e.getMessage(),e);
// 检查是否在分布式事务上下文中
String xid = request.getHeader("TX_XID");
if (StringUtils.isNotEmpty(xid)) {
log.error("捕获到分布式事务中的异常:{}",e.getMessage());
throw new DistributedTransactionException(e);
}
if(e instanceof HttpRequestMethodNotSupportedException){
return Resp.failure("999998","客户端http请求方式有误,请检查!");
}
return Resp.failure("999997","抱歉,服务器繁忙请稍候再试!");
}
// 处理分布式事务相关异常 - 不捕获,直接抛出
@ExceptionHandler(DistributedTransactionException.class)
public void handleDistributedTransactionException(DistributedTransactionException e) throws DistributedTransactionException {
log.error("分布式事务异常: {}", e.getMessage());
throw e;
}
}
新增DistributedTransactionException 自定义分布式事务异常类
/**
* 自定义异常 (分布式事务异常)
*/
public class DistributedTransactionException extends RuntimeException {
public DistributedTransactionException() {
super();
}
public DistributedTransactionException(String message) {
super(message);
}
public DistributedTransactionException(String message, Throwable cause) {
super(message, cause);
}
}
1万+

被折叠的 条评论
为什么被折叠?



