springboot动态修改数据源,访问多个数据库

springboot实现动态数据源访问多个数据

处理的问题

需求:

老板:小江啊!由于我们的数据量太多,现在我们的数据库是这样设计,一个月一个数据库,一天一张表。你去改改吧!
我:好的老板!
于是,我在网上开始找找相应的技术。
网上动态更换数据库的方式,大量的都是编写多个配置,因为他们都是一年创建一个数据库,一个月创建一个表,有一个博主说一个项目最长的使用年限也就是十年,无非就是配置十个连接。
我一想,好像是这个道理。(有个屁道理。)我是一个月创建一个数据库,十年就是120个配置。

经过千辛万苦的查找,终于找到了如何通过Spring Boot配置动态数据源访问多个数据库

但是,我按照这样完成了后,遇到了一些问题。
我在使用这个方法之后,程序在第一次连接的时候会报一个错误配置类型不对。
所以我有找到了一个方法,多数据库的查询。
在这里插入图片描述
数据库的名称是有规定的。
例如

SELECT * FROM hnbd_db_business202106.t_dwxx04

但这种方法在yml的配置文件中配置连接的数据库一定要存在,还有这样的方法一个的数据库要放在一个服务器上。

下面是我的一些代码

Controller


import com.hnbd.dwxx.pojo.DeviceData;
import com.hnbd.dwxx.pojo.response.ApiResponse;
import com.hnbd.dwxx.pojo.response.ApiResponseStatus;
import com.hnbd.dwxx.pojo.response.ApiResponseWithData;
import com.hnbd.dwxx.service.DwxxService;
import com.hnbd.dwxx.untils.MyCalendarUntil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;

/**
 * Test
 *
 * @创建人 江枫沐雪
 * @创建时间 2021/7/12 19:38
 */
@Slf4j
@RestController
@RequestMapping("dwxx")
public class DwxxController {

    @Autowired
    private DwxxService dwxxService;

    /**
     * 查询时间段内的所有数据信息
     * @param sender        编码
     * @param startTime     开始时间
     * @param endTime       结束时间
     * @return
     */
    @GetMapping("FindListByTime")
    public ApiResponse test(@RequestParam("sender") String sender,
                            @RequestParam("startTime") String startTime,
                            @RequestParam("endTime") String endTime) {
        //判断传递的参数是否为空
        if (StringUtils.isAllBlank(sender, startTime, endTime)) {
            return ApiResponseWithData.ofStatus(ApiResponseStatus.INVALID_PARAM);
        }
        try {
            //求两个日期的差值
            int chaMonth = MyCalendarUntil.getMonthSpace(startTime, endTime);
            int chaDay = MyCalendarUntil.getDateSpace(startTime, endTime);
            List deviceData = new ArrayList<>();

            //天数
            int days = 0;

            //月的差值是否正确
            if (chaMonth >= 0) {
                //循环,不同月份,使用不同的数据库
                for (int a = 0; a <= chaMonth; a++) {
                    //根据不同的月份,生成不同的数据库
                    String newMonth = MyCalendarUntil.getMonth(startTime, a);
                    String dataSource = "hnbd_db_business" + newMonth;
                    //判断数据库是否存在
                    int mysqlCount = dwxxService.getTableName(dataSource, "");
                    //如果数据库存在
                    if (mysqlCount != 0) {
                        //
                        //确定循环的次数
                        int forNum = MyCalendarUntil.getForNum(days, chaDay, newMonth);
                        //循环查询数据
                        for (int i = 0; i <= forNum; i++) {
                            //生成表的  后缀
                            int day = MyCalendarUntil.getDay(startTime, days);
                            days++;
                            String table = "t_dwxx" + String.format("%02d", day);
                            //判断数据库中这个表是否存在
                            int count = dwxxService.getTableName(dataSource, table);
                            //如果表存在 更换数据库的链接   查询出对应的数据
                            if (count == 1) {
                                List list = dwxxService.FindListByTime(sender, startTime, endTime, dataSource+"."+table);
                                if (list != null){
                                    for (int j = 0; j < list.size(); j++) {
                                        deviceData.add(list.get(j));
                                    }
                                }
                            }
                        }
                    } else {
                        //数据库不存在,跳出这一次循环
                        continue;
                    }
                }
                //返回数据
                return ApiResponseWithData.ofSuccess(deviceData);
            } else {
                //时间差有错
                return ApiResponseWithData.ofStatus(ApiResponseStatus.INVALID_PARAM);
            }
        } catch (ParseException e) {
            log.error("求表数据失败!");
            return ApiResponseWithData.ofStatus(ApiResponseStatus.INVALID_PARAM);
        }

    }

}

