关于Spring Boot:多线程事务处理

目录

一、前言

二、解决方案

三、代码示例

四、注意事项


全栈码农以及毕业设计实战开发,CSDN平台Java领域新星创作者,专注于大学生项目实战开发、讲解和毕业答疑辅导。

一、前言

在Spring Boot中处理多线程事务时,需要注意事务的隔离性和线程安全性。由于Spring的默认事务管理机制(如通过@Transactional注解)是基于ThreadLocal的,它确保事务的上下文(如数据库连接和Session)与当前线程绑定。然而,当在事务内部启动新线程时,这些上下文信息并不会被新线程继承,这可能导致事务失效、数据不一致或死锁等问题。

二、解决方案

  1. 单线程优化:首先,尽量通过优化单线程逻辑来解决问题,如减少数据库交互次数、优化查询语句等。

  2. 合理分块后多线程处理:对于大批量数据处理,可以将其分成多个小块,每个小块在独立线程中处理,并使用类似分布式事务的方式确保数据的最终一致性。

  3. 自定义事务管理:在某些情况下,可能需要编写自定义的事务管理逻辑来适应多线程环境。

三、代码示例

实体类定义:

import lombok.AllArgsConstructor;  
import lombok.Data;  
import lombok.NoArgsConstructor;  
  
import javax.persistence.Column;  
import javax.persistence.Entity;  
import javax.persistence.Id;  
import javax.persistence.Table;  
import java.io.Serializable;  
import java.math.BigDecimal;  
  
@Data  
@Entity  
@Table(name = "stu")  
@AllArgsConstructor  
@NoArgsConstructor  
public class Stu implements Serializable {  
    private static final long serialVersionUID = 1L;  
  
    @Id  
    @Column(name = "id", nullable = false)  
    private Integer id;  
  
    @Column(name = "name", nullable = false)  
    private String name;  
  
    @Column(name = "price")  
    private BigDecimal price;  
  
    public Stu(String name, BigDecimal price) {  
        this.name = name;  
        this.price = price;  
    }  
}

服务层处理:

import com.example.demo.threadTransactional.entity.Stu;  
import com.example.demo.threadTransactional.repository.StuRepository;  
import com.google.common.collect.Lists;  
import com.google.common.util.concurrent.ThreadFactoryBuilder;  
import lombok.extern.slf4j.Slf4j;  
import org.springframework.beans.factory.annotation.Autowired;  
import org.springframework.scheduling.annotation.Async;  
import org.springframework.stereotype.Service;  
import org.springframework.transaction.annotation.Transactional;  
  
import java.util.List;  
import java.util.concurrent.*;  
  
@Service  
@Slf4j  
public class StuService {  
  
    @Autowired  
    private StuRepository stuRepository;  
  
    // 假设的异步方法,用于处理分块数据  
    @Async  
    @Transactional  
    public void saveBatch(List<Stu> stuList) {  
        for (Stu stu : stuList) {  
            stuRepository.save(stu);  
        }  
    }  
  
    // 主方法,用于分割数据并启动多线程  
    public void saveBooks(List<Stu> bookList) throws InterruptedException {  
        // 根据业务场景,将大任务进行划分成小任务  
        List<List<Stu>> partition = Lists.partition(bookList, 100); // 每批100个对象  
  
        // 线程池  
        ExecutorService executor = Executors.newFixedThreadPool(4); // 4个线程  
  
        // 启动多个线程处理  
        List<Future<?>> futures = new ArrayList<>();  
        for (List<Stu> part : partition) {  
            Future<?> future = executor.submit(() -> saveBatch(part));  
            futures.add(future);  
        }  
  
        // 等待所有线程完成  
        for (Future<?> future : futures) {  
            future.get(); // 阻塞直到该任务完成  
        }  
  
        executor.shutdown();  
        executor.awaitTermination(1, TimeUnit.HOURS); // 等待所有任务完成  
    }  
}

四、注意事项

  • 这里的@Transactional注解用于每个saveBatch方法,但在多线程环境下,它实际上是对每个线程独立生效的,而不是跨线程的事务。
  • 使用了@Async注解来标记saveBatch方法为异步执行,确保它在不同线程中运行。
  • 使用了线程池来管理多个线程,避免频繁创建和销毁线程的开销。
  • 使用了`Future.
  • 15
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值