diff --git a/AGENTS.md b/AGENTS.md
index 1488a3c..709a9c5 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -33,6 +33,7 @@ Java 源码位于 `src/main/java`,配置文件位于 `src/main/resources`,My
## 代码风格与命名规范
保持现有 Java 风格:4 空格缩进、UTF-8 文件编码、基础包名使用 `com.njcn.gather`。命名沿用分层后缀,如 `*Controller`、`*Service`、`*ServiceImpl`、`*Mapper`、`*Param`、`*PO`、`*VO`。优先复用现有 Lombok 注解,如 `@Data`、`@RequiredArgsConstructor`、`@Slf4j`。Mapper XML 文件名应与接口名保持一致。业务代码中,关键流程、分支判断、状态流转或容易误解的节点需要补充简洁的中文注释,但不要添加无信息量的注释。
+- 参照 `user` 模块的组织方式,Controller 与 Service 都按职责拆分;不同职责的方法放到不同 `*Controller`、`*Service`、`*ServiceImpl` 中,同一模块后续新增方法也要沿既有职责边界归类,不再回退为单一大类承载全部接口。
## 数据与 SQL 约束
- 新增业务表的 DO 优先复用当前 `BaseDO` / 审计字段风格;除非表本身明确不需要逻辑删除,不要再引入另一套审计基类。
diff --git a/entrance/pom.xml b/entrance/pom.xml
index 24d6a1d..2a3e7b2 100644
--- a/entrance/pom.xml
+++ b/entrance/pom.xml
@@ -48,6 +48,11 @@
mms-mapping
1.0.0
+
+ com.njcn.gather
+ add-data
+ 1.0.0
+
diff --git a/tools/add-data/pom.xml b/tools/add-data/pom.xml
new file mode 100644
index 0000000..73e794f
--- /dev/null
+++ b/tools/add-data/pom.xml
@@ -0,0 +1,41 @@
+
+
+ 4.0.0
+
+ com.njcn.gather
+ tools
+ 1.0.0
+
+
+ add-data
+
+
+
+
+
+
+ com.njcn
+ njcn-common
+ 0.0.1
+
+
+
+ com.njcn
+ spingboot2.3.12
+ 2.3.12
+
+
+
+ org.springframework
+ spring-jdbc
+
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+
diff --git a/tools/add-data/src/main/java/com/njcn/gather/tool/adddata/component/AddDataBatchWriter.java b/tools/add-data/src/main/java/com/njcn/gather/tool/adddata/component/AddDataBatchWriter.java
new file mode 100644
index 0000000..75a0118
--- /dev/null
+++ b/tools/add-data/src/main/java/com/njcn/gather/tool/adddata/component/AddDataBatchWriter.java
@@ -0,0 +1,135 @@
+package com.njcn.gather.tool.adddata.component;
+
+import com.njcn.gather.tool.adddata.pojo.bo.AddDataBatchWriteResult;
+import com.njcn.gather.tool.adddata.pojo.bo.AddDataTableDefinition;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.dao.DataAccessException;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.stereotype.Component;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * 批量写入组件。
+ */
+@Slf4j
+@Component
+@RequiredArgsConstructor
+public class AddDataBatchWriter {
+
+ /** JDBC 模板。 */
+ private final JdbcTemplate jdbcTemplate;
+
+ /**
+ * 写入一个批次。
+ *
+ * @param definition 表定义
+ * @param rows 行数据
+ * @return 写入结果
+ */
+ public AddDataBatchWriteResult writeBatch(AddDataTableDefinition definition, List> rows) {
+ if (rows == null || rows.isEmpty()) {
+ return new AddDataBatchWriteResult(0L, 0L, 0L, null);
+ }
+ try {
+ return executeInsertIgnore(definition, rows);
+ } catch (DataAccessException ex) {
+ log.warn("批量写入失败,开始降级为逐行写入,table={}, batchSize={}, message={}",
+ definition.getTableName(), rows.size(), resolveErrorMessage(ex));
+ return fallbackWriteOneByOne(definition, rows, ex);
+ }
+ }
+
+ /**
+ * 执行批量 INSERT IGNORE。
+ *
+ * @param definition 表定义
+ * @param rows 行数据
+ * @return 写入结果
+ */
+ private AddDataBatchWriteResult executeInsertIgnore(AddDataTableDefinition definition, List> rows) {
+ String sql = buildInsertIgnoreSql(definition, rows.size());
+ List