前提
本地环境为:windows 10,
正式环境和测试环境均为:linux
数据库为mysql,测试环境和开发环境用的同一个数据库,区别是测试环境用的内网ip,开发环境是用的外网id
java代码,使用的spring-boot框架,
2018年写的老代码了,今天突然出了问题,问题是,@Transactional注解没有回滚,问题描述如下:
Controller调用Service的A方法(A方法有@Transactional注解),
A方法调用同一个Service的B方法(B方法有@Transactional注解),
B方法抛出异常(该异常继承RuntimeException类)
然后A方法的事务没有回滚。
然后我在本地运行代码发现:本地环境正常,事务可以回滚
然后我把上面的代码修改了一下,直接在Service方法的A方法中抛出异常,测试环境仍然没有回滚(本地可以回滚)。
一模一样的代码,在本地可以,在测试环境不行,想问这和运行环境有关系吗?
下面是代码
Controller代码
@RestController
public class UserWithdrawController {
@PutMapping("/v1/user-withdraw/audit")
public boolean auditUserWithdraw(@RequestBody UserWithdrawDeposit uwd,
@RequestParam("loginUserId") Integer loginUserId) {
boolean result = withdrawService.auditUserWithdraw(uwd, loginUserId);
return result;
}
}
Service代码
@Service
@Slf4j
public class UserWithdrawService {
// 此为A方法
@Transactional
public boolean auditUserWithdraw(UserWithdrawDeposit uwd, Integer loginUserId) {
// 判断必填项
if (StringUtils.isBlank(uwd.getId()) || loginUserId == null) {
throw new OSWNException(GlobalError.PARAMETERS_IS_EMPTY);
}
if (uwd.getAuditStatus() == Constants.USER_WITHDRAW_AUDIT_STATUS_UNPASS.getCode()
&& StringUtils.isBlank(uwd.getReason())) {
throw new OSWNException(GlobalError.PARAMETERS_IS_EMPTY);
}
// 检查申请数据,查询数据库中的退款申请,判断是否为待审核状态,如果不是待审核,提示错误
UserWithdrawDeposit dbUwd = withdrawMapper.getUserWithdrawById(uwd.getId());
if (dbUwd == null || dbUwd.getAuditStatus() != Constants.USER_WITHDRAW_AUDIT_STATUS_UNAUDIT.getCode()) {
throw new OSWNException(GlobalError.PARAMETERS_INVALID);
}
// 修改提现申请数据
uwd.setAuditorId(loginUserId);
// 查询管理员的账号
String account = sysUsersMapper.getAccountByUserId(loginUserId);
uwd.setAuditorName(account);
Date date = new Date();
uwd.setAuditTime(date);
// 修改
int num = withdrawMapper.auditUserWithdraw(uwd);
if (num == 0) {
throw new OSWNException(GlobalError.OPERATION_FAILURE);
}
if (num != 0) {// 次判断是为了测试事务写的,此处必报错,
throw new OSWNException(GlobalError.OPERATION_FAILURE);
}
if (uwd.getAuditStatus() == Constants.USER_WITHDRAW_AUDIT_STATUS_PASS.getCode()) {
// 审核通过,创建订单信息,发送转账请求 ----**这里调用B方法**
agreeUserWithdraw(dbUwd, loginUserId);
} else if (uwd.getAuditStatus() == Constants.USER_WITHDRAW_AUDIT_STATUS_UNPASS.getCode()) {
// 审核不通过,返还金额,创建退还提现的订单,创建退还提现和手续费2个流水
refuseUserWithdraw(dbUwd, loginUserId);
} else {
throw new OSWNException(GlobalError.PARAMETERS_INVALID);
}
}
//B方法
/**
* 同意提现申请
*
* @param uwd
* 申请信息
* @param loginUserId
* 登录用户id
* @return boolean
*/
@Transactional
public boolean agreeUserWithdraw(UserWithdrawDeposit uwd, Integer loginUserId) {
// 判断用户钱包是否被冻结
UserWallet userWallet = userWalletMapper.getUserWalletByUserId(uwd.getUserId());
if (userWallet.getStatus() == Constants.USER_WALLET_STATUS_FROZEN.getCode()) {
throw new OSWNException(GlobalError.USER_WALLET_IS_FROZEN);
}
// 判断用户是否绑定支付账号
UserPayAccount account = userWalletMapper.getUserAlipayAccount(uwd.getUserId());
if (account == null) {
throw new OSWNException(GlobalError.USER_PAY_ACCOUNT_NOT_EXISTS);
}
// 查询订单,根据订单进行支付宝转账,返回支付宝支付号
Order order = orderMapper.getOrderByBusiId(uwd.getId(), Constants.ORDER_BUSI_TYPE_WITHDRAW.getCode());
if (order == null) {
throw new OSWNException(GlobalError.ORDER_NOT_EXSIT);
}
// 发起支付宝转账
String alipayOrderId = "";
// 把转账金额由分换成元
String totalAmountY = AmountUtils.changeF2Y(order.getTotalAmount());
AlipayDto alipayDto = new AlipayDto();
alipayDto.setAmount(totalAmountY);
alipayDto.setOrderId(order.getId());
alipayDto.setPayeeAccount(account.getAccount());
alipayDto.setRemark(order.getDescription());
alipayDto.setRealName(account.getName());
try {
alipayOrderId = alipayService.fundTransToaccountTransfer(alipayDto);
} catch (AlipayApiException e) {
throw new OSWNException(GlobalError.OPERATION_FAILURE);
}
// 把支付宝支付号回写到流水表
if (StringUtils.isBlank(alipayOrderId)) {// 走到这段代码抛的异常
throw new OSWNException(GlobalError.OPERATION_FAILURE);
}
}
/**
* 自定义异常
*
* @author HuangTao
*/
public class OSWNException extends RuntimeException {
}
}