当前位置: 首页 > news >正文

spring的事务控制

1.调用这个方法的对象是否是spring的代理对象($CGLIB结尾的)

2.这个方法是否是加了@Transactional注释

都符合才可以被事物控制

如果调用方法的对象没有被事物控制,那么被调用的方法即便是加了@Transactional也是没用的

事务失效情况:

 解释说明:

1)基于aop的环绕通知的方式,如果抛出了异常给spring框架和代理对象就会进行事物的回滚,而如果调用这个方法的时候把异常捕获到了,并没有抛出就会导致事务无法回滚。

 3)事务方法调用事务方法:

        如果在事务对象内部直接调用另一个事务方法,那么是会进行事务传递的,被调用的事务方法是会被当成和调用方一个整体的事务。并且被调用的事务不可以新开启一个事务,也就是说,被调用的事务上方加上如下注释是不起作用的

 5)可以自行定义事务抛出什么类型的异常才能回滚:

 

一个非事务方法调同类一个事务方法,事务无法控制举例如下:

在controller中,调用MediaFileServiceImpl 中的uploadFile方法,因为controller中注入了@Autowired MediaFileService mediaFileService;所以controller将被spring代理对象代理,此时如果MediaFileServiceImpl中的 uploadFile加了@Transactional注释,那么很自然的将受到事物控制。(验证是否是spring的代理对象,可以debug然后查看变量是否是$CGLIB结尾的)。

 如果在uploadFile方法上没有@Transactional注解,代理对象执行此方法前不进行事务控制,如下图:

 现在在addMediaFilesToDb方法上添加@Transactional注解,也不会进行事务是因为并不是通过代理对象执行的addMediaFilesToDb方法。为了判断在uploadFile方法中去调用addMediaFilesToDb方法是否是通过代理对象去调用,我们可以打断点跟踪。

controller代码如下,在try catch中看到用的是mediaFileService去调用的uploadFile方法,此时是可以控制事物的。

