Merge branch 'master' of https://gitea.zianxin.com/zax/biz-api-cloud
This commit is contained in:
commit
da167a46ef
5 files changed
+218
No files matched your search
+34
@@ -0,0 +1,34 @@
|
||||
package com.bsd.pjcloud.admin.api.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.baomidou.mybatisplus.extension.activerecord.Model;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Data
|
||||
@TableName("seata_tx_probe")
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Schema(description = "Seata事务探测")
|
||||
public class SeataTxProbeEntity extends Model<SeataTxProbeEntity> {
|
||||
|
||||
@TableId(type = IdType.ASSIGN_ID)
|
||||
@Schema(description = "主键")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "本次探测标记")
|
||||
private String mark;
|
||||
|
||||
@Schema(description = "commit / rollback")
|
||||
private String caseType;
|
||||
|
||||
@Schema(description = "备注")
|
||||
private String remark;
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
private LocalDateTime createTime;
|
||||
}
|
||||
+100
@@ -0,0 +1,100 @@
|
||||
package com.bsd.pjcloud.admin.controller;
|
||||
|
||||
import com.bsd.pjcloud.admin.service.SeataTxProbeService;
|
||||
import com.bsd.pjcloud.common.core.util.R;
|
||||
import com.bsd.pjcloud.common.log.annotation.SysLog;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 后台一键探测 Seata:提交应落库,回滚应不落库。
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@RequestMapping("/seataProbe")
|
||||
@Tag(description = "seataProbe", name = "Seata事务探测")
|
||||
@SecurityRequirement(name = HttpHeaders.AUTHORIZATION)
|
||||
public class SeataTxProbeController {
|
||||
|
||||
private final SeataTxProbeService seataTxProbeService;
|
||||
|
||||
@Operation(summary = "Seata提交探测")
|
||||
@SysLog("Seata提交探测")
|
||||
@PostMapping("/commit")
|
||||
@PreAuthorize("@pms.hasPermission('admin_seata_probe')")
|
||||
public R<Map<String, Object>> commit() {
|
||||
try {
|
||||
Map<String, Object> started = seataTxProbeService.testCommit();
|
||||
String mark = String.valueOf(started.get("mark"));
|
||||
long cnt = seataTxProbeService.countByMark(mark);
|
||||
Map<String, Object> body = new HashMap<>(started);
|
||||
body.put("rowCount", cnt);
|
||||
body.put("pass", cnt == 1);
|
||||
body.put("message", cnt == 1
|
||||
? "提交成功:已连上 TC,数据已落库(seata_tx_probe)"
|
||||
: "提交异常:事务看似结束但库中无记录,请查 Seata/undo_log/数据源代理");
|
||||
return cnt == 1 ? R.ok(body) : R.failed(body, String.valueOf(body.get("message")));
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("[seataProbe/commit] 失败", e);
|
||||
return R.failed("提交探测失败:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Operation(summary = "Seata回滚探测")
|
||||
@SysLog("Seata回滚探测")
|
||||
@PostMapping("/rollback")
|
||||
@PreAuthorize("@pms.hasPermission('admin_seata_probe')")
|
||||
public R<Map<String, Object>> rollback() {
|
||||
String mark = null;
|
||||
String xid = null;
|
||||
try {
|
||||
seataTxProbeService.testRollbackExpectThrow();
|
||||
return R.failed("回滚探测异常:应抛错触发回滚,但方法正常返回");
|
||||
}
|
||||
catch (IllegalStateException e) {
|
||||
String msg = e.getMessage();
|
||||
if (msg != null && msg.startsWith("SEATA_PROBE_ROLLBACK:")) {
|
||||
String payload = msg.substring("SEATA_PROBE_ROLLBACK:".length());
|
||||
int p = payload.indexOf('|');
|
||||
if (p >= 0) {
|
||||
mark = payload.substring(0, p);
|
||||
xid = payload.substring(p + 1);
|
||||
}
|
||||
else {
|
||||
mark = payload;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("[seataProbe/rollback] 非预期异常", e);
|
||||
return R.failed("回滚探测失败:" + e.getMessage());
|
||||
}
|
||||
if (mark == null) {
|
||||
return R.failed("回滚探测失败:未拿到 mark");
|
||||
}
|
||||
long cnt = seataTxProbeService.countByMark(mark);
|
||||
Map<String, Object> body = new HashMap<>(6);
|
||||
body.put("mark", mark);
|
||||
body.put("xid", xid);
|
||||
body.put("caseType", "rollback");
|
||||
body.put("rowCount", cnt);
|
||||
body.put("pass", cnt == 0);
|
||||
body.put("message", cnt == 0
|
||||
? "回滚成功:已连上 TC,插入被全局回滚,库中无残留"
|
||||
: "回滚失败:库中仍有记录,全局事务可能未生效(检查数据源代理/Seata)");
|
||||
return cnt == 0 ? R.ok(body) : R.failed(body, String.valueOf(body.get("message")));
|
||||
}
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
package com.bsd.pjcloud.admin.mapper;
|
||||
|
||||
import com.bsd.pjcloud.admin.api.entity.SeataTxProbeEntity;
|
||||
import com.bsd.pjcloud.common.data.datascope.PjcloudBaseMapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
@Mapper
|
||||
public interface SeataTxProbeMapper extends PjcloudBaseMapper<SeataTxProbeEntity> {
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
package com.bsd.pjcloud.admin.service;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Seata 全局事务探测:验证 TC 连通与 AT 提交/回滚。
|
||||
*/
|
||||
public interface SeataTxProbeService {
|
||||
|
||||
Map<String, Object> testCommit();
|
||||
|
||||
/**
|
||||
* 故意抛错触发全局回滚;调用方捕获异常后查库校验。
|
||||
*/
|
||||
Map<String, Object> testRollbackExpectThrow();
|
||||
|
||||
long countByMark(String mark);
|
||||
}
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
package com.bsd.pjcloud.admin.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.bsd.pjcloud.admin.api.entity.SeataTxProbeEntity;
|
||||
import com.bsd.pjcloud.admin.mapper.SeataTxProbeMapper;
|
||||
import com.bsd.pjcloud.admin.service.SeataTxProbeService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.seata.core.context.RootContext;
|
||||
import org.apache.seata.spring.annotation.GlobalTransactional;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class SeataTxProbeServiceImpl implements SeataTxProbeService {
|
||||
|
||||
private final SeataTxProbeMapper seataTxProbeMapper;
|
||||
|
||||
@Override
|
||||
@GlobalTransactional(name = "seata-probe-commit", rollbackFor = Exception.class)
|
||||
public Map<String, Object> testCommit() {
|
||||
String mark = "C-" + UUID.randomUUID().toString().replace("-", "");
|
||||
insertRow(mark, "commit", "commit probe");
|
||||
Map<String, Object> out = new HashMap<>(4);
|
||||
out.put("mark", mark);
|
||||
out.put("xid", RootContext.getXID());
|
||||
out.put("caseType", "commit");
|
||||
return out;
|
||||
}
|
||||
|
||||
@Override
|
||||
@GlobalTransactional(name = "seata-probe-rollback", rollbackFor = Exception.class)
|
||||
public Map<String, Object> testRollbackExpectThrow() {
|
||||
String mark = "R-" + UUID.randomUUID().toString().replace("-", "");
|
||||
insertRow(mark, "rollback", "rollback probe before throw");
|
||||
throw new IllegalStateException("SEATA_PROBE_ROLLBACK:" + mark + "|" + RootContext.getXID());
|
||||
}
|
||||
|
||||
@Override
|
||||
public long countByMark(String mark) {
|
||||
return seataTxProbeMapper.selectCount(Wrappers.<SeataTxProbeEntity>lambdaQuery()
|
||||
.eq(SeataTxProbeEntity::getMark, mark));
|
||||
}
|
||||
|
||||
private void insertRow(String mark, String caseType, String remark) {
|
||||
SeataTxProbeEntity row = new SeataTxProbeEntity();
|
||||
row.setMark(mark);
|
||||
row.setCaseType(caseType);
|
||||
row.setRemark(remark);
|
||||
row.setCreateTime(LocalDateTime.now());
|
||||
seataTxProbeMapper.insert(row);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user