Spring BootとApache POIを用いたExcelデータのMySQL一括インポート実装

Spring BootアプリケーションでExcelファイルからMySQLへデータを一括インポートする機能を実装する方法について説明します。Apache POIとHutoolライブラリを活用し、効率的なデータ読み込みと挿入処理を実現します。

依存関係の設定(pom.xml)

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi-ooxml</artifactId>
        <version>5.2.3</version>
    </dependency>
    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
        <version>2.3.0</version>
    </dependency>
    <dependency>
        <groupId>cn.hutool</groupId>
        <artifactId>hutool-all</artifactId>
        <version>5.8.11</version>
    </dependency>
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid-spring-boot-starter</artifactId>
        <version>1.2.9</version>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>
</dependencies>

データソース設定(application.properties)

spring.datasource.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource

mybatis.mapper-locations=classpath:mapper/*.xml
mybatis.type-aliases-package=com.example.model

エンティティクラス

@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class Employee {
    private Long id;
    private String name;
    private String company;
    private String gender;
    private String partner;
    private String address;
}

DAOインターフェースとMapper

@Mapper
public interface EmployeeDao {
    void batchInsert(@Param("employees") List<Employee> employees);
}

対応するMapper XML:

<mapper namespace="com.example.dao.EmployeeDao">
    <insert id="batchInsert">
        INSERT INTO employee_data (name, company, gender, partner, address)
        VALUES
        <foreach collection="employees" item="emp" separator=",">
            (#{emp.name}, #{emp.company}, #{emp.gender}, #{emp.partner}, #{emp.address})
        </foreach>
    </insert>
</mapper>

サービスクラスでのインポート実装

@Service
@Slf4j
public class ExcelImportService {

    @Autowired
    private SqlSessionFactory sqlSessionFactory;

    @Autowired
    private EmployeeDao employeeDao;

    public void importFromExcel(String filePath) {
        // Excel読み込み
        ExcelReader reader = ExcelUtil.getReader(filePath);
        List<Employee> employees = reader.readAll(Employee.class);

        // バッチ処理でDB登録
        try (SqlSession session = sqlSessionFactory.openSession(ExecutorType.BATCH)) {
            EmployeeDao dao = session.getMapper(EmployeeDao.class);
            dao.batchInsert(employees);
            session.commit();
        }
    }

    // 複数スレッドによる並列処理例
    public void parallelImport(String filePath) throws InterruptedException {
        ExcelReader reader = ExcelUtil.getReader(filePath);
        List<Employee> allEmployees = reader.readAll(Employee.class);

        int batchSize = 2000;
        List<List<Employee>> batches = Lists.partition(allEmployees, batchSize);
        ExecutorService executor = Executors.newFixedThreadPool(4);
        CountDownLatch latch = new CountDownLatch(batches.size());

        for (List<Employee> batch : batches) {
            executor.submit(() -> {
                try {
                    employeeDao.batchInsert(batch);
                } finally {
                    latch.countDown();
                }
            });
        }

        latch.await();
        executor.shutdown();
    }
}

テストコード

@SpringBootTest
@MapperScan("com.example.dao")
class ExcelImportTest {

    @Autowired
    private ExcelImportService importService;

    @Test
    void testBatchImport() {
        importService.importFromExcel("C:\\temp\\employees.xlsx");
    }

    @Test
    void testParallelImport() throws InterruptedException {
        importService.parallelImport("C:\\temp\\employees.xlsx");
    }
}

データベーステーブル定義

CREATE TABLE employee_data (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(255),
    company VARCHAR(255),
    gender VARCHAR(10),
    partner VARCHAR(255),
    address VARCHAR(255)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

タグ: Spring Boot Apache POI MySQL MyBatis Hutool

8月3日 05:32 投稿