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将数据复制完成,完成了主表的复制,已经关联表的复制,并将关联关系同步