Improving JPA Development with MyBatis‑Flex: Practical Tips and Code Examples
This article examines the limitations of using JPA for complex queries in SpringBoot projects and demonstrates how MyBatis‑Flex can simplify conditional queries, partial field selection, Kotlin integration, and code generation through clear code examples and practical guidance.
The author introduces a SpringBoot project that initially uses JPA for persistence, appreciating its IDE support and JPQL capabilities, but points out that complex business requirements become cumbersome and unintuitive with JPA.
The article does not criticize JPA or MyBatis‑Plus, nor compare their syntax; it focuses on improving coding productivity and convenience.
Pain Points
JpaRepository (Advantages)
JpaRepository enables CRUD operations by extending the interface and allows method‑name‑derived queries, such as findByCardNo , which automatically generates SQL.
interface AppRealtimeRecordRepository : JpaRepository
{
fun findByCardNo(cardNo: String?): AppRealtimeRecord?
@Query("select count(1) from AppRealtimeRecord arr where " +
"arr.deviceSn = :#{#orderQueryRequest.deviceSn} AND " +
"arr.createTime BETWEEN COALESCE(:#{#orderQueryRequest.payStartTime}, arr.createTime) AND " +
"COALESCE(:#{#orderQueryRequest.payEndTime}, arr.createTime)")
fun summaryQuery(orderQueryRequest: OrderQueryRequest): Long
}When query conditions become numerous, method names grow excessively long, requiring the use of @Query for custom SQL.
Conditional Queries
JPA makes it difficult to build dynamic queries that depend on the presence of parameters, such as checking whether start and end times are null.
MyBatis‑Flex Solution
MyBatis‑Flex provides a fluent API that resembles writing raw SQL, automatically ignoring null conditions.
QueryWrapper query = QueryWrapper.create()
.where(EMPLOYEE.LAST_NAME.like(searchWord)) // null condition ignored
.and(EMPLOYEE.GENDER.eq(1))
.and(EMPLOYEE.AGE.gt(24));
List
employees = employeeMapper.selectListByQuery(query);Partial Field Queries
JPA always returns full entity objects, making it cumbersome to fetch only selected columns.
Use List to receive raw column data and map it manually.
Define a custom model class with only the needed fields, e.g., new Model(ParamA, ParamB) .
MyBatis‑Flex Implementation
MyBatis‑Flex allows selecting specific columns directly.
// Query all fields
QueryWrapper queryWrapper = QueryWrapper.create()
.select()
.where(ACCOUNT.AGE.eq(18));
Account account = accountMapper.selectOneByQuery(queryWrapper);
// Query specific fields
select(QueryColumn("id"), QueryColumn("name"), QueryColumn("category_id"))Kotlin Support
The author migrated a Kotlin project from JPA to MyBatis‑Flex with minimal effort, achieving more elegant code.
Pagination Query
fun detailList(fairyDetailParam: FairyDetailParam): List
{
val paginateWith = paginate
(pageNumber = fairyDetailParam.current,
pageSize = fairyDetailParam.size,
init = {
select(QueryColumn("id"), QueryColumn("name"), QueryColumn("category_id"))
whereWith {
FairyDetail::categoryId eq fairyDetailParam.categoryId
}
})
return paginateWith.records
}The query builder mirrors SQL order: select → where → orderBy .
Update User
// Update user avatar and nickname
update
{
User::avatarUrl set user.avatarUrl
whereWith {
User::openId eq user.openId
}
}Code Generation
By adding the annotation processor com.mybatis-flex:mybatis-flex-processor:1.9.3 to Gradle (or the Maven equivalent), entities, mappers, and controllers can be generated automatically from the database schema.
Entity Example
package cn.db101.jcc.entity;
import java.io.Serializable;
import java.util.Date;
import com.mybatisflex.annotation.Id;
import com.mybatisflex.annotation.KeyType;
import com.mybatisflex.annotation.Table;
import lombok.Data;
@Table("t_banner")
@Data
public class Banner {
@Id(keyType = KeyType.Auto)
private Integer id;
private String url;
private Integer sort;
private Date createTime;
}Full‑Automatic Generation
Using MyBatis‑Flex’s code generator, developers can configure data source, package, table prefixes, and column settings to produce entity classes, mappers, and other layers.
public class Codegen {
public static void main(String[] args) {
// Configure data source
HikariDataSource dataSource = new HikariDataSource();
dataSource.setJdbcUrl("jdbc:mysql://127.0.0.1:3306/your-database?characterEncoding=utf-8");
dataSource.setUsername("root");
dataSource.setPassword("******");
// Create global config (style 1)
GlobalConfig globalConfig = createGlobalConfigUseStyle1();
// Build generator and generate code
Generator generator = new Generator(dataSource, globalConfig);
generator.generate();
}
// ... (configuration methods omitted for brevity)
}Overall Usage
For developers familiar with MyBatis‑Plus, switching to MyBatis‑Flex offers a more intuitive, SQL‑like experience, reduces boilerplate, and improves productivity despite some overlap with existing tools.
Selected Java Interview Questions
A professional Java tech channel sharing common knowledge to help developers fill gaps. Follow us!
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.