主键传回
@Options(useGeneratedKeys = true, keyProperty = "id")的作用:
在 MyBatis 中,@Options(useGeneratedKeys = true, keyProperty = "id") 注解通常用于 插入(Insert)操作 的方法上,其核心作用是:
让 MyBatis 获取数据库自动生成的主键(如自增主键),并将该主键值回填到传入的实体对象的对应属性中。
@Insert("INSERT INTO user(name) VALUES(#{name})")
@Options(useGeneratedKeys = true, keyProperty = "id")
Integer insert(User user);
调用后,user.getId() 就能获取到自增的 ID。
<foreach>

Mybatis中的动态SQL里提供的 <foreach> 标签,该标签的作用,是用来遍历循环,常见的属性说明:
- collection:集合名称
- item:集合遍历出来的元素/项
- separator:每一次遍历使用的分隔符
- open:遍历开始前拼接的片段
- close:遍历结束后拼接的片段
事物
使用
事务控制主要三步操作:开启事务、提交事务/回滚事务。
- 需要在这组操作执行之前,先开启事务 (
start transaction; / begin;)。 - 所有操作如果全部都执行成功,则提交事务 (
commit;)。 - 如果这组操作中,有任何一个操作执行失败,都应该回滚事务 (
rollback)。
-- 开启事务
start transaction; / begin;
-- 1. 保存员工基本信息
insert into emp values (39, 'Tom', '123456', '汤姆', 1, '13300001111', 1, 4000, '1.jpg', '2023-11-01', 1, now(), now());
-- 2. 保存员工的工作经历信息
insert into emp_expr(emp_id, begin, end, company, job) values (39,'2019-01-01', '2020-01-01', '百度', '开发'), (39,'2020-01-10', '2022-02-01', '阿里', '架构');
-- 提交事务(全部成功)
commit;
-- 回滚事务(有一个失败)
rollback;
事务四大特性
- 原子性(Atomicity) :原子性是指事务包装的一组sql是一个不可分割的工作单元,事务中的操作要么全部成功,要么全部失败。
- 一致性(Consistency):一个事务完成之后数据都必须处于一致性状态。
- 如果事务成功的完成,那么数据库的所有变化将生效。
- 如果事务执行出现错误,那么数据库的所有变化将会被回滚(撤销),返回到原始状态。
- 隔离性(Isolation):多个用户并发的访问数据库时,一个用户的事务不能被其他用户的事务干扰,多个并发的事务之间要相互隔离。
- 一个事务的成功或者失败对于其他的事务是没有影响。
- 持久性(Durability):一个事务一旦被提交或回滚,它对数据库的改变将是永久性的,哪怕数据库发生异常,重启之后数据亦然存在。
@Transactional
位置:业务层的方法上、类上、接口上
- 方法上:当前方法交给spring进行事务管理
- 类上:当前类中所有的方法都交由spring进行事务管理
- 接口上:接口下所有的实现类当中所有的方法都交给spring 进行事务管理
默认情况下,只有出现RuntimeException(运行时异常)才会回滚事务。
rollbackFor
假如我们想让所有的异常都回滚,需要来配置@Transactional注解当中的rollbackFor属性,通过rollbackFor这个属性可以指定出现何种异常类型回滚事务。
@Transactional(rollbackFor = Exception.class)
@Override
public void save(Emp emp) throws Exception {
//1.补全基础属性
emp.setCreateTime(LocalDateTime.now());
emp.setUpdateTime(LocalDateTime.now());
//2.保存员工基本信息
empMapper.insert(emp);
//int i = 1/0;
if(true){
throw new Exception("出异常啦....");
}
//3. 保存员工的工作经历信息 - 批量
Integer empId = emp.getId();
List<EmpExpr> exprList = emp.getExprList();
if(!CollectionUtils.isEmpty(exprList)){
exprList.forEach(empExpr -> empExpr.setEmpId(empId));
empExprMapper.insertBatch(exprList);
}
}
Propagation
@Service
public class EmpLogServiceImpl implements EmpLogService {
@Autowired
private EmpLogMapper empLogMapper;
@Transactional(propagation = Propagation.REQUIRES_NEW)
//不论是否有事务,都创建新事务 ,运行在一个独立的事务中
@Override
public void insertLog(EmpLog empLog) {
empLogMapper.insert(empLog);
}
}
- REQUIRED:大部分情况下都是用该传播行为即可。
- REQUIRES_NEW:当我们不希望事务之间相互影响时,可以使用该传播行为。比如:下订单前需要记录日志,不论订单保存成功与否,都需要保证日志记录能够记录成功。
| 属性值 | 含义 |
| REQUIRED | 【默认值】需要事务,有则加入,无则创建新事务 |
| REQUIRES_NEW | 需要新事务,无论有无,总是创建新事务 |
| SUPPORTS | 支持事务,有则加入,无则在无事务状态中运行 |
| NOT_SUPPORTED | 不支持事务,在无事务状态下运行,如果当前存在已有事务,则挂起当前事务 |
| MANDATORY | 必须有事务,否则抛异常 |
| NEVER | 必须没事务,否则抛异常 |
事物管理日志
可以在application.yml配置文件中开启事务管理日志,这样就可以在控制看到和事务相关的日志信息了
#spring事务管理日志
logging:
level:
org.springframework.jdbc.support.JdbcTransactionManager: debug
@Value
示例:
#appllication.yaml
aliyun:
oss:
endpoint: https://oss-cn-hangzhou.aliyuncs.com
bucketName: hozuki
region: cn-hangzhou
@Component
public class AliyunOSSOperator {
@Value("${aliyun.oss.endpoint}")
private String endpoint;
@Value("${aliyun.oss.bucketName}")
private String bucketName;
@Value("${aliyun.oss.region}")
private String region;
}
@Value简化
1). 需要创建一个实现类,且实体类中的属性名和配置文件当中key的名字必须要一致
比如:配置文件当中叫endpoint,实体类当中的属性也得叫endpoint,另外实体类当中的属性还需要提供 getter / setter方法
2). 需要将实体类交给Spring的IOC容器管理,成为IOC容器当中的bean对象
3). 在实体类上添加@ConfigurationProperties注解,并通过perfect属性来指定配置参数项的前缀
package site.suiyue.utils;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Data
@Component
@ConfigurationProperties(prefix = "aliyun.oss")
public class AliyunOSSProperties {
private String endpoint;
private String bucketName;
private String region;
}
package site.suiyue.utils;
import com.aliyun.oss.*;
import com.aliyun.oss.common.auth.CredentialsProviderFactory;
import com.aliyun.oss.common.auth.EnvironmentVariableCredentialsProvider;
import com.aliyun.oss.common.comm.SignVersion;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.io.ByteArrayInputStream;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.UUID;
@Component
public class AliyunOSSOperator {
// @Value("${aliyun.oss.endpoint}")
// private String endpoint;
// @Value("${aliyun.oss.bucketName}")
// private String bucketName;
// @Value("${aliyun.oss.region}")
// private String region;
@Autowired
private AliyunOSSProperties aliyunOSSProperties;
public String upload(byte[] content, String originalFilename) throws Exception {
String endpoint = aliyunOSSProperties.getEndpoint();
String bucketName = aliyunOSSProperties.getBucketName();
String region = aliyunOSSProperties.getRegion();
// 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
// 填写Object完整路径,例如202406/1.png。Object完整路径中不能包含Bucket名称。
//获取当前系统日期的字符串,格式为 yyyy/MM
String dir = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy/MM"));
//生成一个新的不重复的文件名
String newFileName = UUID.randomUUID() + originalFilename.substring(originalFilename.lastIndexOf("."));
String objectName = dir + "/" + newFileName;
// 创建OSSClient实例。
ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
clientBuilderConfiguration.setSignatureVersion(SignVersion.V4);
OSS ossClient = OSSClientBuilder.create()
.endpoint(endpoint)
.credentialsProvider(credentialsProvider)
.clientConfiguration(clientBuilderConfiguration)
.region(region)
.build();
try {
ossClient.putObject(bucketName, objectName, new ByteArrayInputStream(content));
} finally {
ossClient.shutdown();
}
return endpoint.split("//")[0] + "//" + bucketName + "." + endpoint.split("//")[1] + "/" + objectName;
}
}
文件上传
package site.suiyue.controller;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import site.suiyue.pojo.Result;
import site.suiyue.utils.AliyunOSSOperator;
import java.io.File;
import java.io.IOException;
import java.util.UUID;
@Slf4j
@RestController
public class UploadController {
@Autowired
private AliyunOSSOperator aliyunOSSOperator;
@PostMapping("/upload")
public Result upload(MultipartFile file) throws Exception {
log.info("上传文件:{}", file);
if (!file.isEmpty()) {
// 生成唯一文件名
String originalFilename = file.getOriginalFilename();
String extName = originalFilename.substring(originalFilename.lastIndexOf("."));
String uniqueFileName = UUID.randomUUID().toString().replace("-", "") + extName;
// 上传文件
String url = aliyunOSSOperator.upload(file.getBytes(), uniqueFileName);
return Result.success(url);
}
return Result.error("上传失败");
}
}
Comments NOTHING