1.SpringBoot处理内外事务
场景如下:
某个接口,内部会调用其他多个接口,这些接口属于同一个事务下,统一回滚或提交,在出异常的情况下,需要修改其他数据的订单状态,所以事务的一致性是不能保证的,需要对事务级别进行限制
解决方式:
1.设置独立事务,给同一事务下的方法设置自己的独立事务,自己提交或者回滚,不知道啥问题,楼主测试后无效
@Transactional(propagation = Propagation.REQUIRES_NEW)
2.手动处理事务(类似于独立事务,出现异常手动回滚,外部不会接收异常,返回相应code码或者状态判断即可)
//第一步注入事务数据管理器
@Autowired
DataSourceTransactionManager dataSourceTransactionManager;
//第二步声明并创建DefaultTransactionDefinition类,该类为TransactionDefinition的子类,很多人都说直接注入TransactionDefinition类,经测试无效,猜想是事务级别的原因
//此处声明DefaultTransactionDefinition类
DefaultTransactionDefinition defaultTransactionDefinition = new DefaultTransactionDefinition();
//很重要的一点,设置事务的级别,可以查看源码来得知独立事务的级别并设置 defaultTransactionDefinition.setPropagationBehavior(TransactionDefinition.PROPAGATION_NESTED);
//传入事务管理器
TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(defaultTransactionDefinition);
//第三步,在需要手动管理事务的地方提交或者回滚
//回滚
dataSourceTransactionManager.rollback(transactionStatus);
//提交
dataSourceTransactionManager.commit(transactionStatus);
这里需要说明的是,手动触发事务后,外部try{}catch{}是无法捕捉异常的,可以自定义返回码或者状态在外面判断,然后在外面处理自己想处理的其他数据.
2.线程ID的使用
在我的springboot记录日志博文中,有一个严重错误,就是定义的json是全局的,导致数据会出现错乱的现象,但是拦截器和过滤器之间想要进行数据间的交互,我这里采用的是获取线程ID的形式进行辨别
//获取线程ID
Thread.currentThread().getId();
//获取线程名称
Thread.currentThread().getName();
因为线程的特性,在请求未结束前,线程ID是不会被占用和复用的,这样在请求日志中可以在redis中用线程ID作为key进行数据存储,在过滤器中获取响应数据,然后通过线程ID获取缓存数据再次更新,等待操作结束存入静态集合后,删除该缓存即可
//获取返回值
byte[] content = responseWrapper.getContent();
//判断是否有值
if (content.length > 0) {
String str = new String(content, "UTF-8");
ServletOutputStream out = response.getOutputStream();
out.write(content);
out.flush();
JSONObject endJson = (JSONObject) redisService.get(Thread.currentThread().getName());
System.out.println(Thread.currentThread().getName());
if(!endJson.getString(URI).contains(DOWMLOAD_FILE)){
endJson.put("response",str);
redisService.put(Thread.currentThread().getName(),endJson,timeout);
JSONObject endJsons = (JSONObject) redisService.get(Thread.currentThread().getName());
logProcess.addData(endJsons);
//删除当前缓存数据
redisService.deleteString(Thread.currentThread().getName());
}
}
不知道还有没有其他的关联办法,楼主目前还没有想到...
权当技术积累先记录下来,后续有想法再来这里温习一下