前言
項目中遇到一個檢查數據庫數據是否過期,並且如果過期的話需要更新字段的功能,當時想到的是數據庫的存儲過程+定時實現,後續想着很多方法如果能在後端代碼實現的話就不用在數據庫添加太多功能,所以嘗試搜了一下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 加入並行機制,並行定時結果
總結
一般不需要也儘量別對數據庫直接加事務、觸發器、事件等操作(如果是集成的數據庫-後端都有的項目的話),有想法多蒐集資料查一查,邊查邊實踐邊學習邊總結進步~