场景:
在之前做的考勤系统,有个考勤配置的功能,需要从周一到周天每天设置一个开关来支持每天是否开启考勤。当时实现这个功能觉得 so easy! ,但最近突然想到了一个自己觉得更加简单的实现方式,顺便记录下,下面是两种实现方式。
旧数据库设计
这个是我最初的实现方式,创建了两张表,保存考勤配置信息的考勤配置表,关联考勤配置表保存开关信息的开关表。然后添加周一到周天7条记录,每条记录对应每天是否开启考勤。下面是表结构:
- 考勤配置表(cfg_attend)
FEILD | TYPE | LENGTH | PRIMARY | NULL | REMARK |
---|---|---|---|---|---|
id | char | 32 | 是 | 否 | 主键ID |
tenant_id | char | 32 | 是 | 否 | 租户ID |
start_time | time | 0 | 否 | 是 | 上学考勤时间(如9:00) |
late_minutes | int | 11 | 否 | 是 | 迟到时间(单位分钟) |
end_time | time | 0 | 否 | 是 | 放学考勤时间(如12:00) |
early_minutes | int | 11 | 否 | 是 | 早退时间(单位为分钟) |
creator_id | char | 32 | 否 | 是 | 创建人ID |
create_time | datetime | 0 | 否 | 是 | 创建时间 |
modify_time | datetime | 0 | 否 | 是 | 更新时间 |
deleted | tinyint | 4 | 否 | 否 | 删除标记(0-未删除 1-已删除) |
- 考勤开关表(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 | 否 | 是 | 创建人ID |
create_time | datetime | 0 | 否 | 是 | 创建时间 |
modify_time | datetime | 0 | 否 | 是 | 更新时间 |
deleted | tinyint | 4 | 否 | 否 | 删除标记(0-未删除 1-已删除) |
在这个设计中,我们需要从数据库查询出考勤配置以及对应的开关表数据,然后根据开关字段判断是否开启考勤。实现代码如下:
- 查询出考勤配置表数据
select * from cfg_attend where deleted = 0 and tenant_id = {租户ID}
- 获取当天周几
int weekDay = LocalDate.now().getDayOfWeek().getValue(); // 当天为周几
- 根据配置表ID和周几去查询出考勤配置对应的开关数据
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;
}
新数据库设计:
在这个实现方式中去除了考勤开关表,在考勤配置表中添加了有效星期几字段来存储考勤开关。下面是表结构:
- 考勤配置表(cfg_attend)
FEILD | TYPE | LENGTH | PRIMARY | NULL | REMARK |
---|---|---|---|---|---|
id | char | 32 | 是 | 否 | 主键ID |
tenant_id | char | 32 | 是 | 否 | 租户ID |
start_time | time | 0 | 否 | 是 | 上学考勤时间(如9:00) |
late_minutes | int | 11 | 否 | 是 | 迟到时间(单位分钟) |
end_time | time | 0 | 否 | 是 | 放学考勤时间(如12:00) |
early_minutes | int | 11 | 否 | 是 | 早退时间(单位为分钟) |
week_days | char | 7 | 否 | 是 | 有效星期几,如0011111,表示周六、周日不生效 |
creator_id | char | 32 | 否 | 否 | 创建人ID |
create_time | datetime | 0 | 否 | 否 | 创建时间 |
modify_time | datetime | 0 | 否 | 否 | 更新时间 |
deleted | tinyint | 4 | 否 | 是 | 删除标记(0-未删除 1-已删除) |
在这个设计中,我们只需要从数据库查询出考勤配置 ,然后根据有效星期几字段进行位运算即可判断出是否开启考勤。实现代码如下:
- 查询出考勤配置表数据
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); // 二进制转换位整数
int currentDayValue = 1 << (weekDay - 1);
return (weekDaysValue & currentDayValue) == currentDayValue;
}
对比两种实现方式,可以发现:
- 第一种实现多一张数据库表,且多一次数据库操作,效率稍低,但是简单易懂;
- 第二种实现少一张数据库表,且只需一次数据库操作,效率较高,但需要会位运算;
网友评论