先说结果
数据不一致
对外接口中事务部分成功,部分失败,导致数据异常
一个插入方法需要给不同业务插入数据,调用不同方法,部分表数据成功,部分表数据失败
代码调用链中事务有嵌套设置
外层异常,内层正常插入,导致数据异常,操作的是同以数据库,不同的代码包,用POM依赖调用
原因分析:
1.事务时效
1.private、static、final的使用
解决方法:不在类和方法上使用此类关键字
2.通过this.xxx(调用当前类的方法)
使用xml配置方式暴露代理对象.然后在service中通过代理对象AopContext.currentProxy()去调用方法。
2.事务传递生效规则
1.内部使用父层事务,如果父层级没有事务,开启新事务
2.方法内部多层级调用都需要支持事务回滚
pom中依赖的导致事务无法生效
决定用分布式锁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自带有自旋锁和释放自己加的锁,不用担心多线程释放其他线程的锁