SpringbBoot + mybatis(直接在接口方法上写sql) + mysql
解决问题
1.怎么动态新建表
2.怎么一个查询/新增 方法映射多表
3.怎么知道什么是否该新建表,需要新建的表是否在数据库存在
实体类
public class HistoryRule {
private Long sendruleHistoryId;
private Long orderId;
private String adminRule;
private Date sendTime;
private String isRollback;
}
dao层
import org.apache.ibatis.annotations.*;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Repository;
import java.util.List;
/**
* @Description: 历史规则dao
* @Author: cyg
* @Date: 2019/8/2
* @Version:
**/
@Repository
@Mapper
public interface HistoryDao {
//批量插入历史规则
@Insert({""})
@Cacheable(value = "historyCache", key = "#root.methodName")
@Options(useGeneratedKeys = true, keyColumn = "pre_rollback_id")
int insertMoreHistoryRule(@Param(value = "historyRules") List historyRules,
@Param("tableName") String tableName);
//单条插入历史规则
@Insert("insert into ${tableName}(order_id, admin_rule, send_time, is_rollback) values " +
"(#{historyRule.orderId}, #{historyRule.adminRule}, #{historyRule.sendTime}, #{historyRule.isRollback})")
@Cacheable(value = "historyCache", key = "#historyRule.sendruleHistoryId+#root.methodName")
int insertOneHistoryRule(@Param(value = "historyRule") HistoryRule historyRule,
@Param("tableName") String tableName);
//单条删除Rollback
@Delete("delete from ${tableName} where sendrule_history_id = #{historyRule.sendruleHistoryId}")
void deleteOneHistoryRule(@Param(value = "historyRule") HistoryRule historyRule,
@Param("tableName") String tableName);
@Select("SELECT table_name FROM information_schema.`tables` WHERE TABLE_SCHEMA=#{dbName}" +
"AND table_name LIKE 'aps_openresty_rule_history_%'")
//查询表名list
@Cacheable(value = "historyCache", key = "1")
List getHistoryTableNameList(@Param("dbName") String dbName);
@Update("create table ${tableName} (" +
" `sendrule_history_id` bigint(12) NOT NULL AUTO_INCREMENT," +
" `order_id` bigint(12) NULL DEFAULT NULL," +
" `admin_rule` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL," +
" `send_time` datetime(0) NULL DEFAULT NULL," +
" `is_rollback` char(1) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL," +
" PRIMARY KEY (`sendrule_history_id`) USING BTREE)" +
"ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic")
//创建数据表
@CacheEvict(value = "historyCache", key = "1")
void createHistoryTable(@Param("tableName") String tableName);
}
上面dao层有一个 createHistoryTable 和 getHistoryTableNameList 是关键,一个是新建表,一个是查询某个数据库所有满足条件的表名,list返回。
工具类
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Calendar;
import java.util.List;
/**
* @Description: 分表util
* @Author: cyg
* @Date: 2019/8/8
* @Version:
**/
@Component
public class SubTableUtil {
private final static String dbName = "base_aiop";
private final static String preHistoryTableName = "aps_openresty_rule_history_";
@Autowired
private HistoryDao historyDao;
//动态创建历史规则表
public void createHistoryTable() {
//得到当前表的所有分表
List tableNameList = getHistoryTableNameList();
String tableName = getHistoryTableNameByNowDate(preHistoryTableName);
//如果所有分表中不包含当前月份的分表,则新建表
if (!tableNameList.contains(tableName)) {
historyDao.createHistoryTable(tableName);
logger.info("创建历史规则分表:" + tableName);
} else {
logger.info("历史规则分表:" + tableName + "已经存在");
}
}
//查询数据库类似 "aps_openresty_rule_history_"的表名
public List getHistoryTableNameList() {
return historyDao.getHistoryTableNameList(dbName);
}
//获取历史规则分表名
public String getHistoryTableName() {
String tableName = getHistoryTableNameByNowDate(preHistoryTableName);
return tableName;
}
//根据当前日期返回表名
private String getHistoryTableNameByNowDate(String preTableName) {
String calendarYearAndMonth = getData();
return preTableName + calendarYearAndMonth;
}
//获取当前日期,格式 201908
private String getData() {
Calendar calendar = Calendar.getInstance();
String calendarMounth = null;
//日历获取的月份为0-11,所以这里加1
if (calendar.get(Calendar.MONTH) < 9) {
calendarMounth = "0" + (calendar.get(Calendar.MONTH) + 1);
} else {
calendarMounth = String.valueOf((calendar.get(Calendar.MONTH) + 1));
}
return calendar.get(Calendar.YEAR) + calendarMounth;
}
}
工具类里面实现了
1.获取所有分表名
2.获取当前月的分表名
3.创建表
新建表,定时类,使用定时任务、cron表达式,每月月初新建表
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
/**
* @Description: 定时新建表
* @Author: cyg
* @Date: 2019/8/8
* @Version:
**/
@Component
@Transactional
public class CreateTableTask {
//private Logger logger = LoggerFactory.getLogger(Rollback2History.class);
@Autowired
private SubTableUtil subTableUtil;
@Scheduled(cron = "0 0 0 1 1-12 ? ")
public void createTable() {
try {
//新建历史规则表
subTableUtil.createHistoryTable();
} catch (Exception e) {
//logger.info("新建表失败:" + e);
}
}
}
删除,插入代码
//得到当月分表名
String tableName = subTableUtil.getHistoryTableName();
//执行插入代码
historyDao.insertOneHistoryRule(historyRule,tableName)
//执行删除代码
historyDao.deleteOneHistoryRule(historyRule,tableName)
注意点:这样默认操作的都是最新的表,历史表的操作得另外写拼接表名的方法。