Service


import com.fasterxml.jackson.annotation.JsonFormat;
import com.hnbd.dwxx.pojo.DeviceData;
import com.hnbd.dwxx.pojo.Machine;
import com.hnbd.dwxx.pojo.TableData;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.util.*;

/**
 * DwxxService
 *
 * @创建人 江枫沐雪
 * @创建时间 2021/7/9 17:24
 */
@Service
public class DwxxService {

    @Autowired
    private SqlSessionTemplate sqlSessionTemplate;

    /**
     * 查询时间段内的所有数据信息
     *
     * @param sender    定位方北斗卡号
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @return
     */
    public List FindListByTime(String sender, String startTime, String endTime, String table) {
        HashMap<String, Object> map = new HashMap<>();
        map.put("sender", sender);
        map.put("startTime", startTime);
        map.put("endTime", endTime);
        map.put("table", table);

        List list = sqlSessionTemplate.selectList("DateMapper.FindListByTime", map);
        return list;
    }

    /**
     * 判断数据库中是否存在这张表
     *
     * @param dataSource 数据库的名字
     * @param table      表名
     * @return
     */
    public int getTableName(String dataSource, String table) {
        HashMap<String, Object> map = new HashMap<>();
        map.put("dataSource", dataSource);
        map.put("table", table);
        int count = sqlSessionTemplate.selectOne("DateMapper.getTableName", map);
        return count;
    }
}

Mapper

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="DateMapper">

    <!--  查询时间段内的所有数据信息  -->
    <select id="FindListByTime" resultType="map" parameterType="map">
        select h.Sender sender,h.RecvTime recvTime,cast(h.PosLong/1000000 as decimal(9,6)) longitude,cast(h.PosLat/1000000 as decimal(9,6)) latitude
        from ${table} h
        where h.Sender =#{sender} AND date_format(h.RecvTime,'%Y-%m-%d %H:%i:%S') between #{startTime} AND #{endTime}
        ORDER BY h.RecvTime
    </select>

    <!--    判断数据库中是否存在这张表       -->
    <select id="getTableName" resultType="int" parameterType="map">
        select COUNT(*)
        from information_schema.tables
        where table_schema=#{dataSource}
        <if test="table != null and table != '' ">
            AND table_name =#{table}
        </if>
    </select>

</mapper>

计算出日期的工具类untils

package com.hnbd.dwxx.untils;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;

/**
 * MyCalendarUntil
 *  计算两个日期的差值
 * @创建人 江枫沐雪
 * @创建时间 2021/7/12 11:38
 */
public class MyCalendarUntil {

    /**
     * 月份的差值
     * @param startTime         开始时间
     * @param endTime           结束时间
     * @return                  相差的月数
     * @throws ParseException
     */
    public static int getMonthSpace(String startTime, String endTime) throws ParseException {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        int result = 0;
        //时间写入      结束时间
        Calendar cal1 = new GregorianCalendar();
        cal1.setTime(sdf.parse(endTime));
        //时间写入      开始时间
        Calendar cal2 = new GregorianCalendar();
        cal2.setTime(sdf.parse(startTime));
        //求取差值
        result = (cal1.get(Calendar.YEAR) - cal2.get(Calendar.YEAR)) * 12 + cal1.get(Calendar.MONTH) - cal2.get(Calendar.MONTH);
        return result;
    }

