MyBatis sub-table practice

1 Introduction

Project development to the needs, requirementsThe monthly business data archiving, That is, keep a separate monthly data in a table, we must create a new table every month. Never before encountered such a scenario, think fast implementation, the main difficulty is as follows:

  1. Project uses MyBatisthe framework, ORMthe idea is toA bean mapping a table, how to implement a bean object map the same structure multiple tables with different names
  2. Monthly generate a new table,How do I know if the database already exists month table, how to create a new table does not exist

Fortunately, MyBatisthis lightweight ORMframeworkHandwritten SQL statementsHe left the room, otherwise it can only live to DBAgo pondering. We know MyBatisthrough Mapperto operate the database, and can be flexible on their own handwritten SQLstatement, which gives us great convenience

2. Create a dynamic table

2.1 database query whether there is a target table

Based on Mapperthe definition of the interface method, add annotations on the method @Selectto write their own SQL statements. This statement 数据库名称and 表名称as to the Senate,Target quantity statistics target database tables from the database table information stored in itself, through which the return value may be determined whether the target table exists

@Repository
public interface ActionEventMapper extends BaseMapper<ActionEvent> {

    @Select("SELECT count(*) FROM information_schema.`tables` WHERE TABLE_SCHEMA = #{dbName} " +
            "AND TABLE_NAME = #{tableName}")
    int countTable(@Param("tableName") String tableName, @Param("dbName") String dbName);
}

2.2 dynamically created table

Similarly, the handwritten SQL statement is mapped to the interface methods,The table name as a parameter to complete the goal to create a dynamic table. It should be noted there are requirements for the format in MySql table name, connector must use an underscore _, or there will be a syntax error. Further use of the SQL statement table name} {$ spliced directly, instead of using # {} placeholder

@Repository
public interface ActionEventMapper extends BaseMapper<ActionEvent> {

    @Update("CREATE TABLE IF NOT EXISTS ${tableName}(" +
            " `FuiId` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键'," +
            " `FuiEventType` tinyint(4) unsigned NOT NULL DEFAULT '0' COMMENT '事件类型'," +
            " `FuiMicroSeconds` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT '微秒'," +
            " `FuiCreateTime` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT '创建时间'," +
            " `FuiUpdateTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'," +
            " `FuiCasVersion` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT 'cas'," +
            " PRIMARY KEY (`FuiId`)," +
            ")ENGINE = InnoDB AUTO_INCREMENT = 1 DEFAULT CHARSET=utf8 COMMENT='按月归档表';")
    @CacheEvict(value = "action_event_cache", key = "1")
    void createNewTable(@Param("tableName") String tableName);

2.3 Timing create a table

Spring Framework comes with timing task notes @Scheduledcreated crontask, timed to create a table

@Slf4j
@Component
public class CreateTableJob {

    @Autowired
    private ActionEventRepository actionEventRepository;

    /**
     * 每月 28 号 00:00:00 创建下月的表
     */
    @Scheduled(cron = "0 0 0 28 1-12 ?")
    public void createTable() {
        String tableName = actionEventTableUtil.getNextMonthTableName();
        log.warn("It is time to create next month table:{}", tableName);
        try {
            actionEventRepository.createTable(tableName);
        } catch (Exception e) {
            log.warn("Cron job create next month table:" + tableName + "fail!", e);
        }
    }

}

3. Data Insert

3.1 data into single

Inserting a single very simple data, onlyNote that the reference table name, and use the $ {tableName} splicing table

@Repository
public interface ActionEventMapper extends BaseMapper<ActionEvent> {

    @Insert("INSERT INTO ${tableName}(FuiEventType, FuiMicroSeconds, FuiCreateTime, FuiCasVersion) VALUES "
            + "(#{actionEvent.eventType}, #{actionEvent.microSeconds}, #{actionEvent.createTime}, #{actionEvent.casVersion})")
    // @Options 注解将插入表时主键字段 FuiId 生成的值回填到 bean 对象 actionEvent 的 id 属性
    @Options(useGeneratedKeys = true, keyProperty = "actionEvent.id", keyColumn = "FuiId")
    int save(@Param(value = "actionEvent") ActionEvent actionEvent, @Param("tableName") String tableName);

3.2 Bulk Insert

Quantities of data insertion is relatively complex, SQL statements for the script-like form,Notes @Insertno longer is a very long string, but an array of strings

@Repository
public interface ActionEventMapper extends BaseMapper<ActionEvent> {

    @Insert({"<script>",
            "INSERT INTO ${tableName}(FuiEventType, FuiMicroSeconds, FuiCreateTime, FuiCasVersion) VALUES ",
            "<foreach collection='matchActionEvents' item='matchActionEvent' index='index' separator=','>",
            "(#{actionEvent.eventType}, #{actionEvent.microSeconds}, #{actionEvent.createTime}, #{actionEvent.casVersion})",
            "</foreach>",
            "</script>"})
     @Options(useGeneratedKeys = true, keyProperty = "param1.id", keyColumn = "FuiId")
    int saveBatch(@Param(value = "actionEvent") List<ActionEvent> actionEvents,
                  @Param("tableName") String tableName);

3.3 Note

Using @Options(useGeneratedKeys = true, keyProperty = "id", keyColumn = "FuiId")the generated key table to backfill bean object properties corresponding to the time is noted, keyPropertythe need to specify the corresponding parameter of the corresponding attribute, form 参数名.id. Typically have the following information is given, indicating the available parameters, is generally used for bulk insertsparam1.id

Specified key properties are [id] and available parameters are [matchActionEvent, param1, tableName, param2]

Published 97 original articles · won praise 88 · views 10000 +

Guess you like

Origin blog.csdn.net/weixin_45505313/article/details/104495940