一.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{@Resourceprivate ConsumeMapper mapper;@Overridepublic 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@Asyncpublic void batchAdd() {try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("======>批量新增");}
}
3. 调用异步方法
在其他服务或控制器中,可以调用上述异步方法。注意,由于这些方法是异步执行的,所以调用这些方法后不会等待其完成,调用者会立即继续执行后面的代码。
@RestController
public class CustomrControllerImp {@Autowiredprivate 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;//发送简单邮件@Testvoid 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("发送成功!!!");}//发送复杂邮件@Testvoid show2() throws MessagingException {//1.创建邮件对象MimeMessage mimeMessage = javaMailSender.createMimeMessage();//2.创建MimeMessageHelperMimeMessageHelper 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);}@Testpublic 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(专用对象)@Autowiredpublic RedisTemplate redisTemplate;//演示2(专用字符串key value均是String)@Autowiredpublic StringRedisTemplate stringRedisTemplate;//演示3(自定义)@Autowiredpublic RedisTemplate jsonRedisTemplate;
4. 启动 Redis Server
5. 运行 Spring Boot 应用
StringRedisTemplate(专用字符串key value均是String)
@Autowiredpublic StringRedisTemplate stringRedisTemplate;
@Testpublic void stringRedisTemplate(){//1.key相关Set<String> keys = stringRedisTemplate.keys("*");for (String key : keys) {System.out.println(key);}//2.各种类型支持stringRedisTemplate.opsForValue();stringRedisTemplate.opsForList();//ListstringRedisTemplate.opsForHash();//hashstringRedisTemplate.opsForSet();//setstringRedisTemplate.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序列化
所以存对象会乱码
@Autowiredpublic RedisTemplate redisTemplate;
@Testpublic void show2(){ValueOperations valueOperations = redisTemplate.opsForValue();valueOperations.set("name","蜜蜂");String name = (String) valueOperations.get("name");System.out.println(name);redisTemplate.opsForValue();//StringredisTemplate.opsForList();//ListredisTemplate.opsForHash();//hashredisTemplate.opsForSet();//setredisTemplate.opsForZSet();//zsetStudent 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 {@Beanpublic 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
@Autowiredpublic RedisTemplate jsonRedisTemplate;@Testpublic 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类型转为ListList<Student> stus = JSONObject.parseArray(dataJson, Student.class);System.out.println(stus);}