1. プロジェクトの準備
Maven 依存関係
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>3.0.1</version>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
アプリケーション設定(application.yml)
spring:
datasource:
url: jdbc:mysql://localhost:3306/example_db?useSSL=false&serverTimezone=UTC
username: app_user
password: secret
driver-class-name: com.mysql.cj.jdbc.Driver
mybatis:
mapper-locations: classpath:mappers/*.xml
type-aliases-package: com.example.domain.model
2. エンティティとマッパー
従業員エンティティ(Employee.java)
package com.example.domain.model;
public class Employee {
private Long id;
private String firstName;
private String lastName;
private String email;
private Integer age;
// ゲッターとセッター (省略)
}
マッパーインターフェース(EmployeeMapper.java)
package com.example.mapper;
import com.example.domain.model.Employee;
import org.apache.ibatis.annotations.*;
import java.util.List;
@Mapper
public interface EmployeeMapper {
@Select("SELECT * FROM employees WHERE id = #{id}")
Employee fetchById(@Param("id") Long employeeId);
@Select("SELECT * FROM employees")
List<Employee> fetchAll();
@Select("SELECT * FROM employees WHERE last_name = #{lastName}")
List<Employee> findByLastName(@Param("lastName") String surname);
@Select("SELECT * FROM employees WHERE age > #{minAge} AND age < #{maxAge}")
List<Employee> findByAgeRange(@Param("minAge") int min, @Param("maxAge") int max);
@Insert("INSERT INTO employees(first_name, last_name, email, age) VALUES(#{fn}, #{ln}, #{em}, #{ag})")
@Options(useGeneratedKeys = true, keyProperty = "id")
void insertEmployee(@Param("fn") String firstName,
@Param("ln") String lastName,
@Param("em") String email,
@Param("ag") int age);
@Update("UPDATE employees SET email = #{email} WHERE id = #{id}")
int updateEmail(@Param("id") Long employeeId, @Param("email") String newEmail);
@Delete("DELETE FROM employees WHERE id = #{id}")
int remove(@Param("id") Long employeeId);
}
3. 各種クエリ操作
単純検索(主キーによる取得)
Employee employee = employeeMapper.fetchById(101L);
System.out.println(employee.getFirstName() + " " + employee.getLastName());
条件検索(年齢範囲)
List<Employee> midAgeWorkers = employeeMapper.findByAgeRange(25, 40);
midAgeWorkers.forEach(e -> System.out.println(e.getEmail()));
ページネーション
LIMIT と OFFSET を利用したページング。マッパーに追加:
@Select("SELECT * FROM employees ORDER BY id LIMIT #{pageSize} OFFSET #{offset}")
List<Employee> findWithPagination(@Param("offset") int offset,
@Param("pageSize") int pageSize);
サービス層での利用例:
int page = 2;
int size = 20;
int start = (page - 1) * size;
List<Employee> employees = employeeMapper.findWithPagination(start, size);
for (Employee emp : employees) {
System.out.println(emp.getFirstName());
}
関連テーブルとの結合
部署テーブル(departments)を用意し、従業員と部署を結合する例。
部署エンティティ:
package com.example.domain.model;
public class Department {
private Long id;
private String name;
private String location;
// ゲッターとセッター
}
従業員マッパーに結合メソッド追加(アノテーション使用):
@Select("SELECT e.*, d.name AS dept_name FROM employees e " +
"JOIN departments d ON e.department_id = d.id WHERE e.id = #{eid}")
@Results({
@Result(property = "id", column = "id"),
@Result(property = "firstName", column = "first_name"),
@Result(property = "department", column = "department_id",
one = @One(select = "com.example.mapper.DepartmentMapper.findById"))
})
Employee findEmployeeWithDepartment(@Param("eid") Long employeeId);
DepartmentMapper の定義:
package com.example.mapper;
import com.example.domain.model.Department;
import org.apache.ibatis.annotations.*;
@Mapper
public interface DepartmentMapper {
@Select("SELECT * FROM departments WHERE id = #{id}")
Department findById(@Param("id") Long deptId);
}
呼び出し例:
Employee emp = employeeMapper.findEmployeeWithDepartment(101L);
System.out.println(emp.getFirstName() + " belongs to " + emp.getDepartment().getName());
動的SQL(XML マッパー利用)
アノテーションでは複雑な条件分岐が難しい場合、XML を用いる。以下は EmployeeMapper.xml :
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.mapper.EmployeeMapper">
<select id="searchByFlexibleCondition" parameterType="map"
resultType="com.example.domain.model.Employee">
SELECT * FROM employees
<where>
<if test="lastName != null and lastName != ''">
AND last_name LIKE CONCAT('%', #{lastName}, '%')
</if>
<if test="age != null">
AND age = #{age}
</if>
<if test="emailSuffix != null">
AND email LIKE CONCAT('%@', #{emailSuffix})
</if>
</where>
</select>
</mapper>
マッパーインターフェースにメソッド宣言:
List<Employee> searchByFlexibleCondition(Map<String, Object> params);
利用サンプル:
Map<String, Object> conditions = new HashMap<>();
conditions.put("lastName", "Smith");
conditions.put("age", 30);
// emailSuffix は指定しない
List<Employee> result = employeeMapper.searchByFlexibleCondition(conditions);
result.forEach(emp -> System.out.println(emp.getEmail()));