    /**
     * 天数的差值
     * @param startTime         开始时间
     * @param endTime           结束时间
     * @return                  相差的天数
     * @throws ParseException
     */
    public static int getDateSpace(String startTime, String endTime) throws ParseException {

        SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd");
        Calendar calst = Calendar.getInstance();
        Calendar caled = Calendar.getInstance();

        calst.setTime(sf.parse(startTime));
        caled.setTime(sf.parse(endTime));

        //设置时间为0时
        calst.set(Calendar.HOUR_OF_DAY, 0);
        calst.set(Calendar.MINUTE, 0);
        calst.set(Calendar.SECOND, 0);
        caled.set(Calendar.HOUR_OF_DAY, 0);
        caled.set(Calendar.MINUTE, 0);
        caled.set(Calendar.SECOND, 0);
        //得到两个日期相差的天数
        int days = ((int)(caled.getTime().getTime()/1000)-(int)(calst.getTime().getTime()/1000))/3600/24;

        return days;
    }

    /**
     * 根据时间字符串,求取一个月份的第几天
     * @param time     时间
     * @return         天数
     * @throws ParseException
     */
    public static int getDay(String time) throws ParseException {

        SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd");
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(sf.parse(time));
        //求取第几天
        int day = calendar.get(Calendar.DATE);
        return day;
    }

    /**
     * 根据时间字符串,和相加的天数,求取相应月份的第几天
     * @param time          开始时间
     * @param days          相加的天数
     * @return
     * @throws ParseException
     */
    public static int getDay(String time,int days) throws ParseException {

        SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd");
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(sf.parse(time));
        calendar.add(Calendar.DATE,days);
        //求取添加天数后  相应月份的日期。
        int day = calendar.get(Calendar.DATE);
        return day;
    }

    /**
     * 根据时间字符串,和相加的月份,求取相应月份数据
     * @param time          开始时间
     * @param num           相加的月份
     * @return              相应月份数据
     * @throws ParseException
     */
    public static String getMonth(String time,int num) throws ParseException {

        SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd");
        SimpleDateFormat month = new SimpleDateFormat("yyyyMM");

        //月份添加
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(sf.parse(time));
        calendar.add(Calendar.MONTH,num);

        //格式转化
        String format = month.format(calendar.getTime());

        return format;
    }

    /**
     * 根据时间字符串,求取月份
     * @param time          时间   字符串类型
     * @return              月份
     * @throws ParseException
     */
    public static int getMonth(String time) throws ParseException {

        SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd");
        SimpleDateFormat month = new SimpleDateFormat("yyyyMM");

        String format = month.format(sf.parse(time));
        //求取月份
        return Integer.parseInt(format);
    }

    /**
     * 根据时间,求取月份
     * @param time          时间   date类型
     * @return              月份
     */
    public static int getMonth(Date time) {
        //格式转化
        SimpleDateFormat month = new SimpleDateFormat("yyyyMM");
        String format = month.format(time);
        //求取月份
        return Integer.parseInt(format);
    }

    /**
     * 应该循环的次数
     * @param days              已经循环了多少天
     * @param chaDay            相差的天数
     * @param newMonth          月份信息
     * @return                  应该循环的次数
     * @throws ParseException
     */
    public static int getForNum(int days,int chaDay,String newMonth) throws ParseException {
        SimpleDateFormat month = new SimpleDateFormat("yyyyMM");

        Calendar calendar = Calendar.getInstance();
        calendar.setTime(month.parse(newMonth));

        int i = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
        int cha = chaDay - days;
        return cha >= i ? i : cha;
    }
}

总结

如果还想动态的更换连接的服务器。我建议使用Sharding-JDBC

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值