場景:
在之前做的考勤系統(tǒng)借卧,有個考勤配置的功能,需要從周一到周天每天設(shè)置一個開關(guān)來支持每天是否開啟考勤筛峭。當時實現(xiàn)這個功能覺得 so easy! 铐刘,但最近突然想到了一個自己覺得更加簡單的實現(xiàn)方式,順便記錄下影晓,下面是兩種實現(xiàn)方式镰吵。
舊數(shù)據(jù)庫設(shè)計
這個是我最初的實現(xiàn)方式,創(chuàng)建了兩張表挂签,保存考勤配置信息的考勤配置表疤祭,關(guān)聯(lián)考勤配置表保存開關(guān)信息的開關(guān)表。然后添加周一到周天7條記錄饵婆,每條記錄對應(yīng)每天是否開啟考勤勺馆。下面是表結(jié)構(gòu):
- 考勤配置表(cfg_attend)
FEILD | TYPE | LENGTH | PRIMARY | NULL | REMARK |
---|---|---|---|---|---|
id | char | 32 | 是 | 否 | 主鍵ID |
tenant_id | char | 32 | 是 | 否 | 租戶ID |
start_time | time | 0 | 否 | 是 | 上學(xué)考勤時間(如9:00) |
late_minutes | int | 11 | 否 | 是 | 遲到時間(單位分鐘) |
end_time | time | 0 | 否 | 是 | 放學(xué)考勤時間(如12:00) |
early_minutes | int | 11 | 否 | 是 | 早退時間(單位為分鐘) |
creator_id | char | 32 | 否 | 是 | 創(chuàng)建人ID |
create_time | datetime | 0 | 否 | 是 | 創(chuàng)建時間 |
modify_time | datetime | 0 | 否 | 是 | 更新時間 |
deleted | tinyint | 4 | 否 | 否 | 刪除標記(0-未刪除 1-已刪除) |
- 考勤開關(guān)表(cfg_week_on)
FEILD | TYPE | LENGTH | PRIMARY | NULL | REMARK |
---|---|---|---|---|---|
id | char | 32 | 是 | 否 | 主鍵ID |
ca_id | char | 32 | 是 | 否 | 配置表ID |
week_day | tinyint | 4 | 是 | 否 | 周幾 |
on | tinyint | 4 | 否 | 否 | 是否開啟考勤(0-未開啟 1-開啟) |
creator_id | char | 32 | 否 | 是 | 創(chuàng)建人ID |
create_time | datetime | 0 | 否 | 是 | 創(chuàng)建時間 |
modify_time | datetime | 0 | 否 | 是 | 更新時間 |
deleted | tinyint | 4 | 否 | 否 | 刪除標記(0-未刪除 1-已刪除) |
在這個設(shè)計中,我們需要從數(shù)據(jù)庫查詢出考勤配置以及對應(yīng)的開關(guān)表數(shù)據(jù)侨核,然后根據(jù)開關(guān)字段判斷是否開啟考勤谓传。實現(xiàn)代碼如下:
- 查詢出考勤配置表數(shù)據(jù)
select * from cfg_attend where deleted = 0 and tenant_id = {租戶ID}
- 獲取當天周幾
int weekDay = LocalDate.now().getDayOfWeek().getValue(); // 當天為周幾
- 根據(jù)配置表ID和周幾去查詢出考勤配置對應(yīng)的開關(guān)數(shù)據(jù)
select * from cfg_week_on where deleted = 0 and ca_id = {配置表ID} and week_day = {周幾}
- 使用字段 on 判斷是否開啟了考勤
public static boolean currentAttendIsOn(int on) {
return on == 1;
}
新數(shù)據(jù)庫設(shè)計:
在這個實現(xiàn)方式中去除了考勤開關(guān)表,在考勤配置表中添加了有效星期幾字段來存儲考勤開關(guān)芹关。下面是表結(jié)構(gòu):
- 考勤配置表(cfg_attend)
FEILD | TYPE | LENGTH | PRIMARY | NULL | REMARK |
---|---|---|---|---|---|
id | char | 32 | 是 | 否 | 主鍵ID |
tenant_id | char | 32 | 是 | 否 | 租戶ID |
start_time | time | 0 | 否 | 是 | 上學(xué)考勤時間(如9:00) |
late_minutes | int | 11 | 否 | 是 | 遲到時間(單位分鐘) |
end_time | time | 0 | 否 | 是 | 放學(xué)考勤時間(如12:00) |
early_minutes | int | 11 | 否 | 是 | 早退時間(單位為分鐘) |
week_days | char | 7 | 否 | 是 | 有效星期幾,如0011111紧卒,表示周六侥衬、周日不生效 |
creator_id | char | 32 | 否 | 否 | 創(chuàng)建人ID |
create_time | datetime | 0 | 否 | 否 | 創(chuàng)建時間 |
modify_time | datetime | 0 | 否 | 否 | 更新時間 |
deleted | tinyint | 4 | 否 | 是 | 刪除標記(0-未刪除 1-已刪除) |
在這個設(shè)計中,我們只需要從數(shù)據(jù)庫查詢出考勤配置 跑芳,然后根據(jù)有效星期幾字段進行位運算即可判斷出是否開啟考勤轴总。實現(xiàn)代碼如下:
- 查詢出考勤配置表數(shù)據(jù)
select * from cfg_attend where deleted = 0 and tenant_id = {租戶ID}
- 使用字段 week_days 判斷是否開啟了考勤
public static boolean currentAttendIsOn(String weekDays) {
// 傳入的字符串從左往右一次代表周一到周天,但是我們計算的時候是需要從右到左
// String reverseWeekDays = new StringBuilder(weekDays).reverse().toString();
int weekDay = LocalDate.now().getDayOfWeek().getValue(); // 當天為周幾
int weekDaysValue = Integer.parseInt(weekDays, 2); // 二進制轉(zhuǎn)換位整數(shù)
int currentDayValue = 1 << (weekDay - 1);
return (weekDaysValue & currentDayValue) == currentDayValue;
}
對比兩種實現(xiàn)方式博个,可以發(fā)現(xiàn):
- 第一種實現(xiàn)多一張數(shù)據(jù)庫表怀樟,且多一次數(shù)據(jù)庫操作,效率稍低盆佣,但是簡單易懂往堡;
- 第二種實現(xiàn)少一張數(shù)據(jù)庫表械荷,且只需一次數(shù)據(jù)庫操作,效率較高虑灰,但需要會位運算吨瞎;