前言
项目中遇到一个检查数据库数据是否过期,并且如果过期的话需要更新字段的功能,当时想到的是数据库的存储过程+定时实现,后续想着很多方法如果能在后端代码实现的话就不用在数据库添加太多功能,所以尝试搜了一下springboot这块是否有这个功能,发现还真有,通过定时任务实现该功能,定时检查是否过期,如果过期更新字段;如果没有过期的则不作任何操作。在此进行简单记录。
参考链接
1. mysql event实现:https://blog.csdn.net/qq_40425961/article/details/82974273
2. SpringBoot实现:
https://blog.csdn.net/J080624/article/details/80959271
https://blog.csdn.net/onedaycbfly/article/details/79093829
实现过程
1. 方法一:MySQL event
1.1 事件简介
事件是MySQL在相应的时刻调用的过程式数据库对象。一个事件可调用一次,也可周期性的启动,由一个特定的线程来管理的,即所谓的“事件调度器”。
事件和触发器类似,都是在某些事情发生的时候启动。当数据库上启动一条语句的时候,触发器就启动了,而事件是根据调度事件来启动的。由于他们彼此相似,所以事件也称为临时性触发器。
1.2 基本用法 参考https://www.cnblogs.com/gaogaoxingxing/p/9909970.html
1.2.1 查看是否开启定时器
SHOW VARIABLES LIKE 'event_scheduler';
1.2.2 开启MySQL定时器
方法一:在my.ini中添加 event_scheduler = ON,
方法二:命令行中输入SET GLOBAL event_scheduler = 1; (1为ON;0为OFF)
SHOW VARIABLES LIKE 'event_scheduler'查看可以看到结果为ON
1.2.3 创建事件
定义事件的运行间隔事件
SQL预览
1.2.4 开启事件
ALTER EVENT expireJudge ON
COMPLETION PRESERVE ENABLE;
1.2.5 关闭事件
ALTER EVENT expireJudge ON
COMPLETION PRESERVE DISABLE;
1.3 测试
开启事件前:
开启事件后:(系统当前时间为16:51,所以只要开启事件就会直接更新两条字段)
2. 方法二:SpringBoot 注解@Scheduled开启定时任务
2.1 @Scheduled定义定时任务
@Component
@Service
public class ScheduleController{
@Autowired
UserMapper userMapper;
// @Scheduled(cron="0 0 0 * * ? *") //每天00:00:00执行一次
// @Scheduled(cron="0 15 15,20 * * 2005 *") //2005年每天15点整合和20点整每隔15分钟执行一次
// @Scheduled(fixedDelay=1000) //距离上次执行结果每1s执行一次
// @Scheduled(initialDelay=1000,fixdRate=6000) //第一次延迟1s,之后每隔6s执行一次
@Scheduled(fixedRate = 60000) //距离项目启动每1分钟执行一次
public void expireTimeJudge(){
//首先拿到所有的过期且expire=0的条目
List<User> userList = userMapper.selectExpiredUser(new Date());
if(userList.isEmpty()){
logger.info("没有需要更新的过期用户");
return;
}
//遍历更新expire=1
for(User user : userList){
user.setExpired(1);
int update = userMapper.update(user);
if(update!=0){
logger.info("{} : 更新成功,已过期",user.getUsername());
}else {
logger.info("{} : 更新失败",user.getUsername());
}
}
}
}
MyBatis中进行时间大小判断可使用CDATA标签,可解析XML解析器解析不了的文本数据
在 XML 元素中,"<" 和 "&" 是非法的。为了避免错误,可以将脚本代码定义为 CDATA。
CDATA 部分中的所有内容都会被解析器忽略。由 "<![CDATA[" 开始,由 "]]>" 结束,
如果遇到特殊字符,将包含sql语句用CDATA包裹住即可不被解析器解析
<select id="selectExpired" parameterType="java.util.Date" resultType="com..User">
select *
from user
where user.expired=0
and <![CDATA[user.expire_time <= #{date}]]>;
</select>
2.2 @EableScheduling开启定时任务
@EnableScheduling //定时器注解
//@EnableRedisHttpSession
public class UseApplication {
public static void main(String[] args) {
SpringApplication.run(UserApplication.class, args);
}
}
2.3 加入并行线程机制
/**
* 定时任务的并行实现,目前为3个线程
*/
@Configuration
public class ScheduledConfig implements SchedulingConfigurer {
@Override
public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
scheduledTaskRegistrar.setScheduler(setTaskExecutors());
}
@Bean
public Executor setTaskExecutors(){
return Executors.newScheduledThreadPool(3);
}
}
2.4 测试(每1s执行一次)
2.4.1 未加入并行机制,串行定时结果
2.4.2 加入并行机制,并行定时结果
总结
一般不需要也尽量别对数据库直接加事务、触发器、事件等操作(如果是集成的数据库-后端都有的项目的话),有想法多搜集资料查一查,边查边实践边学习边总结进步~