先说结果
数据不一致
对外接口中事务部分成功,部分失败,导致数据异常

一个插入方法需要给不同业务插入数据,调用不同方法,部分表数据成功,部分表数据失败
代码调用链中事务有嵌套设置

外层异常,内层正常插入,导致数据异常,操作的是同以数据库,不同的代码包,用POM依赖调用
原因分析:
1.事务时效
1.private、static、final的使用
解决方法:不在类和方法上使用此类关键字
2.通过this.xxx(调用当前类的方法)
使用xml配置方式暴露代理对象.然后在service中通过代理对象AopContext.currentProxy()去调用方法。
2.事务传递生效规则
1.内部使用父层事务,如果父层级没有事务,开启新事务
2.方法内部多层级调用都需要支持事务回滚,我们的数据库层级使用的
MyBatis3Utils.insert执行后直接提交了导致了事务失效
结果确认:
MyBatis3Utils.insert执行后直接提交了导致了事务失效
在同一个方法中确定抛异常

异常抛出后前面插入的方法已经在数据库提交,并且没有回滚
解决方案
1.添加MyBatis3Utils.insert事务生效的代码
在service执行方法中添加手动事务
@Autowired private DataSourceTransactionManager transactionManager;
DefaultTransactionDefinition def = new DefaultTransactionDefinition();//事务定义类 def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED); TransactionStatus status = transactionManager.getTransaction(def);//返回事务对象。
transactionManager.commit(status);

2.使用分布式锁实现业务流程完成在执行下一条
决定用分布式锁redisson
import org.redisson.Redisson;
import org.redisson.config.Config;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.redisson.api.RedissonClient;
/**
* @Date 2022/2/8 20:29
* @Version 1.0
*/
@Configuration
public class RedissionConfig {
Logger log = LoggerFactory.getLogger(RedissionConfig.class);
@Value("${spring.redis.host}")
String redisIp;
@Value("${spring.redis.port}")
String redisPort;
@Value("${spring.redis.password}")
String redisPassword;
@Bean(name="redissonClient")
public RedissonClient init(){
Config config = new Config();
String url = "redis://"+redisIp+":"+redisPort;
log.info(url);
config.useSingleServer().setAddress(url).setPassword(redisPassword);
config.useSingleServer().setConnectionMinimumIdleSize(10);
RedissonClient redissonClient = Redisson.create(config);
log.info("初始化RedissonClient成功");
return redissonClient;
}
}
业务代码中直接加锁解决
String dataKey = winnerCandidateVO.getDataKey();
RLock lock = redissonClient.getLock("stock:" + dataKey);
lock.lock(10, TimeUnit.SECONDS);
lock.unlock();
通过加锁确保业务的完整唯一性,记得要释放锁
redisson自带有自旋锁和释放自己加的锁,不用担心多线程释放其他线程的锁
本文探讨了一次数据库操作中遇到的数据不一致问题,源于事务嵌套和部分提交。通过分析事务时效和传递规则,作者提出了修正措施,如移除私有静态方法的使用并引入AOP代理。为确保业务流程完整性,文章介绍了如何使用Redisson分布式锁进行同步,以避免并发冲突。
1347

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



