MyBatis
MyBatisは、SQL中心の軽量な永続化フレームワークです。SQLの完全制御を提供し、XMLマッピングファイルとアノテーションベースの両方をサポートします。複雑なクエリと高パフォーマンスを重視し、企業のレガシーシステム統合に強みを持つJava向けORMライブラリです。
GitHub概要
mybatis/mybatis-3
MyBatis SQL mapper framework for Java
スター20,185
ウォッチ1,138
フォーク12,952
作成日:2013年2月14日
言語:Java
ライセンス:Apache License 2.0
トピックス
javamybatissql
スター履歴
データ取得日時: 2025/8/13 01:43
ライブラリ
MyBatis
概要
MyBatisは、SQL中心の軽量な永続化フレームワークです。SQLの完全制御を提供し、XMLマッピングファイルとアノテーションベースの両方をサポートします。複雑なクエリと高パフォーマンスを重視し、企業のレガシーシステム統合に強みを持つJava向けORMライブラリです。
詳細
MyBatisは従来のORMとは異なり、SQLを中心としたアプローチを採用しています。開発者が直接SQLを記述することで、データベースへの完全な制御を可能にし、複雑なクエリやストアドプロシージャとの統合を容易にします。動的SQL生成機能により、条件に応じて柔軟なクエリを構築できます。
主な特徴
- SQL中心設計: 生SQLの記述による完全制御
- XMLとアノテーション: 両方のマッピング方式をサポート
- 動的SQL: 条件に応じた柔軟なクエリ生成
- Spring Boot統合: シームレスな統合とトランザクション管理
- 高パフォーマンス: 最適化されたクエリ実行とキャッシュ機能
メリット・デメリット
メリット
- SQLの完全制御により複雑なクエリを効率的に実装
- 既存のデータベースやストアドプロシージャとの統合が容易
- 学習コストが低く、SQLに慣れた開発者に適している
- 軽量で高速なクエリ実行とキャッシュ機能
- Spring Bootとの優秀な統合によるエンタープライズ対応
デメリット
- SQLを直接記述するため、データベース依存のコードになりやすい
- 大量のXMLファイル管理が煩雑になる場合がある
- 自動的なスキーマ管理機能が限定的
- 動的型生成がないため、コンパイル時の型チェックが制限的
参考ページ
書き方の例
基本的なセットアップ
<!-- Maven依存関係 -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>3.0.4</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
# application.yml
spring:
datasource:
url: jdbc:mysql://localhost:3306/mydb
username: user
password: password
driver-class-name: com.mysql.cj.jdbc.Driver
mybatis:
mapper-locations: classpath:mapper/*.xml
type-aliases-package: com.example.model
configuration:
map-underscore-to-camel-case: true
cache-enabled: true
基本操作(CRUD、XMLマッピング)
// User.java
public class User {
private int id;
private String name;
private String email;
// getters and setters
}
<!-- UserMapper.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.mapper.UserMapper">
<select id="selectUser" resultType="User">
SELECT id, name, email FROM users WHERE id = #{id}
</select>
<insert id="insertUser">
INSERT INTO users (name, email) VALUES (#{name}, #{email})
</insert>
<update id="updateUser">
UPDATE users SET name = #{name}, email = #{email} WHERE id = #{id}
</update>
<delete id="deleteUser">
DELETE FROM users WHERE id = #{id}
</delete>
</mapper>
// UserMapper.java
@Mapper
public interface UserMapper {
User selectUser(int id);
void insertUser(User user);
void updateUser(User user);
void deleteUser(int id);
}
アノテーションベース
@Mapper
public interface UserMapper {
@Select("SELECT id, name, email FROM users WHERE id = #{id}")
User selectUser(int id);
@Insert("INSERT INTO users (name, email) VALUES (#{name}, #{email})")
@Options(useGeneratedKeys = true, keyProperty = "id")
void insertUser(User user);
@Update("UPDATE users SET name = #{name}, email = #{email} WHERE id = #{id}")
void updateUser(User user);
@Delete("DELETE FROM users WHERE id = #{id}")
void deleteUser(int id);
@Select("SELECT * FROM users WHERE name LIKE CONCAT('%', #{name}, '%')")
List<User> findUsersByName(String name);
}
動的SQL
<select id="findUsers" resultType="User">
SELECT * FROM users
<where>
<if test="name != null">
AND name LIKE CONCAT('%', #{name}, '%')
</if>
<if test="email != null">
AND email = #{email}
</if>
<if test="status != null">
AND status = #{status}
</if>
</where>
</select>
<update id="updateUserSelective">
UPDATE users
<set>
<if test="name != null">name = #{name},</if>
<if test="email != null">email = #{email},</if>
<if test="status != null">status = #{status}</if>
</set>
WHERE id = #{id}
</update>
<select id="findUsersByIds" resultType="User">
SELECT * FROM users
WHERE id IN
<foreach item="id" collection="ids" open="(" separator="," close=")">
#{id}
</foreach>
</select>
Spring Boot統合
@SpringBootApplication
@MapperScan("com.example.mapper")
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
@Service
@Transactional
public class UserService {
@Autowired
private UserMapper userMapper;
public User getUserById(int id) {
return userMapper.selectUser(id);
}
public void createUser(User user) {
userMapper.insertUser(user);
}
@Transactional(rollbackFor = Exception.class)
public void transferUserData(User fromUser, User toUser) {
userMapper.updateUser(fromUser);
userMapper.updateUser(toUser);
// 例外が発生した場合、自動的にロールバック
}
}
@RestController
@RequestMapping("/api/users")
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/{id}")
public User getUser(@PathVariable int id) {
return userService.getUserById(id);
}
@PostMapping
public void createUser(@RequestBody User user) {
userService.createUser(user);
}
}
高度な機能(カスタムタイプハンドラー、プラグイン等)
// カスタムタイプハンドラー
@Component
public class JsonTypeHandler implements TypeHandler<Map<String, Object>> {
private final ObjectMapper objectMapper = new ObjectMapper();
@Override
public void setParameter(PreparedStatement ps, int i, Map<String, Object> parameter,
JdbcType jdbcType) throws SQLException {
try {
ps.setString(i, objectMapper.writeValueAsString(parameter));
} catch (JsonProcessingException e) {
throw new SQLException(e);
}
}
@Override
public Map<String, Object> getResult(ResultSet rs, String columnName) throws SQLException {
try {
String json = rs.getString(columnName);
return json == null ? null : objectMapper.readValue(json, Map.class);
} catch (JsonProcessingException e) {
throw new SQLException(e);
}
}
}
// MyBatis設定
@Configuration
public class MyBatisConfig {
@Bean
public ConfigurationCustomizer mybatisConfigurer() {
return configuration -> {
// カスタムタイプハンドラー登録
configuration.getTypeHandlerRegistry()
.register(Map.class, JsonTypeHandler.class);
// キャッシュ設定
configuration.setCacheEnabled(true);
configuration.setLazyLoadingEnabled(true);
configuration.setAggressiveLazyLoading(false);
};
}
}
// 結果マップでの複雑なマッピング
<resultMap id="userWithProfileMap" type="User">
<id property="id" column="user_id"/>
<result property="name" column="user_name"/>
<result property="profile" column="profile_json"
typeHandler="com.example.handler.JsonTypeHandler"/>
<association property="department" javaType="Department">
<id property="id" column="dept_id"/>
<result property="name" column="dept_name"/>
</association>
<collection property="roles" ofType="Role">
<id property="id" column="role_id"/>
<result property="name" column="role_name"/>
</collection>
</resultMap>
<select id="selectUserWithProfile" resultMap="userWithProfileMap">
SELECT u.id as user_id, u.name as user_name, u.profile_json,
d.id as dept_id, d.name as dept_name,
r.id as role_id, r.name as role_name
FROM users u
LEFT JOIN departments d ON u.department_id = d.id
LEFT JOIN user_roles ur ON u.id = ur.user_id
LEFT JOIN roles r ON ur.role_id = r.id
WHERE u.id = #{id}
</select>