事务与异步脏数据问题

2023-11-04

1、事务未提交,异步获取不到数据

package com.spring.pro.service.impl;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;

import javax.annotation.Resource;

import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import com.alibaba.fastjson.JSON;
import com.spring.pro.entity.User;
import com.spring.pro.mapper.UserMapper;
import com.spring.pro.service.UserService;

import lombok.extern.slf4j.Slf4j;

/**
 * @Title: UserServiceImpl.java
 * @ProjectName com.spring.pro.threadpool
 * @Description:
 * @author ybwei
 * @date 2020年1月10日 下午4:37:35
 */
@Component("userService")
@Slf4j
public class UserServiceImpl implements UserService {

	@Resource
	private UserMapper userMapper;
	@Resource(name = "taskExecutor")
	private ThreadPoolTaskExecutor threadPoolTaskExecutor;

	@Override
	@Transactional
	public void testTransactional() {
		User user = new User();
		user.setName("张三");
		user.setAge(12);
		userMapper.insertSelective(user);
		// 异步
		CompletableFuture.runAsync(() -> {
			handleDb(user.getId());
		}, threadPoolTaskExecutor);
		try {
			TimeUnit.SECONDS.sleep(1);// 休眠1秒,测试使用,保证异步执行时,事务未提交
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		log.info("添加后user:{}", JSON.toJSONString(user));
	}

	private void handleDb(Long id) {
		User user = userMapper.selectByPrimaryKey(id);
		log.info("异步user:{}", JSON.toJSONString(user));
	}

}

打印日志如下

[INFO ] 2020-01-10 16:52:34.907 [taskExecutor-1] c.s.pro.service.impl.UserServiceImpl - 异步user:null
[INFO ] 2020-01-10 16:52:35.659 [http-nio-8080-exec-5] c.s.pro.service.impl.UserServiceImpl - 添加后user:{"age":12,"id":47025,"name":"张三"}

因为事务还未提交,所以异步中获取user是空的。

2、事务已提交,获取数据库数据

异步中的user,我们想要的是事务提交后的数据

package com.spring.pro.service.impl;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;

import javax.annotation.Resource;

import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import com.alibaba.fastjson.JSON;
import com.spring.pro.entity.User;
import com.spring.pro.mapper.UserMapper;
import com.spring.pro.service.UserService;

import lombok.extern.slf4j.Slf4j;

/**
 * @Title: UserServiceImpl.java
 * @ProjectName com.spring.pro.threadpool
 * @Description:
 * @author ybwei
 * @date 2020年1月10日 下午4:37:35
 */
@Component("userService")
@Slf4j
public class UserServiceImpl implements UserService {

	@Resource
	private UserMapper userMapper;
	@Resource(name = "taskExecutor")
	private ThreadPoolTaskExecutor threadPoolTaskExecutor;

	@Override
	@Transactional
	public void testTransactional() {
		User user = new User();
		user.setName("张三");
		user.setAge(12);
		userMapper.insertSelective(user);
		// 异步
		CompletableFuture.runAsync(() -> {
			handleDb(user.getId());
		}, threadPoolTaskExecutor);
		log.info("添加后user:{}", JSON.toJSONString(user));
	}

	private void handleDb(Long id) {
		try {
			TimeUnit.SECONDS.sleep(1);// 休眠1秒,测试使用,保证异步执行时,事务已提交
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		User user = userMapper.selectByPrimaryKey(id);
		log.info("异步user:{}", JSON.toJSONString(user));
	}

}

打印日志如下:

[INFO ] 2020-01-10 16:57:14.862 [http-nio-8080-exec-7] c.s.pro.service.impl.UserServiceImpl - 添加后user:{"age":12,"id":47027,"name":"张三"}
[INFO ] 2020-01-10 16:57:15.866 [taskExecutor-2] c.s.pro.service.impl.UserServiceImpl - 异步user:{"age":12,"createTime":1578646634000,"id":47027,"name":"张三","points":0,"status":0,"updateTime":1578646634000}

3、解决问题

第二步,休眠1秒,并不是解决问题的方案。

package com.spring.pro.service.impl;

import java.util.concurrent.CompletableFuture;

import javax.annotation.Resource;

import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronizationAdapter;
import org.springframework.transaction.support.TransactionSynchronizationManager;

import com.alibaba.fastjson.JSON;
import com.spring.pro.entity.User;
import com.spring.pro.mapper.UserMapper;
import com.spring.pro.service.UserService;

import lombok.extern.slf4j.Slf4j;

/**
 * @Title: UserServiceImpl.java
 * @ProjectName com.spring.pro.threadpool
 * @Description:
 * @author ybwei
 * @date 2020年1月10日 下午4:37:35
 */
@Component("userService")
@Slf4j
public class UserServiceImpl implements UserService {

	@Resource
	private UserMapper userMapper;
	@Resource(name = "taskExecutor")
	private ThreadPoolTaskExecutor threadPoolTaskExecutor;

	@Override
	@Transactional
	public void testTransactional() {
		User user = new User();
		user.setName("张三");
		user.setAge(12);
		userMapper.insertSelective(user);
		TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
			@Override
			public void afterCommit() {
				// 异步
				CompletableFuture.runAsync(() -> {
					handleDb(user.getId());
				}, threadPoolTaskExecutor);
			}
		});
		log.info("添加后user:{}", JSON.toJSONString(user));
	}

	private void handleDb(Long id) {
		User user = userMapper.selectByPrimaryKey(id);
		log.info("异步user:{}", JSON.toJSONString(user));
	}

}

TransactionSynchronizationManager.registerSynchronization可以保证事务提交后,才会执行afterCommit里面的异步方法。

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

事务与异步脏数据问题 的相关文章

