一.Spring Boot中的事务管理
设置事务
@Transactional(isolation = Isolation.DEFAULT)
@Transactional(propagation = Propagation.REQUIRED)
开启事务
@EnableTransactionManagement
1. 开启事务管理
要开启 Spring 的事务管理,你需要在你的 Spring Boot 应用中添加 @EnableTransactionManagement
注解。通常这个注解会放在你的主应用类或者配置类上。
@SpringBootApplication
@EnableTransactionManagement
public class Springboot01CenterTxApplication {
public static void main(String[] args) {
SpringApplication.run(Springboot01CenterTxApplication.class, args);
}
}
2. 使用事务注解
@Transactional
注解可以加在服务类的方法上,表示该方法是一个事务。这个注解可以接收多个参数来控制事务的行为,比如isolation
和propagation
。
@Transactional
@Service
public class CustomerServiceImp implements ICustomerService{
@Resource
private ConsumeMapper mapper;
@Override
public void batchAdd() {
mapper.insert(new Customer(1,"台湾君越酒店","五星级","佩洛西1","12345678"));
int a = 10/0;
mapper.insert(new Customer(2,"台湾君越酒店","五星级","佩洛西1","12345678"));
mapper.insert(new Customer(3,"台湾君越酒店","五星级","佩洛西1","12345678"));
}
}
3. 事务属性
Isolation:定义多个事务之间的隔离级别,主要有以下几个选择:
Isolation.DEFAULT
:使用数据库默认的隔离级别。
Isolation.READ_UNCOMMITTED
:允许读取未提交的数据。
Isolation.READ_COMMITTED
:确保只读取已提交的数据。
Isolation.REPEATABLE_READ
:确保在同一事务中多次读取的数据一致。
Isolation.SERIALIZABLE
:完全隔离的事务,确保每个事务都按照某个顺序执行(性能较低)。Propagation:定义事务的传播行为,主要有以下几种:
Propagation.REQUIRED
:如果当前存在事务,则加入该事务;如果没有事务,则创建新的事务。
Propagation.REQUIRES_NEW
:创建一个新的事务,如果当前存在事务,则将当前事务挂起。
Propagation.NESTED
:如果当前存在事务,则在嵌套事务中执行;否则,就执行与REQUIRED
相同的方式。
Propagation.SUPPORTS
:如果当前存在事务,则加入该事务;否则以非事务方式执行。
Propagation.NOT_SUPPORTED
:以非事务方式执行,挂起当前事务(如果存在)。
Propagation.NEVER
: 不支持事务,如果当前存在事务则会抛出异常。
4. 测试事务
你可以创建测试用例,验证事务的正确性。例如,如果在一个事务中执行了多个数据库操作,而其中一个操作失败,则整个事务应回滚,数据库应保持在失败前的状态。
public void batchAdd() {
mapper.insert(new Customer(1,"台湾君越酒店","五星级","佩洛西1","12345678"));
// int a = 10/0;
mapper.insert(new Customer(2,"台湾君越酒店","五星级","佩洛西1","12345678"));
mapper.insert(new Customer(3,"台湾君越酒店","五星级","佩洛西1","12345678"));
}
public void batchAdd() {
mapper.insert(new Customer(1,"台湾君越酒店","五星级","佩洛西1","12345678"));
int a = 10/0;
mapper.insert(new Customer(2,"台湾君越酒店","五星级","佩洛西1","12345678"));
mapper.insert(new Customer(3,"台湾君越酒店","五星级","佩洛西1","12345678"));
}
二.Spring Boot异步任务
在项目开发中,绝大多数情况下都是通过同步方式处理业务逻辑的,但是比如批量处理数据,批量发送 邮件,批量发送短信等操作 容易造成阻塞的情况,之前大部分都是使用多线程来完成此类任务而在 Spring 3+之后,就已经内置了@Async注解来完美解决这个问题,从而提高效率。
使用的注解
@EnableAsync 启动类上开启基于注解的异步任务
@Async 标识的方法会异步执行
1. 启用异步支持
在你的主应用类或配置类上添加 @EnableAsync
注解。这样 Spring 就会扫描带有 @Async
注解的方法并在异步执行它们。
@SpringBootApplication
@EnableAsync
public class Springboot02CenterAysncApplication {
public static void main(String[] args) {
SpringApplication.run(Springboot02CenterAysncApplication.class, args);
}
}
2. 创建异步方法
在你的服务类中,可以通过 @Async
注解来标记要异步执行的方法。这个方法应该返回 void
或者是 Future
、CompletableFuture
等可用于异步结果的类型。
@Service
public class CustomerServiceImp implements ICustomerService{
@Override
@Async
public void batchAdd() {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("======>批量新增");
}
}
3. 调用异步方法
在其他服务或控制器中,可以调用上述异步方法。注意,由于这些方法是异步执行的,所以调用这些方法后不会等待其完成,调用者会立即继续执行后面的代码。
@RestController
public class CustomrControllerImp {
@Autowired
private ICustomerService service;
@RequestMapping("/add")
public String batchAdd() {
service.batchAdd();
return "成功";
}
}
总结
通过
@EnableAsync
和@Async
注解,Spring 允许你轻松地将方法异步执行,从而提高应用的吞吐量和响应速度。同时,自定义配置线程池也可以使你更好地控制异步任务的执行。使用异步任务时要注意,异步方法不能被同一类中的其他方法直接调用,因为那样不会触发代理,方法会在同一线程中执行。
三.SpringBoot定时任务调度
SpringTask
在项目开发中,经常需要执行一些定时任务,比如 每月1号凌晨需要汇总上个月的数据分析报表; 每天 凌晨分析前一天的日志信息等定时操作。Spring 为我们提供了异步执行定时任务调度的方式
使用的注解
@EnableScheduling启动类上开启基于注解的定时任务
@Scheduled标识的方法会进行定时处理
需要通过 cron 属性来指定 cron 表达式:秒 分 时 日 月 星期 年
在线生成cron表达式 http://cron.qqe2.com/
1. 启用定时任务
在你的主应用类或配置类上添加 @EnableScheduling
注解,以启用 Spring 的定时任务功能。
@SpringBootApplication
@EnableScheduling
public class Springboot03CenterJobApplication {
public static void main(String[] args) {
SpringApplication.run(Springboot03CenterJobApplication.class, args);
}
}
2. 创建定时任务
在你的服务类中,可以使用 @Scheduled
注解来标识需要定时执行的方法。可以通过 cron
属性来指定 cron 表达式。
@Service
public class MyScheduledService {
// 每分钟执行一次
@Scheduled(cron = "0 * * * * ?")
public void executeTaskEveryMinute() {
System.out.println("Executing task every minute: " + System.currentTimeMillis());
}
// 每天凌晨 1 点执行
@Scheduled(cron = "0 0 1 * * ?")
public void executeTaskAtOneAM() {
System.out.println("Executing task at 1 AM: " + System.currentTimeMillis());
}
// 每周一执行
@Scheduled(cron = "0 0 12 ? * MON")
public void executeTaskEveryMonday() {
System.out.println("Executing task every Monday at noon: " + System.currentTimeMillis());
}
}
3. 使用 cron 表达式
cron 表达式的格式如下:
秒 分 时 日 月 星期 年(可选)
- 秒:0-59
- 分:0-59
- 时:0-23
- 日:1-31
- 月:1-12 或者 JAN-DEC
- 星期:1-7(1=星期日)或 SUN-SAT
- 年:1970-2099(可选)
示例 cron 表达式
"0 * * * * ?"
:每分钟执行一次"0 0 1 * * ?"
:每天凌晨 1 点执行"0 0 12 ? * MON"
:每周一中午 12 点执行"0 0/5 * * * ?"
:每 5 分钟执行一次你可以使用在线工具生成和测试 cron 表达式,例如 在线Cron表达式生成器。
总结
通过
@EnableScheduling
和@Scheduled
注解,Spring 提供了一种简单而强大的方式来实现定时任务。你可以根据需要自定义 cron 表达式,以满足不同的调度需求。
四.SpringBoot 整合Mail
第一步添加坐标
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
第二步开启配置
配置邮箱信息
spring.mail.username=
spring.mail.password=
发送邮件服务器
spring.mail.host=smtp.qq.com
spring.mail.username=3058389349
spring.mail.password=topqjgemcudxdfch
spring.mail.host=smtp.qq.com
spring.mail.properties.smtp.ssl.enable=true
第三步编写代码
邮件收发核心类
JavaMailSenderImpl javaMailSender;
封装简单的邮件内容
SimpleMailMessage
封装复杂的邮件(携带附件)
MimeMessage MimeMessageHelper
@SpringBootTest
class Springboot04CenterMailApplicationTests {
@Autowired(required = false)
private JavaMailSenderImpl javaMailSender;
//发送简单邮件
@Test
void show1() {
//1.创建邮件对象
SimpleMailMessage simpleMailMessage=new SimpleMailMessage();
//2.设置信息
simpleMailMessage.setSubject("疫情全面放开");
simpleMailMessage.setText("2022年好难,做了11个月的核酸,结果在第12个月阳了~~~");
simpleMailMessage.setFrom("3058389349@qq.com");
simpleMailMessage.setTo("3418813089@qq.com");
//3.发送邮件
javaMailSender.send(simpleMailMessage);
System.out.println("发送成功!!!");
}
//发送复杂邮件
@Test
void show2() throws MessagingException {
//1.创建邮件对象
MimeMessage mimeMessage = javaMailSender.createMimeMessage();
//2.创建MimeMessageHelper
MimeMessageHelper mimeMessageHelper=new MimeMessageHelper(mimeMessage,true);
//3.设置信息
mimeMessageHelper.setSubject("程序员的误解");
mimeMessageHelper.setText("程序员是个<span style='color:red'>高薪,高危</span>的职业",true);
mimeMessageHelper.addAttachment("pp.jpg",new File("D:\\1\\图片\\pp.jpg"));
mimeMessageHelper.setFrom("3058389349@qq.com");
mimeMessageHelper.setTo("3418813089@qq.com");
//4.发送邮件
javaMailSender.send(mimeMessage);
}
@Test
public void show(){
//1、new Jedis对象即可
Jedis jedis=new Jedis("127.0.0.1",6379);
//jedis所有的命令
System.out.println(jedis.ping());
}
}
五.SpringBoot 整合redis
1、添加坐标
<!-- redis依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>RELEASE</version>
<scope>test</scope>
</dependency>
2、配置Redis
spring.redis.host=localhost
spring.redis.port=6379
3、使用 Redis
//演示1(专用对象)
@Autowired
public RedisTemplate redisTemplate;
//演示2(专用字符串key value均是String)
@Autowired
public StringRedisTemplate stringRedisTemplate;
//演示3(自定义)
@Autowired
public RedisTemplate jsonRedisTemplate;
4. 启动 Redis Server
5. 运行 Spring Boot 应用
StringRedisTemplate(专用字符串key value均是String)
@Autowired
public StringRedisTemplate stringRedisTemplate;
@Test
public void stringRedisTemplate(){
//1.key相关
Set<String> keys = stringRedisTemplate.keys("*");
for (String key : keys) {
System.out.println(key);
}
//2.各种类型支持
stringRedisTemplate.opsForValue();
stringRedisTemplate.opsForList();//List
stringRedisTemplate.opsForHash();//hash
stringRedisTemplate.opsForSet();//set
stringRedisTemplate.opsForZSet();//zset
//3.举例字符串
stringRedisTemplate.opsForValue().set("name","水果");
String name = stringRedisTemplate.opsForValue().get("name");
System.out.println(name);
//4.操作list列表
stringRedisTemplate.opsForList().leftPush("myList","香蕉");
stringRedisTemplate.opsForList().leftPush("myList","苹果");
stringRedisTemplate.opsForList().leftPushAll("mylistAll","苹果","香蕉","香蕉");
List<String> list = stringRedisTemplate.opsForList().range("mylistAll",0,2);
System.out.println(list);
}
RedisTemplate(专用对象)
注意:
1.测试RedisTemplate与stringRedisTemplate存的数据相互独立
2.redisTemplate默认使用key序列化方式和value的序列化方式都使用的是jdk serializer序列化
所以存对象会乱码
@Autowired
public RedisTemplate redisTemplate;
@Test
public void show2(){
ValueOperations valueOperations = redisTemplate.opsForValue();
valueOperations.set("name","蜜蜂");
String name = (String) valueOperations.get("name");
System.out.println(name);
redisTemplate.opsForValue();//String
redisTemplate.opsForList();//List
redisTemplate.opsForHash();//hash
redisTemplate.opsForSet();//set
redisTemplate.opsForZSet();//zset
Student stu1 = new Student(1,"蜜蜂","采蜜");
redisTemplate.opsForValue().set("stu1",stu1);
Student ss1 = (Student)redisTemplate.opsForValue().get("stu1");
System.out.println(ss1);
redisTemplate.opsForList().leftPushAll("mylist","睡觉","游戏");
List<String> list = redisTemplate.opsForList().range("mylist",0,-1);
for (int i = 0; i < list.size(); i++) {
String s = list.get(i);
System.out.println(s);
}
System.out.println("打印默认序列策略"+redisTemplate.getDefaultSerializer());
}
jsonRedisTemplate(自定义)
JsonRedisTemplate
是 Spring Data Redis 提供的一个模板类,专门用于操作 Redis 数据库并以 JSON 格式序列化和反序列化对象。
添加坐标
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
创建 JsonRedisTemplate Bean
然后,你可以创建一个 JsonRedisTemplate
的 Bean。通常,我们会通过 @Configuration
类来配置。
package com.xn.springboot_redis01.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import java.net.UnknownHostException;
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<Object, Object> jsonRedisTemplate(
RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
//1.创建自定义模板类
RedisTemplate<Object, Object> template = new RedisTemplate<Object, Object>();
//配置json类型的序列化工具
template.setKeySerializer(new StringRedisSerializer());//这样key会用字符串方式保存
template.setDefaultSerializer(new Jackson2JsonRedisSerializer<Object>(Object.class));
template.setConnectionFactory(redisConnectionFactory);
return template;
}
}
使用 JsonRedisTemplate
@Autowired
public RedisTemplate jsonRedisTemplate;
@Test
public void show3(){
//保存对象
Student stu = new Student(1,"彭老师","拉面");
jsonRedisTemplate.opsForValue().set("stu",stu);
//获取对象
Object s1 = jsonRedisTemplate.opsForValue().get("stu");
String jsonS1 = JSONObject.toJSONString(s1);
Student s11 = JSONObject.parseObject(jsonS1,Student.class);
System.out.println(s11);
Student stu2 = new Student(2,"彭老师","拉面");
Student stu1 = new Student(2,"彭老师","拉面");
Student stu3 = new Student(2,"彭老师","拉面");
List<Student> students = Arrays.asList(stu1, stu2, stu3);
jsonRedisTemplate.opsForValue().set("stus",students);
//必须Object接受,利用ObjectMapper对象转换,如果强制转换会报错
Object data = jsonRedisTemplate.opsForValue().get("stus");
String dataJson = JSONObject.toJSONString(data);
//将JSON类型转为List
List<Student> stus = JSONObject.parseArray(dataJson, Student.class);
System.out.println(stus);
}