public class MediaFilesController {@Autowired
MediaFileService mediaFileService;@RequestMapping(value = "/upload/coursefile", consumes = {MediaType.MULTIPART_FORM_DATA_VALUE})public UploadFileResultDto upload(@RequestPart("filedata") MultipartFile filedata,@RequestParam(value = "folder",required=false) String folder,@RequestParam(value= "objectName",required=false) String objectName) {Long companyId = 1232141425L;UploadFileParamsDto uploadFileParamsDto = new UploadFileParamsDto();String contentType = filedata.getContentType();uploadFileParamsDto.setContentType(contentType);uploadFileParamsDto.setFileSize(filedata.getSize());//文件大小if (contentType.indexOf("image") >= 0) {//是个图片uploadFileParamsDto.setFileType("001001");} else {uploadFileParamsDto.setFileType("001003");}uploadFileParamsDto.setFilename(filedata.getOriginalFilename());//文件名称UploadFileResultDto uploadFileResultDto = null;try {uploadFileResultDto = mediaFileService.uploadFile(companyId, uploadFileParamsDto, filedata.getBytes(), folder, objectName);} catch (Exception e) {XueChengPlusException.cast("上传文件过程中出错");}return uploadFileResultDto;}

如果在uploadFile方法中取调用另外一个方法,那么显然调用的对象默认是this,并不是受到spring代理的对象,所以即便被uploadFile方法调用的方法加了@Transactional注释,也是没用的。

解决非代理对象调用@Transactional方法的:

我们可以模仿@Controller中的写法,在被调用的方法中注入相应的service,然后用service在非事物方法中取调用加了@Transactional注释的方法,这样事物是会生效的。

下面举例:

serviceimpl类中的uploadFile方法调用另一个@Transactional方法,形成事物

首先在serviceimpl中注入service对象:(对象名字无所谓,加了@Autowired注释的对象会被AOP拦截)

    @AutowiredMediaFileService proxy;

调用方法:(在try代码第2行,用proxy调用)

@Overridepublic UploadFileResultDto uploadFile(Long companyId, UploadFileParamsDto uploadFileParamsDto, byte[] bytes, String folder, String objectName) {....try {addMediaFilesToMinIO(bytes,bucket_files,objectName);MediaFiles mediaFiles = proxy.addMediaFilesToDb(companyId, fileMd5, uploadFileParamsDto, bucket_files, objectName);//准备返回数据UploadFileResultDto uploadFileResultDto = new UploadFileResultDto();BeanUtils.copyProperties(mediaFiles,uploadFileResultDto);return uploadFileResultDto;} catch (Exception e) {log.debug("上传文件失败:{}",e.getMessage());throw new RuntimeException(e.getMessage());}//        return null;}

被调用的方法:

@Transactional
public MediaFiles addMediaFilesToDb(Long companyId, String fileId, UploadFileParamsDto uploadFileParamsDto, String bucket, String objectName) {//保存到数据库MediaFiles mediaFiles = mediaFilesMapper.selectById(fileId);if(mediaFiles == null){mediaFiles = new MediaFiles();//封装数据BeanUtils.copyProperties(uploadFileParamsDto,mediaFiles);mediaFiles.setId(fileId);mediaFiles.setFileId(fileId);mediaFiles.setCompanyId(companyId);mediaFiles.setBucket(bucket);mediaFiles.setFilePath(objectName);mediaFiles.setUrl("/"+bucket+"/"+objectName);mediaFiles.setCreateDate(LocalDateTime.now());mediaFiles.setStatus("1");mediaFiles.setAuditStatus("002003");//插入文件表mediaFilesMapper.insert(mediaFiles);}return mediaFiles;}

注意:我们这里由于是用的service来调用,而service是一个接口,所以被proxy调用的方法必须也是以接口形式呈现出来,那么需要将addMediaFilesToDb写入到对应调用这个方法的service(此处用)MediaFileService proxy调用,所以在MediaFileService 中加上这个方法,写个接口即可。

接口如下:

public interface MediaFileService {
/***
* @description 上传文件到数据库,抽取为接口的形式,方便调用
* @param companyId* @param fileId* @param uploadFileParamsDto* @param bucket* @param objectName
* @return
* @author
* @date
*/public MediaFiles addMediaFilesToDb(Long companyId, String fileId, UploadFileParamsDto uploadFileParamsDto, String bucket, String objectName);
}

http://www.lryc.cn/news/10876.html

相关文章:

  • 4.如何靠IT逆袭大学?
  • 提供网络可测试的接口【公共Webservice】
  • 【深入理解计算机系统】库打桩 - 阅读笔记
  • RocketMQ高性能原理分析
  • 前端面试当中CDN会问啥------CDN详细教程来啦
  • 刷题记录:牛客NC19429红球进黑洞 区间拆位异或+区间求和
  • 信息数智化招采系统源码——信息数智化招采系统
  • 20230217使AIO-3399J开发板上跑通Android11系统
  • Java 基础面试题——面向对象
  • PDF文件替换内容(电子签章),依赖免费pdfbox
  • nvm 控制 node版本
  • javaEE 初阶 — 传输层 TCP 协议中的异常情况与面向字节流的粘包问题
  • IP路由基础
  • 12.centos7部署sonarqube9.6
  • 大学四年自学Java编程,现在拿到28万年薪的offer,还是觉得挺值的
  • MySQL的日志详解
  • 输出该股票所有收盘比开盘上涨3%以上的日期
  • 数值卡,让数据可视化玩出新花样丨三叠云
  • 有这几个表现可能是认知障碍前兆
  • java面试题-阿里真题详解
  • JSON格式解析关键词搜索API
  • 【Java基础】泛型(二)-泛型的难点:通配符
  • 黑马】后台管理-两个括号的坑
  • 05:进阶篇 - 使用 CTKWidgets
  • 【YOLO V5】代码复现过程
  • 汽车如何实现制动
  • cmake 引入第三方库(头文件目录、库目录、库文件)
  • 插件开发版|Authing 结合 APISIX 实现统一可配置 API 权限网关
  • deepinlinux v20安装rust和tauri并配置vscode开发工具过程
  • 通俗易懂的机器学习——sklearn鸢尾花分类(KNN)