前言
作者在使用Mybatis+Spring Boot框架的时候,遇到了一个需求,就是定期汇总3个用户分表中的数据去重后进行后期处理,实现思路比较简单,但是有一些需要注意的地方。
相关sql
作者对sql语言仅有一定的基础,所以提出的方案未必最优,但是可以解决当前的问题。
对于3个用户表user,user1和user2,可以这样写——
select * from user union select * from user1 union select * from user2
union 和union all的区别
最大的区别就是union对于并集同时完成了去重的操作,相当于使用了distinct,而union all只取并集,不进行任何其他操作。
结合Spring Boot框架
松耦合配置
作者使用了Spring Boot框架,故可以通过配置文件和@ConfigurationProperties注解方便地将所有的表名注入到一个String类型的List中,以供下一步使用。
![](https://img-blog.csdnimg.cn/img_convert/ecb8ab865f48cb1ca9f8744ad8ac2a88.png)
其中prefix属性表示类中的所有属性都来自于application.yml/application.properties中的sql,如tableList就对应sql.tableList=XXX。
使用foreach标签完成需求
作为Mybatis中最为强大的标签之一的foreach标签,它可以灵活地完成各种批量、循环相关的数据库需求。
我们观察上面的sql语句,发现联合查询中共同的是select * from和union,不同的是表名。结合foreach标签的各个属性我们可以这么做。
<select id="selectAllCrossTable" useCache="false" flushCache="false" resultType="com.school.springboot.entity.User">
select * from user union all
<foreach collection="list" item="table" separator="union">
select * from ${table}
</foreach>
</select>
将表名通过${table}注入,使用union作为不同select语句的分隔符,最终就可以得到这样的sql语句
select * from user union select * from user1 union select * from user2
Mapper层
@Mapper
public interface UserMapper extends BaseMapper<User> {
List<User> selectAllCrossTable(List<String> list);
}
Service层
@Service(value = "userService")
@SuppressWarnings("all")
@Transactional(rollbackFor = Exception.class, isolation = Isolation.DEFAULT)
@RequiredArgsConstructor
@ConfigurationProperties(prefix = "sql")
@Data
public class UserService {
private List<String> tableList;
private final UserMapper userMapper;
private final RedisTemplate firstRedisTemplate;
//...其他的业务逻辑代码
public List<User> selectAllCrossTable() {
return userMapper.selectAllCrossTable(tableList);
}
}
Controller层
@Slf4j
@RestController
@SuppressWarnings("all")
@RequestMapping(value = "/user")
@CrossOrigin
public class UserController {
@Autowired
private UserService userService;
// @RequiresGuest
@ResponseBody
@RequestMapping(value = "/crossTable", method = RequestMethod.GET)
public Result getAllCrossTable() {
return Result.success(userService.selectAllCrossTable());
}
}
Postman测试
使用postman进行测试,接口功能正确
![](https://img-blog.csdnimg.cn/img_convert/857a1bf1370c9f460cbd1ace85428ace.png)
注意事项
#和$的区别
我们使用Mybatis框架时,用的最多的应该是#{}这样的形式注入参数,但是这里传入的是字符串,如果仍然使用#{}的形式,那么得到的sql语句中表名会带有单引号,这样的sql语句无法执行,所以必须换成${table}的形式,它可以直接将字符串注入,但是安全性较差,在其他场景不推荐使用。
如何定期汇总数据?
这个就仁者见仁智者见智了,不过目前Spring Boot使用的主流定时调度框架估计只有Quartz了。