MyBatis-Plus Extension module providing advanced features including service layers, Kotlin extensions, SQL parsers, caching mechanisms, and various interceptors for enhanced ORM functionality
—
MyBatis-Plus Extension provides fluent API builders for constructing complex database queries and updates through method chaining. The condition builders offer both traditional string-based and type-safe lambda-based approaches for building database operations.
Query chain wrappers allow building complex SELECT queries with fluent method chaining.
public class QueryChainWrapper<T> extends AbstractChainWrapper<T, String, QueryChainWrapper<T>, QueryWrapper<T>>
implements ChainQuery<T> {
public QueryChainWrapper(BaseMapper<T> baseMapper);
public QueryChainWrapper(Class<T> entityClass);
// Terminal operations
public List<T> list();
public T one();
public Optional<T> oneOpt();
public long count();
public boolean exists();
public <E extends IPage<T>> E page(E page);
// Select operations
public QueryChainWrapper<T> select(String... columns);
public String getSqlSelect();
// Access methods
public BaseMapper<T> getBaseMapper();
public Class<T> getEntityClass();
}
public class LambdaQueryChainWrapper<T> extends AbstractChainWrapper<T, SFunction<T, ?>, LambdaQueryChainWrapper<T>, LambdaQueryWrapper<T>>
implements ChainQuery<T> {
public LambdaQueryChainWrapper(BaseMapper<T> baseMapper);
public LambdaQueryChainWrapper(Class<T> entityClass);
// Terminal operations
public List<T> list();
public T one();
public Optional<T> oneOpt();
public long count();
public boolean exists();
public <E extends IPage<T>> E page(E page);
// Select operations
public LambdaQueryChainWrapper<T> select(SFunction<T, ?>... columns);
}Update chain wrappers provide fluent API for UPDATE and DELETE operations.
public class UpdateChainWrapper<T> extends AbstractChainWrapper<T, String, UpdateChainWrapper<T>, UpdateWrapper<T>>
implements ChainUpdate<T> {
public UpdateChainWrapper(BaseMapper<T> baseMapper);
public UpdateChainWrapper(Class<T> entityClass);
// Terminal operations
public boolean update();
public boolean update(T entity);
public boolean remove();
// Set operations
public UpdateChainWrapper<T> set(String column, Object val);
public UpdateChainWrapper<T> setSql(String sql);
// Access methods
public BaseMapper<T> getBaseMapper();
public Class<T> getEntityClass();
}
public class LambdaUpdateChainWrapper<T> extends AbstractChainWrapper<T, SFunction<T, ?>, LambdaUpdateChainWrapper<T>, LambdaUpdateWrapper<T>>
implements ChainUpdate<T> {
public LambdaUpdateChainWrapper(BaseMapper<T> baseMapper);
public LambdaUpdateChainWrapper(Class<T> entityClass);
// Terminal operations
public boolean update();
public boolean update(T entity);
public boolean remove();
// Set operations
public LambdaUpdateChainWrapper<T> set(SFunction<T, ?> column, Object val);
public LambdaUpdateChainWrapper<T> setSql(String sql);
}Base interfaces defining the contract for chain operations.
public interface ChainQuery<T> {
List<T> list();
T one();
Optional<T> oneOpt();
long count();
boolean exists();
<E extends IPage<T>> E page(E page);
}
public interface ChainUpdate<T> {
boolean update();
boolean update(T entity);
boolean remove();
}
public interface ChainWrapper<T> {
BaseMapper<T> getBaseMapper();
Class<T> getEntityClass();
}public abstract class AbstractChainWrapper<T, R, Children, Wrapper> implements ChainWrapper<T> {
protected BaseMapper<T> baseMapper;
protected Class<T> entityClass;
protected Wrapper wrapper;
public BaseMapper<T> getBaseMapper();
public Class<T> getEntityClass();
protected Wrapper getWrapper();
protected Children instance();
}// Using service method to create chain
@Autowired
private UserService userService;
// Simple query chain
List<User> activeUsers = userService.query()
.eq("active", true)
.list();
// Lambda query chain with type safety
List<User> adults = userService.lambdaQuery()
.ge(User::getAge, 18)
.eq(User::getActive, true)
.list();
// Using ChainWrappers factory
List<User> users = ChainWrappers.queryChain(userMapper)
.eq("status", "ACTIVE")
.gt("created_time", LocalDateTime.now().minusDays(30))
.list();// Multiple conditions with different operators
List<User> users = userService.query()
.eq("active", true)
.ne("status", "DELETED")
.gt("age", 18)
.le("age", 65)
.like("name", "John")
.isNotNull("email")
.in("role", Arrays.asList("USER", "ADMIN"))
.between("created_time", startDate, endDate)
.orderByDesc("created_time")
.list();
// Using OR conditions
List<User> users = userService.query()
.eq("active", true)
.and(wrapper -> wrapper
.eq("role", "ADMIN")
.or()
.gt("score", 90)
)
.list();
// Nested conditions with lambda
List<User> premiumUsers = userService.lambdaQuery()
.eq(User::getActive, true)
.and(wrapper -> wrapper
.eq(User::getSubscriptionType, "PREMIUM")
.or()
.ge(User::getCredits, 1000)
)
.orderByDesc(User::getCreatedTime)
.list();// Select specific columns using string names
List<User> users = userService.query()
.select("id", "name", "email")
.eq("active", true)
.list();
// Select specific columns using lambda (type-safe)
List<User> users = userService.lambdaQuery()
.select(User::getId, User::getName, User::getEmail)
.eq(User::getActive, true)
.list();// Get single result
User user = userService.query()
.eq("email", "john@example.com")
.one();
// Get optional result (safer)
Optional<User> optionalUser = userService.lambdaQuery()
.eq(User::getEmail, "john@example.com")
.oneOpt();
if (optionalUser.isPresent()) {
User user = optionalUser.get();
// Process user
}// Count records
long totalActive = userService.query()
.eq("active", true)
.count();
// Check existence
boolean hasAdminUsers = userService.lambdaQuery()
.eq(User::getRole, "ADMIN")
.exists();// Paginated query
Page<User> page = new Page<>(1, 10);
Page<User> result = userService.query()
.eq("active", true)
.orderByDesc("created_time")
.page(page);
List<User> users = result.getRecords();
long total = result.getTotal();
// Lambda pagination
Page<User> premiumPage = userService.lambdaQuery()
.eq(User::getSubscriptionType, "PREMIUM")
.orderByDesc(User::getLastLogin)
.page(new Page<>(1, 20));// Simple update
boolean updated = userService.update()
.set("last_login", LocalDateTime.now())
.eq("id", 1L)
.update();
// Lambda update with type safety
boolean deactivated = userService.lambdaUpdate()
.set(User::getActive, false)
.set(User::getDeactivatedTime, LocalDateTime.now())
.isNull(User::getLastLogin)
.update();
// Update with entity
User updateEntity = new User();
updateEntity.setActive(false);
boolean updated = userService.lambdaUpdate()
.eq(User::getRole, "TEMP")
.update(updateEntity);// Delete with conditions
boolean removed = userService.update()
.eq("active", false)
.isNull("last_login")
.remove();
// Lambda delete
boolean removed = userService.lambdaUpdate()
.eq(User::getStatus, "DELETED")
.lt(User::getCreatedTime, LocalDateTime.now().minusYears(1))
.remove();// Multiple set operations
boolean updated = userService.update()
.set("status", "INACTIVE")
.set("deactivated_time", LocalDateTime.now())
.setSql("login_attempts = login_attempts + 1")
.eq("active", true)
.gt("failed_login_count", 5)
.update();
// Conditional updates with complex logic
boolean updated = userService.lambdaUpdate()
.set(User::getStatus, "SUSPENDED")
.set(User::getSuspendedTime, LocalDateTime.now())
.and(wrapper -> wrapper
.gt(User::getFailedLoginCount, 3)
.or()
.eq(User::getReportedByUsers, true)
)
.update();@Autowired
private UserMapper userMapper;
// Create chains directly with mapper
List<User> users = ChainWrappers.queryChain(userMapper)
.eq("department", "IT")
.orderByAsc("name")
.list();
boolean updated = ChainWrappers.updateChain(userMapper)
.set("department", "Engineering")
.eq("department", "IT")
.update();
// Lambda chains with mapper
List<User> managers = ChainWrappers.lambdaQueryChain(userMapper)
.eq(User::getRole, "MANAGER")
.isNotNull(User::getTeamId)
.list();// Using entity class instead of mapper
List<User> users = ChainWrappers.queryChain(User.class)
.eq("active", true)
.list();
boolean updated = ChainWrappers.lambdaUpdateChain(User.class)
.set(User::getLastModified, LocalDateTime.now())
.eq(User::getId, 1L)
.update();// Using setSql for complex expressions
boolean updated = userService.update()
.setSql("score = score * 1.1")
.setSql("updated_time = NOW()")
.eq("active", true)
.update();// You can still use regular QueryWrapper/UpdateWrapper for more complex scenarios
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.eq("active", true)
.nested(w -> w.eq("role", "ADMIN").or().gt("score", 90))
.orderByDesc("created_time");
List<User> users = userService.list(wrapper);// Handle single result operations safely
try {
User user = userService.query()
.eq("email", "unique@example.com")
.one(); // May throw exception if multiple results
} catch (Exception e) {
// Handle multiple results or other errors
}
// Safer approach with Optional
Optional<User> user = userService.lambdaQuery()
.eq(User::getEmail, "unique@example.com")
.oneOpt();list(), one(), update(), etc.) execute the actual database queryselect() to limit columns when you don't need the full entityInstall with Tessl CLI
npx tessl i tessl/maven-com-baomidou--mybatis-plus-extension