【Java】AccessファイルをJavaで操作!Jackcessライブラリ完全ガイド+DAOパターン実装例
はじめに
Microsoft Accessのファイル(.mdb、.accdb)をJavaから直接操作したいと思ったことはありませんか?
「AccessがインストールされていないLinuxサーバーでAccessファイルを読みたい」
「既存システムのデータをAccessファイルにエクスポートしたい」
「AccessファイルをJavaアプリケーションで処理したい」
そんな時に役立つのがJackcessライブラリです!
この記事では、Jackcessの基本的な使い方から、DAOパターンを使った実践的なデータベース移行まで、初心者にもわかりやすく解説します。
対象読者
- Javaの基礎を学習中の方
- AccessファイルをJavaで扱いたい方
- データベース間のデータ移行を実装したい方
- DAOパターンを実践で学びたい方
環境
- Java 8以上
- Jackcess 4.0.5
- Maven または Gradle
目次
Jackcessとは
JackcessはPure Javaで書かれたライブラリで、Microsoft Accessのデータベースファイルを読み書きできます。
🎯 主な特徴
特徴 | 説明 |
---|---|
Accessなしで動作 | Microsoft Accessのインストール不要 |
クロスプラットフォーム | Windows、Mac、Linuxで動作 |
無料 | Apache Licenseで提供 |
幅広いバージョン対応 | Access 2000〜2019に対応 |
セットアップ
Maven
<dependency>
<groupId>com.healthmarketscience.jackcess</groupId>
<artifactId>jackcess</artifactId>
<version>4.0.5</version>
</dependency>
Gradle
dependencies {
implementation 'com.healthmarketscience.jackcess:jackcess:4.0.5'
}
基本操作
1️⃣ データベースを開く
import com.healthmarketscience.jackcess.*;
import java.io.File;
// try-with-resourcesで自動的にクローズ
try (Database db = DatabaseBuilder.open(new File("sample.mdb"))) {
System.out.println("データベースを開きました");
// 処理
} // ここで自動的にクローズされる
2️⃣ データを読み取る
try (Database db = DatabaseBuilder.open(new File("sample.mdb"))) {
Table table = db.getTable("顧客テーブル");
// 拡張for文で簡単にループ
for (Row row : table) {
String name = row.getString("名前");
Integer age = row.getInt("年齢");
System.out.println(String.format("%s さん(%d歳)", name, age));
}
}
3️⃣ データを検索する
try (Database db = DatabaseBuilder.open(new File("sample.mdb"))) {
Table table = db.getTable("顧客テーブル");
// 特定の条件でデータを検索
Map<String, Object> criteria = Collections.singletonMap("名前", "田中太郎");
Row row = CursorBuilder.findRow(table, criteria);
if (row != null) {
System.out.println("見つかりました: " + row);
}
}
4️⃣ データを追加する
try (Database db = DatabaseBuilder.open(new File("sample.mdb"))) {
Table table = db.getTable("顧客テーブル");
// addRowメソッドで簡単に追加
table.addRow(
Column.AUTO_NUMBER, // ID(自動採番)
"山田花子", // 名前
25, // 年齢
"東京都" // 住所
);
}
5️⃣ 新しいデータベースを作成
// 新規Accessファイルを作成
try (Database db = DatabaseBuilder.create(
Database.FileFormat.V2010, // Access 2010形式
new File("new_database.accdb"))) {
// テーブルを作成
Table newTable = new TableBuilder("商品マスタ")
.addColumn(new ColumnBuilder("商品ID", DataType.LONG)
.setAutoNumber(true))
.addColumn(new ColumnBuilder("商品名", DataType.TEXT))
.addColumn(new ColumnBuilder("価格", DataType.MONEY))
.toTable(db);
// データを追加
newTable.addRow(Column.AUTO_NUMBER, "ノートPC", 98000);
newTable.addRow(Column.AUTO_NUMBER, "マウス", 2980);
}
実践的な使い方
CSVファイルをインポート
try (Database db = DatabaseBuilder.open(new File("database.mdb"))) {
// CSVファイルを直接インポート
new ImportUtil.Builder(db, "CSVデータ")
.setDelimiter(",")
.setHeader(true)
.importFile(new File("data.csv"));
System.out.println("CSVインポート完了!");
}
データ型の対応表
Jackcess型 | Java型 | 用途 |
---|---|---|
TEXT | String | 文字列 |
INT | Integer | 整数 |
LONG | Long | ID等の長整数 |
MONEY | BigDecimal | 金額 |
BOOLEAN | Boolean | フラグ |
SHORT_DATE_TIME | LocalDateTime | 日時 |
DAOパターンでDB連携
実際の開発では、DAOパターンを使ってデータベースアクセスを抽象化することが重要です。
ここでは、MySQLなどの既存DBからAccessファイルへデータを移行する実装例を紹介します。
📁 プロジェクト構造
src/main/java/
├── entity/
│ └── Employee.java # エンティティクラス
├── dao/
│ ├── EmployeeDAO.java # DAOインターフェース
│ ├── MySQLEmployeeDAO.java # MySQL実装
│ └── AccessEmployeeDAO.java # Access実装
└── DatabaseMigration.java # メインクラス
Step 1: エンティティクラス
// entity/Employee.java
public class Employee {
private Integer id;
private String name;
private String department;
private Integer age;
private BigDecimal salary;
private LocalDateTime hireDate;
// コンストラクタ
public Employee() {}
public Employee(Integer id, String name, String department,
Integer age, BigDecimal salary, LocalDateTime hireDate) {
this.id = id;
this.name = name;
this.department = department;
this.age = age;
this.salary = salary;
this.hireDate = hireDate;
}
// Getter/Setter(Lombokを使えば @Data で省略可能)
public Integer getId() { return id; }
public void setId(Integer id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
// 他のGetter/Setterも同様に実装...
}
Step 2: DAOインターフェース
// dao/EmployeeDAO.java
public interface EmployeeDAO {
List<Employee> findAll(); // 全件取得
Employee findById(Integer id); // ID検索
List<Employee> findByDepartment(String dept); // 部署検索
void save(Employee employee); // 保存
void saveAll(List<Employee> employees); // 一括保存
void close(); // リソース解放
}
Step 3: MySQL実装
// dao/MySQLEmployeeDAO.java
public class MySQLEmployeeDAO implements EmployeeDAO {
private Connection connection;
public MySQLEmployeeDAO() throws SQLException {
// データベース接続
String url = "jdbc:mysql://localhost:3306/company_db?useUnicode=true&characterEncoding=utf8";
String user = "root";
String password = "password";
this.connection = DriverManager.getConnection(url, user, password);
}
@Override
public List<Employee> findAll() {
List<Employee> employees = new ArrayList<>();
String sql = "SELECT * FROM employees ORDER BY id";
try (Statement stmt = connection.createStatement();
ResultSet rs = stmt.executeQuery(sql)) {
while (rs.next()) {
employees.add(mapRowToEmployee(rs));
}
} catch (SQLException e) {
e.printStackTrace();
}
return employees;
}
// ResultSetからEmployeeへのマッピング
private Employee mapRowToEmployee(ResultSet rs) throws SQLException {
Employee emp = new Employee();
emp.setId(rs.getInt("id"));
emp.setName(rs.getString("name"));
emp.setDepartment(rs.getString("department"));
emp.setAge(rs.getInt("age"));
emp.setSalary(rs.getBigDecimal("salary"));
Timestamp timestamp = rs.getTimestamp("hire_date");
if (timestamp != null) {
emp.setHireDate(timestamp.toLocalDateTime());
}
return emp;
}
@Override
public void close() {
try {
if (connection != null && !connection.isClosed()) {
connection.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
// 他のメソッドも実装...
}
Step 4: Access実装
// dao/AccessEmployeeDAO.java
public class AccessEmployeeDAO implements EmployeeDAO {
private Database database;
private Table employeeTable;
public AccessEmployeeDAO(String fileName) throws IOException {
File dbFile = new File(fileName);
// ファイルが存在しない場合は新規作成
if (!dbFile.exists()) {
createNewDatabase(dbFile);
} else {
this.database = DatabaseBuilder.open(dbFile);
this.employeeTable = database.getTable("社員マスタ");
}
}
private void createNewDatabase(File dbFile) throws IOException {
// 新規データベース作成
this.database = DatabaseBuilder.create(
Database.FileFormat.V2010, dbFile);
// テーブル作成
this.employeeTable = new TableBuilder("社員マスタ")
.addColumn(new ColumnBuilder("社員ID", DataType.LONG)
.setAutoNumber(true))
.addColumn(new ColumnBuilder("氏名", DataType.TEXT)
.setMaxLength(100))
.addColumn(new ColumnBuilder("部署", DataType.TEXT)
.setMaxLength(50))
.addColumn(new ColumnBuilder("年齢", DataType.INT))
.addColumn(new ColumnBuilder("給与", DataType.MONEY))
.addColumn(new ColumnBuilder("入社日", DataType.SHORT_DATE_TIME))
.addIndex(new IndexBuilder("idx_部署")
.addColumns("部署"))
.toTable(database);
}
@Override
public void saveAll(List<Employee> employees) {
int count = 0;
for (Employee emp : employees) {
try {
employeeTable.addRow(
Column.AUTO_NUMBER,
emp.getName(),
emp.getDepartment(),
emp.getAge(),
emp.getSalary(),
emp.getHireDate()
);
count++;
// 進捗表示(100件ごと)
if (count % 100 == 0) {
System.out.println(count + "件処理済み...");
}
} catch (IOException e) {
System.err.println("保存エラー: " + emp.getName());
e.printStackTrace();
}
}
System.out.println("合計 " + count + " 件を保存しました");
}
@Override
public void close() {
try {
if (database != null) {
database.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
// 他のメソッドも実装...
}
Step 5: 実行クラス
// DatabaseMigration.java
public class DatabaseMigration {
public static void main(String[] args) {
System.out.println("=== データベース移行開始 ===");
// try-with-resourcesを活用
try (MySQLEmployeeDAO mysqlDAO = new MySQLEmployeeDAO();
AccessEmployeeDAO accessDAO = new AccessEmployeeDAO("社員データ.accdb")) {
// 1. MySQLからデータ取得
System.out.println("データ取得中...");
List<Employee> employees = mysqlDAO.findAll();
System.out.println("取得件数: " + employees.size());
// 2. Accessへ保存
System.out.println("Access保存中...");
accessDAO.saveAll(employees);
// 3. 部署別ファイル作成(オプション)
createDepartmentFiles(mysqlDAO);
System.out.println("=== 移行完了 ===");
} catch (Exception e) {
System.err.println("エラー発生: " + e.getMessage());
e.printStackTrace();
}
}
// 部署別ファイル作成
private static void createDepartmentFiles(MySQLEmployeeDAO dao) {
String[] departments = {"営業部", "開発部", "総務部"};
for (String dept : departments) {
try (AccessEmployeeDAO deptDAO =
new AccessEmployeeDAO(dept + "_社員.accdb")) {
List<Employee> deptEmployees = dao.findByDepartment(dept);
if (!deptEmployees.isEmpty()) {
deptDAO.saveAll(deptEmployees);
System.out.println(dept + ": " + deptEmployees.size() + "件");
}
} catch (IOException e) {
System.err.println(dept + " の処理失敗: " + e.getMessage());
}
}
}
}
応用例:定期バックアップ
@Component // Spring Bootの場合
public class ScheduledBackup {
@Scheduled(cron = "0 0 * * * *") // 毎時0分に実行
public void backupToAccess() {
String timestamp = LocalDateTime.now()
.format(DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss"));
String fileName = String.format("backup_%s.accdb", timestamp);
try (MySQLEmployeeDAO source = new MySQLEmployeeDAO();
AccessEmployeeDAO backup = new AccessEmployeeDAO(fileName)) {
List<Employee> data = source.findAll();
backup.saveAll(data);
System.out.println("バックアップ完了: " + fileName);
} catch (Exception e) {
System.err.println("バックアップ失敗: " + e.getMessage());
}
}
}
トラブルシューティング
💡 よくあるエラーと対処法
1. ファイルが見つからない
File dbFile = new File("data.mdb");
if (!dbFile.exists()) {
System.err.println("ファイルが存在しません: " + dbFile.getAbsolutePath());
return;
}
2. 文字化け対策
// JVMオプションで指定
-Dfile.encoding=UTF-8
3. メモリ不足(大量データ処理時)
// バッチ処理で分割
int batchSize = 1000;
for (int i = 0; i < employees.size(); i += batchSize) {
List<Employee> batch = employees.subList(i,
Math.min(i + batchSize, employees.size()));
accessDAO.saveAll(batch);
}
必要な依存関係まとめ
<dependencies>
<!-- Jackcess -->
<dependency>
<groupId>com.healthmarketscience.jackcess</groupId>
<artifactId>jackcess</artifactId>
<version>4.0.5</version>
</dependency>
<!-- MySQL Driver -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.33</version>
</dependency>
<!-- ログ出力(オプション) -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>2.0.9</version>
</dependency>
</dependencies>
パフォーマンスTips
🚀 高速化のコツ
- インデックスを活用
.addIndex(new IndexBuilder("idx_name").addColumns("name"))
- バッチ処理
// 1000件ずつ処理
List<List<Employee>> batches = Lists.partition(employees, 1000);
- 接続プーリング(HikariCP使用例)
HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:mysql://localhost:3306/db");
HikariDataSource dataSource = new HikariDataSource(config);
まとめ
Jackcessを使えば、JavaからAccessファイルを簡単に操作できます。
✅ 基本操作:読み取り、書き込み、検索、作成
✅ DAOパターン:データベース操作の抽象化
✅ 実践例:MySQLからAccessへのデータ移行
✅ 応用:定期バックアップ、バッチ処理
この記事のコードを参考に、ぜひ実際に動かしてみてください!
参考リンク
関連記事
もしJavaでExcelファイルを操作したい場合は、Apache POIライブラリがおすすめです。
CSVファイルの操作なら、OpenCSVやApache Commons CSVが便利です。
タグ候補: Java
Jackcess
MicrosoftAccess
DAO
データベース
ご質問やご意見があればコメントください!