You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Oracle APEX中批量导入CSV至NON_DYNAMIC_USER_GROUPS表的代码咨询

实现CSV批量插入到NON_DYNAMIC_USER_GROUPS表的完整流程

我来帮你梳理从CSV文件批量导入数据到目标表的完整代码流程,下面以Java Spring Boot(企业级开发常用栈)为例,同时覆盖前端文件上传的基础处理:

1. 前端文件上传组件(HTML+JS)

先补全你已创建的文件浏览项,加上表单和基础格式校验,确保用户只能上传CSV文件:

<!-- 前端上传表单 -->
<form id="csvImportForm" enctype="multipart/form-data" method="POST" action="/api/groups/batch-import">
  <label for="csvFile">选择CSV文件:</label>
  <input type="file" id="csvFile" name="csvFile" accept=".csv" required>
  <button type="submit">开始导入</button>
</form>

<script>
// 前端简单校验文件格式
document.getElementById('csvFile').addEventListener('change', (e) => {
  const selectedFile = e.target.files[0];
  if (selectedFile && !selectedFile.name.toLowerCase().endsWith('.csv')) {
    alert('请选择CSV格式的文件哦!');
    e.target.value = ''; // 清空错误选择
  }
});
</script>

2. 后端依赖准备

处理CSV文件推荐用OpenCSV库,比手动解析更稳定,先在Maven的pom.xml中添加依赖:

<dependency>
  <groupId>com.opencsv</groupId>
  <artifactId>opencsv</artifactId>
  <version>5.6</version>
</dependency>

3. 实体类定义(对应数据库表)

重点注意:GROUP是SQL关键字,必须用@Column注解指定数据库列名,否则ORM框架生成SQL时会报错:

import jakarta.persistence.*;

@Entity
@Table(name = "NON_DYNAMIC_USER_GROUPS")
public class NonDynamicUserGroup {

    @Id
    private Long id; // 如果ID是自增主键,可添加@GeneratedValue(strategy = GenerationType.IDENTITY)
    
    private String name;
    
    @Column(name = "GROUP") // 规避SQL关键字冲突的核心配置
    private String group;
    
    private String groupType;

    // Getter & Setter 方法
    public Long getId() { return id; }
    public void setId(Long id) { this.id = id; }
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    public String getGroup() { return group; }
    public void setGroup(String group) { this.group = group; }
    public String getGroupType() { return groupType; }
    public void setGroupType(String groupType) { this.groupType = groupType; }
}

4. 后端核心处理逻辑(Controller+Service)

Controller层:接收文件、解析CSV

负责接收前端上传的文件,解析CSV内容并做基础校验:

import com.opencsv.CSVReader;
import com.opencsv.exceptions.CsvValidationException;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;

@RestController
public class GroupImportController {

    private final NonDynamicUserGroupService groupService;

    // 构造注入Service(推荐的依赖注入方式)
    public GroupImportController(NonDynamicUserGroupService groupService) {
        this.groupService = groupService;
    }

    @PostMapping("/api/groups/batch-import")
    public String batchImport(@RequestParam("csvFile") MultipartFile file) {
        // 先检查文件是否为空
        if (file.isEmpty()) {
            return "请选择要上传的CSV文件!";
        }

        try (CSVReader reader = new CSVReader(new InputStreamReader(file.getInputStream(), StandardCharsets.UTF_8))) {
            // 读取表头并校验格式
            String[] header = reader.readNext();
            validateCsvHeader(header);

            List<NonDynamicUserGroup> groupList = new ArrayList<>();
            String[] rowData;
            // 逐行解析CSV内容
            while ((rowData = reader.readNext()) != null) {
                NonDynamicUserGroup group = new NonDynamicUserGroup();
                // CSV列顺序需与表头对应:ID,NAME,GROUP,GROUP_TYPE
                group.setId(Long.parseLong(rowData[0].trim()));
                group.setName(rowData[1].trim());
                group.setGroup(rowData[2].trim());
                group.setGroupType(rowData[3].trim());

                // 校验单条数据合法性(非空、格式等)
                validateGroupData(group);

                groupList.add(group);
            }

            // 批量插入数据库
            groupService.batchInsertGroups(groupList);
            return String.format("导入成功!共插入 %d 条数据", groupList.size());
        } catch (IOException | CsvValidationException e) {
            return String.format("导入失败:%s", e.getMessage());
        } catch (IllegalArgumentException e) {
            return String.format("数据格式错误:%s", e.getMessage());
        }
    }

    // 校验CSV表头是否符合要求
    private void validateCsvHeader(String[] header) {
        String[] expectedHeaders = {"ID", "NAME", "GROUP", "GROUP_TYPE"};
        for (int i = 0; i < expectedHeaders.length; i++) {
            if (!expectedHeaders[i].equalsIgnoreCase(header[i].trim())) {
                throw new IllegalArgumentException("CSV表头格式错误,要求为:ID,NAME,GROUP,GROUP_TYPE");
            }
        }
    }

    // 校验单条数据的合法性
    private void validateGroupData(NonDynamicUserGroup group) {
        if (group.getId() == null || group.getName() == null || group.getName().isEmpty()) {
            throw new IllegalArgumentException("ID和NAME字段不能为空!");
        }
        // 可根据业务需求添加更多校验,比如GROUP_TYPE的可选值范围
    }
}

Service层:批量插入事务处理

必须添加事务管理,确保数据一致性:要么全部插入成功,要么全部回滚:

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

@Service
public class NonDynamicUserGroupService {

    private final NonDynamicUserGroupRepository groupRepository;

    public NonDynamicUserGroupService(NonDynamicUserGroupRepository groupRepository) {
        this.groupRepository = groupRepository;
    }

    @Transactional(rollbackFor = Exception.class)
    public void batchInsertGroups(List<NonDynamicUserGroup> groupList) {
        // 方式1:JPA自带的saveAll(适合数据量不大的场景,代码简洁)
        groupRepository.saveAll(groupList);

        // 方式2:原生SQL批量插入(适合大数据量,性能更优,需自定义Repository方法)
        /*
        String insertSql = "INSERT INTO NON_DYNAMIC_USER_GROUPS (ID, NAME, GROUP, GROUP_TYPE) VALUES (?, ?, ?, ?)";
        // 可使用JdbcTemplate执行批量SQL
        */
    }
}

Repository接口

基于Spring Data JPA的基础Repository:

import org.springframework.data.jpa.repository.JpaRepository;

public interface NonDynamicUserGroupRepository extends JpaRepository<NonDynamicUserGroup, Long> {
    // 如需原生SQL批量插入,可在此定义方法并实现
}

5. 关键注意事项

  • SQL关键字规避GROUP是SQL保留字,必须用@Column(name = "GROUP")指定列名,否则会触发SQL语法错误。
  • ID自增处理:如果表ID是自增主键,CSV中无需提供ID,实体类给id字段加@GeneratedValue(strategy = GenerationType.IDENTITY)即可。
  • 数据校验:插入前必须做校验,避免脏数据入库(比如重复ID、空值、格式错误等)。
  • 大数据量优化:若导入数据超过1万条,建议分批次插入(比如每1000条一批),防止内存溢出。
  • 编码问题:读取CSV时指定UTF-8编码,避免中文乱码。

内容的提问来源于stack exchange,提问作者Abinnaya

火山引擎 最新活动