• MyBatis 动态创建表


    项目中需要记录接口调用的日志,由于目前数量不大,决定根据年进行动态创建表(invoke_interface_log_2019)。使用MyBatis实现(动态SQL)。

    1、Dao.xml

    <mapper namespace="com.xxx.xxx.dao.manager.system.InvokeInterfaceLogDao">
        <!-- 根据表名统计已存在的数量 -->
        <select id="countTables" parameterType="string" resultType="int" databaseId="mysql">
            SELECT count(1)
            FROM information_schema.TABLES
            WHERE LCASE(table_name) = #{tableName}
        </select>
    
    
        <!-- 创建表SQL,参数为表名 -->
        <update id="createTable" parameterType="string" databaseId="mysql">
            CREATE TABLE ${tableName} (
                `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
                `client_id` varchar(50) DEFAULT NULL COMMENT '客户端标识',
                `interface_type` tinyint(4) unsigned DEFAULT NULL COMMENT '接口归类',
                `interface_name` varchar(50) DEFAULT NULL COMMENT '接口名称',
                `invoke_time` datetime DEFAULT NULL COMMENT '调用时间',
                `is_success` tinyint(1) unsigned DEFAULT '0' COMMENT '是否成功',
                `fail_type` tinyint(4) unsigned DEFAULT NULL COMMENT '失败类型',
                `fail_msg` varchar(255) DEFAULT NULL COMMENT '失败信息',
                PRIMARY KEY (`id`)
            ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='调用接口日志表';
        </update>
    
        <insert id="insert" parameterType="com.xxx.xxx.xxx.manager.system.InvokeInterfaceLogDO" databaseId="mysql">
            INSERT INTO ${tableName} (
                client_id,
                interface_type,
                interface_name,
                invoke_time,
                is_success,
                fail_type,
                fail_msg
            )
            VALUES
                (
                    #{invokeInterfaceLog.clientId},
                    #{invokeInterfaceLog.interfaceType},
                    #{invokeInterfaceLog.interfaceName},
                    #{invokeInterfaceLog.invokeTime},
                    #{invokeInterfaceLog.success},
                    #{invokeInterfaceLog.failType},
                    #{invokeInterfaceLog.failMsg}
                )
        </insert>
    </mapper>

    2、Dao.java

    /**
     * 接口调用日志数据访问层接口
     *
     * @author: yemingxiang
     * @date: 2019/05/28
     */
    public interface InvokeInterfaceLogDao {
    
        /**
         * 统计存在的表数量
         *
         * @param tableName 表名
         * @return 存在的表数量
         */
        int countTables(String tableName);
    
        /**
         * 创建表
         *
         * @param tableName 表名
         */
        void createTable(@Param("tableName") String tableName);
    
        /**
         * 新增
         *
         * @param tableName 表名
         * @param invokeInterfaceLogDO 调用接口日志数据对象
         * @return 新增成功的记录数
         */
        int insert(@Param("tableName") String tableName,
            @Param("invokeInterfaceLog") InvokeInterfaceLogDO invokeInterfaceLogDO);
    }

    3、业务层实现如下:

    /**
     * 调用接口日志业务逻辑层实现
     *
     * @author yemingxiang
     * @date 2019/05/28
     */
    @Service
    public class InvokeInterfaceLogServiceImpl implements InvokeInterfaceLogService {
    
        private static final Logger logger = LoggerFactory.getLogger(InvokeInterfaceLogServiceImpl.class);
    
        @Autowired
        private InvokeInterfaceLogDao invokeInterfaceLogDao;
    
        @Override
        public boolean save(InvokeInterfaceLogDO invokeInterfaceLogDO) {
            int currentYear = LocalDate.now().getYear();
            String key = String.format("cs:system:invokeInterfaceLog:%s:string", currentYear);
            logger.info("接口调用日志表Redis Key:" + key);
            String tableName = RedisUtils.getString(key);
            logger.info("接口调用日志表表名:" + tableName);
            if (tableName != null) {
                return invokeInterfaceLogDao.insert(tableName, invokeInterfaceLogDO) == 1;
            }
    
            String newTableName = String.format("invoke_interface_log_%s", currentYear);
            RedisUtils redisUtils = new RedisUtils(newTableName);
            try {
                if (redisUtils.lock()) {
                    logger.info("获得Redis锁");
                    // 第二层判断,防范作用
                    tableName = RedisUtils.getString(key);
                    logger.info("再次获取接口调用日志表表名:" + tableName);
                    if (tableName != null) {
                        return invokeInterfaceLogDao.insert(tableName, invokeInterfaceLogDO) == 1;
                    }
    
                    int count = invokeInterfaceLogDao.countTables(newTableName);
                    if (count == 0) {
                        logger.info("创建接口调用日志表,并将表名保存到Redis");
                        invokeInterfaceLogDao.createTable(newTableName);
                        RedisUtils.set(key, newTableName);
                    }
                    return invokeInterfaceLogDao.insert(newTableName, invokeInterfaceLogDO) == 1;
                }
            } catch (InterruptedException e) {
                logger.error("新增调用接口日志时获取Redis锁失败_" + e.getMessage(), e);
            } finally {
                redisUtils.unlock();
                logger.info("释放Redis锁");
            }
            return false;
        }
    }
  • 相关阅读:
    JS获当前网页元素高度offsetHeight
    C-LODOP回调多个返回值On_Return_Remain
    JS的slice、substring、substr字符串截取
    【JS新手教程】JS修改css样式的几种方法
    Unity GUI(uGUI)使用心得与性能总结
    PDB文件:每个开发人员都必须知道的
    IEnumerable 使用foreach 详解
    Unity------Unity 脚本基类 MonoBehaviour 与 GameObject 的关系
    Unity5-----------之GI设置简介
    unity5x --------Music Mixer参数详解
  • 原文地址:https://www.cnblogs.com/KingJames/p/10936618.html
Copyright © 2020-2023  润新知