SpringBoot使用当前类代理类(内部事务)解决方案

文章目录

  • 一、场景描述
  • 二、解决方案
      • 1. 使用 `@Lazy`(推荐)
      • 2. 使用方法注入
      • 3. 使用 `ApplicationContext`
      • 4. 分离服务层
      • 5. AspectJ 代理模式

Spring Boot 开发中,我们时常遇到需要在一个类的内部调用自己的其他方法,并且这些方法可能需要事务支持。这种场景通常发生在业务逻辑较为复杂的服务类中,其中一些操作需要确保数据的一致性和完整性。本文将以 MediaFileServiceImpl 类为例,探讨如何在 Spring Boot 中有效地使用当前类的代理类来处理内部事务。

一、场景描述

考虑一个典型的例子:在 MediaFileServiceImpl 服务类中,upload 方法需要调用 upload2Mysql 方法。这里,upload2Mysql 方法是事务性的,意味着它涉及到数据库操作,这些操作需要在一个事务中被处理。如果直接在 upload 方法中调用 upload2Mysql,由于 Spring 的代理方式,事务管理可能不会被正确应用,因为实际上是在同一个实例内部进行方法调用,绕过了 Spring 的代理。

@Service
@Slf4j
public class MediaFileServiceImpl implements MediaFileService {

    @Lazy
    @Autowired
    private MediaFileService mediaFileService;

    @Override
    public UploadFileResultDto upload() {
        // ... 一些业务逻辑 ...
        mediaFileService.upload2Mysql();
        // ... 其他业务逻辑 ...
    }

    @Transactional
    @Override
    public MediaFiles upload2Mysql() {
        // ... 事务性操作 ...
    }
}

二、解决方案

1. 使用 @Lazy(推荐)

MediaFileServiceImpl 类中使用 @Lazy 注解解决循环依赖问题。

@Service
@Slf4j
public class MediaFileServiceImpl implements MediaFileService {

    @Lazy
    @Autowired
    private MediaFileService mediaFileService;

    @Override
    public UploadFileResultDto upload() {
        // ... 一些业务逻辑 ...
        mediaFileService.upload2Mysql();
        // ... 其他业务逻辑 ...
    }

    @Transactional
    @Override
    public MediaFiles upload2Mysql() {
        // ... 事务性操作 ...
    }
}

2. 使用方法注入

方法注入是一种允许在运行时动态注入方法实现的技术。这里,我们通过一个简单的例子来说明如何应用方法注入。

@Service
@Slf4j
public abstract class MediaFileServiceImpl implements MediaFileService {

    @Override
    public UploadFileResultDto upload() {
        // ... 一些业务逻辑 ...
        getMediaFileService().upload2Mysql();
        // ... 其他业务逻辑 ...
    }

    @Transactional
    @Override
    public MediaFiles upload2Mysql() {
        // ... 事务性操作 ...
    }

    @Lookup
    protected abstract MediaFileService getMediaFileService();
}

3. 使用 ApplicationContext

这种方法通过 ApplicationContext 获取当前类的代理。

@Service
@Slf4j
public class MediaFileServiceImpl implements MediaFileService {

    @Autowired
    private ApplicationContext context;

    private MediaFileService getMediaFileService() {
        return context.getBean(MediaFileService.class);
    }

    @Override
    public UploadFileResultDto upload() {
        // ... 一些业务逻辑 ...
        getMediaFileService().upload2Mysql();
        // ... 其他业务逻辑 ...
    }

    @Transactional
    @Override
    public MediaFiles upload2Mysql() {
        // ... 事务性操作 ...
    }
}

4. 分离服务层

将事务性方法移至另一个服务类中。

@Service
@Slf4j
public class MediaFileServiceImpl implements MediaFileService {

    @Autowired
    private MediaFileTransactionalService transactionalService;

    @Override
    public UploadFileResultDto upload() {
        // ... 一些业务逻辑 ...
        transactionalService.upload2Mysql();
        // ... 其他业务逻辑 ...
    }
}

@Service
@Transactional
class MediaFileTransactionalService {

    public MediaFiles upload2Mysql() {
        // ... 事务性操作 ...
    }
}

5. AspectJ 代理模式

使用 AspectJ 代理模式而不是默认的 JDK 动态代理。

@EnableAspectJAutoProxy(proxyTargetClass = true)
@Configuration
public class AppConfig {
    // ... 其他配置 ...
}

然后,您的 MediaFileServiceImpl 类保持不变。

你可能感兴趣的:(SpringBoot3,spring,boot,java,数据库)