随机推荐

  • 基于Spring Cloud Alibaba搭建nacos

    关系 Spring Boot是框架 将各个组件集合在一起 方便快速开发web应用 Spring Cloud基于Spring Boot 限定了一组特定的组件 从而可以方便地进行微服务工程的开发 Spring Cloud Alibaba在Spr
  • C/C++中如何获取数组的长度

    1 算术表达式 include
  • 2022李宏毅机器学习深度学习学习笔记第四周--Self-Supervised Learning

    文章目录 前言 Self Supervised Learning 什么是Self Supervised Learning Masking Input Next Sentence Prediction BERT如何使用 为什么BERT 有用呢
  • 最牛的人脸检测算法

    深大于老师的libfacedetection检测算法快速高效 准确率相当高 世界排名第五 最小可检测人脸12 12像素 关键是前两天开源了 于是我简单的看了一下 是自己用c 手敲的cnn代码 真心佩服 该代码可以在windows linux
  • pycharm安装beautifulsoup出错

    尝试一 将虚拟环境的解释器改成安装python真实路径的解释器 步骤 setting gt project interpreter gt show all gt gt system interpreter 尝试二 Python3的选择bs4
  • 休眠唤醒(suspend/resume)时长问题分析思路

    1 echo 1 gt sys power pm print times 打开suspend resume耗时开关 如下 可以看到系统休眠时各阶段驱动模块的耗时打印 可用来帮助分析排查休眠耗时长的问题 267 398855 lt 1 gt
  • windows系统c++多线程开发

    线程的一些基本概念 一 线程的基本概念 基本概念 线程 即轻量级进程 LWP LightWeight Process 是程序执行流的最小单元 一个标准的线程由线程ID 当前指令指针 PC 寄存器集合和堆栈组成 线程是进程中的一个实体 是被系
  • 50Hz双T陷波滤波器(带阻滤波器)

    一 双T陷波滤波器 针对其中50Hz仿真计算 https www docin com p 1945752171 html 双T型陷波滤波器 Ivan 的专栏 CSDN博客 t型滤波器 https blog csdn net stephani
  • C语言学习:运算符和表达式

    算数运算符 自增 自减运算符 作用是让变量的值加1减1 i 在使用i之前加一 i 在使用i之后加一 这种运算符只能用于变量 常常用在循环语句哪里 也用于指针变量 是指针指向下一个地址 算数优先级 一个数两边都有运算符 那么先考虑优先级 如果
  • 改善你的jQuery的25个步骤 千倍级效率提升

    1 从Google Code加载jQueryGoogle Code上已经托管了多种JavaScript类库 从Google Code上加载jQuery比直接从你的服务器加载更有优势 它节省了你服务器上的带宽 能够很快的从Google的内容分
  • 喜大普奔!70k Star 《Java面试突击手册》PDF版本开放下载啦!

    前段时间我的朋友 Guide 哥终于把PDF版本的 Java面试突击手册 搞定 废话不多说 直接上目录 这份文档是 JavaGuide 这个项目所有和 Java 面试相关的文章的集合 内容涵盖Java基础 计算机网络 数据库 Spring等
  • Cookie基本使用

    开发工具与关键技术 IDEA 撰写时间 2022 10 8 发送Cookie 创建Cookie对象 设置数据 Cookie cookie new Cookie String key String value 2 发送Cookie到客户端 使
  • spring使用内存数据库(h2)快速开发

    目录 什么是内存数据库 内存数据库可以解决什么问题 有哪些内存数据库 内存数据库这么多 到底选哪个好 可以参考对比 代码下载 https gitee com hong99 spring issues I1N1DF 代码实现 代码下载 htt
  • 移动端项目常见适配

    目录 1 视口设置 2 解决click事件0 3秒延迟问题 3 解决不同机型border显示不一样的问题 移动端rem适配 1 视口设置 如果是vue项目 视口设置一般在根目录或public下的index html 设置为理想视口 不允许用
  • 深度学习中训练时候遇到这些错误 RuntimeError、IndexError、ValueError如何解决

    深度学习训练中遇到一些bug torch版 RuntimeError 类型一 RuntimeError Input type torch cuda FloatTensor and weight type torch FloatTensor
  • 华为机试:最长方连续方波信号

    题目来源 最长方连续方波信号 题目描述 输入一串方波信号 求取最长的完全连续交替方波信号 并将其输出 如果有相同长度的交替方波信号 输出任一即可 方波信号高位用1标识 低位用0标识 如图 说明 1 一个完整的信号一定以0开始然后以0结尾 即
  • 我的全栈之路-C语言基础之C语言概述与开发环境搭建

    我的全栈之路 C语言基础之C语言概述与开发环境搭建 我的全栈之路 1 1 信息技术发展趋势 1 2 浅谈计算机系统架构 1 2 1 计算机系统架构概述 1 2 2 计算机硬件系统 1 2 2 计算机软件系统 1 3 程序和指令 1 4 编程
  • 惯导系列(一):STM232 IIC读取MPU数据

    前言 消失了几天的我在哪 对 没错 就在实验室默默的调试代码 折磨我几天的MPU终于弄好了 虽然只是弄好一半 但是也是值得令人开心的 本节介绍 一 IIC通讯 1 1 IIC通讯简介 1 2 模拟IIC 1 3 mpu外设 二 实现 2 1
  • Windows10如何添加开机启动项

    在日常生活中 偶尔要求其中的软件在开机时便能自动启动 比如MySQL一般被设置为自启动项 今天将为大家介绍window10中如何添加开机启动项 操作过程 1 按下win R调出运行窗口 并输入 shell startup 即可进入开机启动文
  • 事务与异步脏数据问题

    1 事务未提交 异步获取不到数据 package com spring pro service impl import java util concurrent CompletableFuture import java util conc