注意:このライブラリは現在開発中です。不具合や未開発のAPIを含む点に注意してください。
BatisFluidは、Seasar2のJdbcManagerのような操作性を提供する、モダンでミニマルなMyBatisラッパーライブラリです。
fluent API、型安全性、externalized SQLサポートを提供します。
v0.0.2の変更点:
SeasarBatisからBatisFluidにリブランドしました。
旧API(SB*クラス)は非推奨となり、v0.0.3以降で削除予定です。
移行ガイド: MIGRATION_GUIDE_v0.0.1_to_v0.0.2.md
<dependency>
<groupId>jp.vemi</groupId>
<artifactId>batis-fluid-core</artifactId>
<version>0.0.2</version>
</dependency>
<!-- 必要な依存関係 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.15</version>
</dependency>dependencies {
implementation 'jp.vemi:batis-fluid-core:0.0.2'
// 必要な依存関係
implementation 'org.mybatis:mybatis:3.5.15'
}<dependency>
<groupId>jp.vemi</groupId>
<artifactId>seasar-batis</artifactId>
<version>0.0.1</version>
</dependency>dependencies {
implementation 'jp.vemi:seasar-batis:0.0.1'
}SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder()
.build(Resources.getResourceAsStream("mybatis-config.xml"));
// BatisFluidを使用
BatisFluid fluid = BatisFluid.of(sqlSessionFactory);
JdbcFlow flow = fluid.jdbcFlow();SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder()
.build(Resources.getResourceAsStream("mybatis-config.xml"));
SBJdbcManager jdbcManager = new SBJdbcManager(sqlSessionFactory); // 非推奨Spring Frameworkと統合する場合は、以下の追加依存関係が必要です。
<!-- BatisFluid Spring統合モジュール -->
<dependency>
<groupId>jp.vemi</groupId>
<artifactId>batis-fluid-spring</artifactId>
<version>0.0.2</version>
</dependency>
<!-- Spring統合用の追加依存関係 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>3.0.3</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>6.1.3</version>
</dependency>// BatisFluid Spring統合モジュール
implementation 'jp.vemi:batis-fluid-spring:0.0.2'
// Spring統合用の追加依存関係
implementation 'org.mybatis:mybatis-spring:3.0.3'
implementation 'org.springframework:spring-jdbc:6.1.3'<!-- SeasarBatis Spring統合モジュール -->
<dependency>
<groupId>jp.vemi</groupId>
<artifactId>seasar-batis-spring</artifactId>
<version>0.0.1</version>
</dependency>// SeasarBatis Spring統合モジュール
implementation 'jp.vemi:seasar-batis-spring:0.0.1'application.ymlに以下の設定を追加します:
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/your_database
username: your_username
password: your_password
mybatis:
configuration:
map-underscore-to-camel-case: trueJavaコンフィグを追加:
@Configuration
public class SeasarBatisConfig {
@Bean
public SBJdbcManager sbJdbcManager(SqlSessionFactory sqlSessionFactory) {
return new SBJdbcManager(sqlSessionFactory);
}
}SBJdbcManagerはSeasar2のJdbcManagerに似た操作性を提供するユーティリティクラスです。
@Autowired
private SBJdbcManager jdbcManager;
// エンティティの取得(主キー指定)
User pk = new User();
pk.setId(1L);
User user = jdbcManager.findByPk(pk).getSingleResult();
// 一覧取得
List<User> users = jdbcManager.findAll(User.class);
// エンティティの保存
User newUser = new User();
newUser.setName("John");
jdbcManager.insert(newUser);
// エンティティの更新(主キーを持つエンティティを渡す)
user.setName("Jane");
jdbcManager.update(user);
// エンティティの削除(主キーを持つエンティティを渡す)
User toDelete = new User();
toDelete.setId(1L);
jdbcManager.delete(toDelete);Seasar2のJdbcManagerと同様のスタイルでクエリを構築できます:
// 単一の結果を取得
User user = jdbcManager
.from(User.class)
.where()
.eq("name", "John")
.getSingleResult();
// 検索結果のリストを取得
List<User> users = jdbcManager
.from(User.class)
.where()
.ge("age", 20)
.like("name", "J%")
.orderBy("name ASC")
.getResultList();
// ComplexWhereとの組み合わせ
List<User> complexUsers = jdbcManager
.from(User.class)
.where(jdbcManager
.complexWhere()
.add(jdbcManager.where().eq("status", "ACTIVE"))
.or()
.add(jdbcManager.where().eq("role", "ADMIN")))
.orderBy("id DESC")
.getResultList();WHERE句を使用した更新操作も提供しています:
// 単純な条件での更新
int updatedRows = jdbcManager
.update(User.class)
.set("status", "INACTIVE")
.set("updatedAt", new Date())
.where(jdbcManager.where()
.eq("department", "IT")
.gt("age", 30))
.execute();
// 複合条件での更新
int updatedRows = jdbcManager
.update(User.class)
.set("role", "MANAGER")
.where(jdbcManager
.complexWhere()
.add(jdbcManager.where()
.eq("status", "ACTIVE")
.gt("experience", 5))
.or()
.add(jdbcManager.where()
.eq("department", "SALES")
.ge("performance", 90)))
.execute();SBJdbcManagerは効率的なバッチ処理もサポートしています:
// 複数エンティティの一括登録
List<User> users = Arrays.asList(
new User("Alice", 25),
new User("Bob", 30),
new User("Charlie", 35)
);
List<User> insertedUsers = jdbcManager.batchInsert(users);
// 複数エンティティの一括更新
users.forEach(user -> user.setStatus("ACTIVE"));
List<Integer> updateCounts = jdbcManager.batchUpdate(users);
// 複数エンティティの一括削除
List<Integer> deleteCounts = jdbcManager.batchDelete(users);
// 複数エンティティの一括登録または更新
List<User> mixedUsers = Arrays.asList(
existingUser, // 存在する場合は更新
newUser1, // 存在しない場合は登録
newUser2 // 存在しない場合は登録
);
List<User> processedUsers = jdbcManager.batchInsertOrUpdate(mixedUsers);
// 独立したトランザクションでのバッチ処理
List<User> results = jdbcManager.batchInsert(users, true);バッチ処理の利点:
- 複数のエンティティを一度のトランザクションで処理するため、パフォーマンスが向上
- トランザクションの境界が明確で、データ整合性が保たれる
- エラー発生時は、バッチ全体がロールバックされる
使用上の注意:
- 大量のデータを処理する場合は、メモリ使用量に注意してください
isIndependentTransactionフラグを使用して、既存のトランザクションとの分離レベルを制御できます- 空のリストやnullを渡すと
SBIllegalStateExceptionがスローされます
トランザクションをラムダ式で簡単に扱えます:
jdbcManager.transaction(manager -> {
User user = new User();
user.setName("John");
manager.insert(user);
Address address = new Address();
address.setUserId(user.getId());
address.setCity("Tokyo");
manager.insert(address);
});SQL文を直接実行することもできます:
// SELECT文の実行
Map<String, Object> params = new HashMap<>();
params.put("status", "ACTIVE");
List<User> users = jdbcManager.selectBySql(
"SELECT * FROM users WHERE status = /*status*/''",
params
);
// SQLファイルの実行
List<User> users = jdbcManager.selectBySqlFile(
"sql/selectUsers.sql",
params
);generatorConfig.xmlに以下のプラグイン設定を追加してください:
<plugin type="jp.vemi.seasarbatis.generator.SBEntityMetaPlugin">
<property name="addSchemaName" value="true"/>
</plugin>完全な設定例はsrc/test/resources/sample-generatorConfig.xmlを参照してください。
SeasarBatisは日本語と英語に対応した国際化機能を提供します。
import jp.vemi.seasarbatis.core.i18n.SBLocaleConfig;
// 日本語に設定
SBLocaleConfig.getInstance().setJapanese();
// 英語に設定
SBLocaleConfig.getInstance().setEnglish();
// システムのデフォルトロケールに設定
SBLocaleConfig.getInstance().setDefault();import jp.vemi.seasarbatis.core.i18n.SBMessageManager;
SBMessageManager messageManager = SBMessageManager.getInstance();
// 基本的なメッセージの取得
String message = messageManager.getMessage("transaction.error.execution");
// パラメータ付きメッセージの取得
String paramMessage = messageManager.getMessage("transaction.error.savepoint.not.found", "SP001");SeasarBatisの例外クラスは自動的に現在のロケールに応じたメッセージを表示します:
// ロケールが日本語の場合:「トランザクション実行エラー」
// ロケールが英語の場合:「Transaction execution error」
throw new SBTransactionException("transaction.error.execution");- トランザクション関連エラー
- エンティティ操作エラー
- SQL実行エラー
- 一般的なエラーメッセージ
詳細なメッセージ一覧はsrc/main/resources/jp/vemi/seasarbatis/messages.propertiesとmessages_ja.propertiesを参照してください。
BatisFluid は、バージョンカラムまたは最終更新日時カラムに基づく楽観的排他制御をサポートします。更新時に自動で条件を付与し、競合が検出された場合は例外をスローします。詳細は OPTIMISTIC_LOCKING.md を参照してください。
@FluidTable(name = "users") // v0.0.2の新アノテーション
public class User {
@FluidColumn(name = "id", primaryKey = true)
private Long id;
@FluidColumn(name = "name")
private String name;
// バージョン方式
@FluidColumn(name = "version", versionColumn = true)
private Long version;
// または、最終更新日時方式
// @FluidColumn(name = "updated_at", lastModifiedColumn = true)
// private LocalDateTime updatedAt;
}@SBTableMeta(name = "users") // v0.0.2で非推奨
public class User {
@SBColumnMeta(name = "id", primaryKey = true)
private Long id;
@SBColumnMeta(name = "name")
private String name;
@SBColumnMeta(name = "version", versionColumn = true)
private Long version;
}src/main/resources/batisfluid-optimistic-lock.properties で制御方式を上書きできます。
batisfluid.optimistic-lock.enabled=true
batisfluid.optimistic-lock.default-type=NONE
# エンティティごとの上書き
batisfluid.optimistic-lock.entity.com.example.User.type=VERSION
batisfluid.optimistic-lock.entity.com.example.User.column=version
batisfluid.optimistic-lock.entity.com.example.Order.type=LAST_MODIFIED
batisfluid.optimistic-lock.entity.com.example.Order.column=updated_atsrc/main/resources/seasarbatis-optimistic-lock.properties も引き続きサポートされますが、
将来のバージョンでは削除されます。
seasarbatis.optimistic-lock.enabled=true
seasarbatis.optimistic-lock.default-type=NONE
# エンティティごとの上書き
seasarbatis.optimistic-lock.entity.com.example.User.type=VERSION
seasarbatis.optimistic-lock.entity.com.example.User.column=version
seasarbatis.optimistic-lock.entity.com.example.Order.type=LAST_MODIFIED
seasarbatis.optimistic-lock.entity.com.example.Order.column=updated_atimport jp.vemi.seasarbatis.core.config.SBOptimisticLockConfig;
import jp.vemi.seasarbatis.core.config.SBOptimisticLockConfig.EntityLockConfig;
import jp.vemi.seasarbatis.core.config.SBOptimisticLockConfig.LockType;
SBOptimisticLockConfig config = new SBOptimisticLockConfig()
.setEnabled(true)
.setDefaultLockType(LockType.VERSION)
.addEntityConfig(User.class, new EntityLockConfig(LockType.VERSION, null))
.addEntityConfig(Order.class, new EntityLockConfig(LockType.LAST_MODIFIED, "updated_at"));
SBJdbcManager jdbcManager = new SBJdbcManager(sqlSessionFactory, config);User user = jdbcManager.findByPk(pk).getSingleResult();
Long originalVersion = user.getVersion();
user.setName("Updated");
User updated = jdbcManager.update(user);
// VERSION なら自動で +1 される
assert updated.getVersion().equals(originalVersion + 1);try {
User u = jdbcManager.findByPk(pk).getSingleResult();
u.setName("Updated");
jdbcManager.update(u);
} catch (SBOptimisticLockException e) {
// 競合。最新データを取得して再実行など
}より詳しい設計や制約、エッジケースは OPTIMISTIC_LOCKING.md を参照してください。
/*IF*///*BEGIN*///*END*/を含む S2JDBC スタイルの SQL コメントはネストや複数行に対応しました。コレクション型パラメータはIN句で自動的に個別プレースホルダへ展開され、デフォルトリテラルがそのままフォールバック値として機能します。LIKE句ではデフォルトのワイルドカードを保持したまま#{param}へ置換されるため、/*keyword*/'%'のようなパターンも安全に利用できます。- SQL ファイル互換性テストに加え、H2 と MySQL/Oracle/PostgreSQL/SQL Server(いずれも Testcontainers)向けの統合テストを追加し、
sql/complex-users-query.sqlをサンプルとして実環境相当の動作確認を行っています。 - 未実装の構文:
/*ELSE*/ブロック、FOR/FOREACH互換記法、Oracle 固有方言の自動最適化などは今後のロードマップに残っています。これらはdocs/SQL-PARSER-DESIGN.mdに整理された設計方針と既知の制約を参照してください。