t场景:在开发中经常使用树形结构来组织数据,而在业务中长长出现复制的操作。通常我们复制只修改了用户id,而其他字段都不变变。那么将一棵较大的树复制呢?
表结构如下:
-- 用例库表
CREATE TABLE `venus_case_library` (`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',`name` varchar(100) DEFAULT NULL COMMENT '用例库名',`type` tinyint(4) DEFAULT NULL COMMENT '类型,-127~127',`app_id` bigint(20) DEFAULT NULL COMMENT '关联应用id',`description` varchar(255) DEFAULT NULL COMMENT '用例库描述',`is_deleted` varchar(1) DEFAULT 'N' COMMENT '删除标志',`creator` bigint(20) DEFAULT NULL,`gmt_created` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',`modifier` bigint(20) DEFAULT NULL COMMENT '修改人',`gmt_modified` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '更新时间',PRIMARY KEY (`id`),UNIQUE KEY `uk_name_type` (`name`,`type`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;-- 树形结构表
CREATE TABLE `venus_case_tree_copy` (`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',`name` varchar(100) DEFAULT NULL COMMENT '节点名',`parent_id` bigint(20) DEFAULT NULL COMMENT '父节点id',`type` tinyint(4) DEFAULT NULL COMMENT '节点类型 1 文件夹 2 用例集 3 用例',`case_lib_id` bigint(20) DEFAULT NULL COMMENT '用例库id',`is_deleted` varchar(1) DEFAULT 'N' COMMENT '删除标志',`copy_id` int(11) DEFAULT NULL, -- 该字段时为了复制使用PRIMARY KEY (`id`),KEY `idx_caseLibId` (`case_lib_id`)
) ENGINE=InnoDB AUTO_INCREMENT=42 DEFAULT CHARSET=utf8;-- 关联表
CREATE TABLE `venus_text_copy` (`id` bigint(20) NOT NULL AUTO_INCREMENT,`link_table` tinyint(4) NOT NULL COMMENT '连接表id 1:venus_case_tree',`link_cid` bigint(20) NOT NULL COMMENT '关联id',`text` mediumtext COMMENT '文本',PRIMARY KEY (`id`),KEY `uk_link` (`link_table`,`link_cid`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=41 DEFAULT CHARSET=utf8;
老的做法:将数据去读到内存中,修改部分数据,然后将数据插入到数据库;这样做出有哪些问题呢
- 如果有大量的数据,产生多次IO交互
- 如果在一次读取所有的数据,分批插入,有可能把应用内存打爆;
为了处理以上的问题,我们使用 insert select 的语法,直接在数据库中进行复制操作,变免多个io和内存消耗
- 修改表结构,在主表中增加 copy_id 字段,记录复制的数据的原id,用来为之后的关连数据insert select 提供支持
-
-- 复制数据,将case_id为4的节点全部复制,新的节点设置的case_id为5 insert into venus_case_tree_copy (name,parent_id,type,case_lib_id,copy_id,is_deleted) select name,parent_id,type,5,id,'N' from venus_case_tree_copy where case_lib_id=4;-- 复制关联数据 insert into venus_text_copy (link_table,link_cid,text) select link_table,cid,text from venus_text_copy t1 , (select id as cid,copy_id from venus_case_tree_copy where case_lib_id=5 ) t2 where t1.link_cid=t2.copy_id-- 获取关联关系 @Select("select t1.id,t2.id as parent_id from " +"(select id,parent_id,copy_id from venus_case_tree where case_lib_id=#{libId} and parent_id is not null) t1 " +"left JOIN (select id,copy_id from venus_case_tree where case_lib_id=#{libId} ) t2 " +"on t1.parent_id=t2.copy_id")List<VenusCaseTree> selectNodeRelation(@Param("libId") Long libId); -- 刷新关联关系@Update("<script>" +"<foreach collection='vcts' item='item' separator=';' >" +"update venus_case_tree set parent_id=#{item.parentId} where id=#{item.id}" +"</foreach>"+"</script>")void updateBatch(@Param("vcts") List<VenusCaseTree> vcts); - 通过以上四个sql将数据复制完成,完成了主表的复制,已经关联表的复制,并将关联关系同步