网站实施方案,做外卖有哪些网站有哪些,国内网站建设的趋势是怎样的,免费注册帐号qq例子#xff1a; 举例#xff1a;假设我们有一个文件上传的uploadFile方法#xff0c;在这个方法中我们会先执行上传一个文件到分布式文件系统中的方法addMediaFilesToMinIO( )#xff0c;上传成功后执行文件资源数据入库的addMediaFilesToDb( ),那么这个时候事务应该加在哪… 例子 举例假设我们有一个文件上传的uploadFile方法在这个方法中我们会先执行上传一个文件到分布式文件系统中的方法addMediaFilesToMinIO( )上传成功后执行文件资源数据入库的addMediaFilesToDb( ),那么这个时候事务应该加在哪个方法上 是否会有事务失效的问题 问题引出 先说结论我们只将addMediaFilesToDb方法添加事务控制即可,uploadFile方法上的不需要加Transactional注解只给与本地数据库进行网络传输的方法加相应的注解在开发时不同的网络传输方法要抽离成单独的方法但是要注意事务生效的条件。 正常情况下我们在外部uploadFile方法上加会生效但是直接将Transactional加在addMediaFilesToDb( )事务会失效问题出在哪里呢 原因分析
如果在uploadFile方法上添加Transactional注解代理对象执行此方法前会开启事务如下图 如果在uploadFile方法上没有Transactional注解代理对象执行此方法前不进行事务控制如下图 所以判断该方法是否可以事务控制必须保证是通过代理对象调用此方法且此方法上添加了Transactional注解。
现在在addMediaFilesToDb方法上添加Transactional注解也不会进行事务控制是因为并不是通过代理对象执行的addMediaFilesToDb方法。为了判断在uploadFile方法中去调用addMediaFilesToDb方法是否是通过代理对象去调用我们可以打断点跟踪。 我们发现在uploadFile方法中去调用addMediaFilesToDb方法不是通过代理对象去调用。
如何解决呢通过代理对象去调用addMediaFilesToDb方法即可解决。
先将addMediaFilesToDb方法提成接口 /*** description 将文件信息添加到文件表* param companyId 机构id* param fileMd5 文件md5值* param uploadFileParamsDto 上传文件的信息* param bucket 桶* param objectName 对象名称* return com.xuecheng.media.model.po.MediaFiles* author Mr.M* date 2022/10/12 21:22*/public MediaFiles addMediaFilesToDb(Long companyId,String fileMd5,UploadFileParamsDto uploadFileParamsDto,String bucket,String objectName);
在MediaFileService的实现类中注入MediaFileService的代理对象注入自己交托spring管理成为代理对象如下
Autowired
MediaFileService currentProxy;
在uploadFile方法中将调用addMediaFilesToDb方法处代码改为
MediaFiles mediaFiles currentProxy.addMediaFilesToDb(companyId, fileMd5, uploadFileParamsDto, bucket_files, objectName);
再次debug可以看到对象为代理对象并且可以通过加入int i 1/0观察十五是否回滚测试addMediaFilesToDb上加事务是否生效。 完整代码
package com.xuecheng.media.service.impl;import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.j256.simplemagic.ContentInfo;
import com.j256.simplemagic.ContentInfoUtil;
import com.xuecheng.base.exception.XueChengPlusException;
import com.xuecheng.base.model.PageParams;
import com.xuecheng.base.model.PageResult;
import com.xuecheng.media.mapper.MediaFilesMapper;
import com.xuecheng.media.model.dto.QueryMediaParamsDto;
import com.xuecheng.media.model.dto.UploadFileParamsDto;
import com.xuecheng.media.model.dto.UploadFileResultDto;
import com.xuecheng.media.model.po.MediaFiles;
import com.xuecheng.media.service.MediaFileService;
import io.minio.MinioClient;
import io.minio.UploadObjectArgs;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;import java.io.File;
import java.io.FileInputStream;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.List;/*** author Mr.M* version 1.0* description TODO* date 2022/9/10 8:58*/
Slf4j
Service
public class MediaFileServiceImpl implements MediaFileService {AutowiredMediaFilesMapper mediaFilesMapper;AutowiredMinioClient minioClient;AutowiredMediaFileService currentProxy;
// 存储普通文件Value(${minio.bucket.files})private String bucket_files;
// 存储视频文件Value(${minio.bucket.videofiles})private String bucket_video;//普通文件桶Value(${minio.bucket.files})private String bucket_Files;Overridepublic PageResultMediaFiles queryMediaFiels(Long companyId, PageParams pageParams, QueryMediaParamsDto queryMediaParamsDto) {//构建查询条件对象LambdaQueryWrapperMediaFiles queryWrapper new LambdaQueryWrapper();//分页对象PageMediaFiles page new Page(pageParams.getPageNo(), pageParams.getPageSize());// 查询数据内容获得结果PageMediaFiles pageResult mediaFilesMapper.selectPage(page, queryWrapper);// 获取数据列表ListMediaFiles list pageResult.getRecords();// 获取数据总数long total pageResult.getTotal();// 构建结果集PageResultMediaFiles mediaListResult new PageResult(list, total, pageParams.getPageNo(), pageParams.getPageSize());return mediaListResult;}//获取文件默认存储目录路径 年/月/日private String getDefaultFolderPath() {SimpleDateFormat sdf new SimpleDateFormat(yyyy-MM-dd);String folder sdf.format(new Date()).replace(-, /) /;return folder;}//获取文件的md5private String getFileMd5(File file) {try (FileInputStream fileInputStream new FileInputStream(file)) {String fileMd5 DigestUtils.md5Hex(fileInputStream);return fileMd5;} catch (Exception e) {e.printStackTrace();return null;}}/*** 根据扩展名获取MimeType* param extension* return*/private String getMimeType(String extension) {if (extension null) {extension ;}//根据扩展名取出mimeTypeContentInfo extensionMatch ContentInfoUtil.findExtensionMatch(extension);//通用mimeType字节流String mimeType MediaType.APPLICATION_OCTET_STREAM_VALUE;if (extensionMatch ! null) {mimeType extensionMatch.getMimeType();}return mimeType;}/*** 将文件上传到minio* param localFilePath 文件地址* param bucket 桶* param objectName 对象名称* return void* description 将文件写入minIO* author Mr.M* date 2022/10/12 21:22*/public boolean addMediaFilesToMinIO(String localFilePath, String mimeType, String bucket, String objectName) {try {UploadObjectArgs testbucket UploadObjectArgs.builder().bucket(bucket).object(objectName).filename(localFilePath).contentType(mimeType).build();minioClient.uploadObject(testbucket);log.debug(上传文件到minio成功,bucket:{},objectName:{}, bucket, objectName);System.out.println(上传成功);return true;} catch (Exception e) {e.printStackTrace();log.error(上传文件到minio出错,bucket:{},objectName:{},错误原因:{}, bucket, objectName, e.getMessage(), e);XueChengPlusException.cast(上传文件到文件系统失败);}return false;}/*** param companyId 机构id* param fileMd5 文件md5值* param uploadFileParamsDto 上传文件的信息* param bucket 桶* param objectName 对象名称* return com.xuecheng.media.model.po.MediaFiles* description 将文件信息添加到文件表* author Mr.M* date 2022/10/12 21:22*/OverrideTransactional // 在这里加注解public MediaFiles addMediaFilesToDb(Long companyId, String fileMd5, UploadFileParamsDto uploadFileParamsDto, String bucket, String objectName) {//从数据库查询文件MediaFiles mediaFiles mediaFilesMapper.selectById(fileMd5);if (mediaFiles null) {mediaFiles new MediaFiles();//拷贝基本信息BeanUtils.copyProperties(uploadFileParamsDto, mediaFiles);mediaFiles.setId(fileMd5);mediaFiles.setFileId(fileMd5);mediaFiles.setCompanyId(companyId);mediaFiles.setUrl(/ bucket / objectName);mediaFiles.setBucket(bucket);mediaFiles.setFilePath(objectName);mediaFiles.setCreateDate(LocalDateTime.now());mediaFiles.setAuditStatus(002003);mediaFiles.setStatus(1);//保存文件信息到文件表int insert mediaFilesMapper.insert(mediaFiles);if (insert 0) {log.error(保存文件信息到数据库失败,{}, mediaFiles.toString());XueChengPlusException.cast(保存文件信息失败);return null;}log.debug(保存文件信息到数据库成功,{}, mediaFiles.toString());}return mediaFiles;}/*** 上传文件** param companyId 机构id* param uploadFileParamsDto 上传文件信息* param localFilePath 文件磁盘路径* return*/
// Transactional 不要给这个方法加事务注解细化到数据库传输方法加Overridepublic UploadFileResultDto uploadFile(Long companyId, UploadFileParamsDto uploadFileParamsDto, String localFilePath) {File file new File(localFilePath);if (!file.exists()) {XueChengPlusException.cast(文件不存在);}//文件名称String filename uploadFileParamsDto.getFilename();//文件扩展名String extension filename.substring(filename.lastIndexOf(.));//文件mimeTypeString mimeType getMimeType(extension);//文件的md5值String fileMd5 getFileMd5(file);//文件的默认目录String defaultFolderPath getDefaultFolderPath();//存储到minio中的对象名(带目录)String objectName defaultFolderPath fileMd5 extension;//将文件上传到minioboolean result addMediaFilesToMinIO(localFilePath, mimeType, bucket_files, objectName);if (!result){XueChengPlusException.cast(上传文件失败);}//文件大小uploadFileParamsDto.setFileSize(file.length());//将文件信息存储到数据库MediaFiles mediaFiles currentProxy.addMediaFilesToDb(companyId, fileMd5, uploadFileParamsDto, bucket_files, objectName);if (nullmediaFiles){XueChengPlusException.cast(文件上传后保存信息失败);}//准备返回数据UploadFileResultDto uploadFileResultDto new UploadFileResultDto();BeanUtils.copyProperties(mediaFiles, uploadFileResultDto);return uploadFileResultDto;}
}结论 在使用事务注解的时候要考虑与三方等网络传输的效率等问题正确的使用事务。