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 the Db utility class that offers static methods for direct database operations without requiring service layer dependency injection. This is particularly useful in utility classes, static contexts, or when you need database operations outside of the traditional service layer.
The main static utility class providing all common database operations.
public class Db {
// Save operations
public static <T> boolean save(T entity);
public static <T> boolean saveBatch(Collection<T> entityList);
public static <T> boolean saveBatch(Collection<T> entityList, int batchSize);
public static <T> boolean saveOrUpdate(T entity);
public static <T> boolean saveOrUpdateBatch(Collection<T> entityList);
public static <T> boolean saveOrUpdateBatch(Collection<T> entityList, int batchSize);
// Remove operations
public static <T> boolean removeById(Object entity);
public static <T> boolean removeById(Class<T> entityClass, Serializable id);
public static <T> boolean removeByIds(Class<T> entityClass, Collection<? extends Serializable> list);
public static <T> boolean removeByMap(Class<T> entityClass, Map<String, Object> map);
public static <T> boolean remove(Class<T> entityClass, Wrapper<T> queryWrapper);
// Update operations
public static <T> boolean updateById(T entity);
public static <T> boolean update(Class<T> entityClass, Wrapper<T> updateWrapper);
public static <T> boolean update(Class<T> entityClass, T entity, Wrapper<T> updateWrapper);
public static <T> boolean updateBatchById(Collection<T> entityList);
public static <T> boolean updateBatchById(Collection<T> entityList, int batchSize);
// Query operations
public static <T> T getById(Class<T> entityClass, Serializable id);
public static <T> T getOne(Class<T> entityClass, Wrapper<T> queryWrapper);
public static <T> T getOne(Class<T> entityClass, Wrapper<T> queryWrapper, boolean throwEx);
public static <T> Optional<T> getOptById(Class<T> entityClass, Serializable id);
public static <T> Optional<T> getOneOpt(Class<T> entityClass, Wrapper<T> queryWrapper);
public static <T> Optional<T> getOneOpt(Class<T> entityClass, Wrapper<T> queryWrapper, boolean throwEx);
public static <T> Map<String, Object> getMap(Class<T> entityClass, Wrapper<T> queryWrapper);
public static <T, V> V getObj(Class<T> entityClass, Wrapper<T> queryWrapper, Function<? super Object, V> mapper);
// List operations
public static <T> List<T> list(Class<T> entityClass);
public static <T> List<T> list(Class<T> entityClass, Wrapper<T> queryWrapper);
public static <T> List<T> listByIds(Class<T> entityClass, Collection<? extends Serializable> idList);
public static <T> List<T> listByMap(Class<T> entityClass, Map<String, Object> columnMap);
public static <T> List<Map<String, Object>> listMaps(Class<T> entityClass);
public static <T> List<Map<String, Object>> listMaps(Class<T> entityClass, Wrapper<T> queryWrapper);
public static <T, V> List<V> listObjs(Class<T> entityClass);
public static <T, V> List<V> listObjs(Class<T> entityClass, Function<? super Object, V> mapper);
public static <T, V> List<V> listObjs(Class<T> entityClass, Wrapper<T> queryWrapper);
public static <T, V> List<V> listObjs(Class<T> entityClass, Wrapper<T> queryWrapper, Function<? super Object, V> mapper);
// Count operations
public static <T> long count(Class<T> entityClass);
public static <T> long count(Class<T> entityClass, Wrapper<T> queryWrapper);
public static <T> boolean exists(Class<T> entityClass, Wrapper<T> queryWrapper);
// Pagination operations
public static <T> Page<T> page(Class<T> entityClass, IPage<T> page);
public static <T> Page<T> page(Class<T> entityClass, IPage<T> page, Wrapper<T> queryWrapper);
public static <T> Page<Map<String, Object>> pageMaps(Class<T> entityClass, IPage<T> page, Wrapper<T> queryWrapper);
// Chain operations
public static <T> QueryChainWrapper<T> query(Class<T> entityClass);
public static <T> LambdaQueryChainWrapper<T> lambdaQuery(Class<T> entityClass);
public static <T> KtQueryChainWrapper<T> ktQuery(Class<T> entityClass);
public static <T> UpdateChainWrapper<T> update(Class<T> entityClass);
public static <T> LambdaUpdateChainWrapper<T> lambdaUpdate(Class<T> entityClass);
public static <T> KtUpdateChainWrapper<T> ktUpdate(Class<T> entityClass);
}Factory class for creating chain wrappers directly with mappers or entity classes.
public class ChainWrappers {
// Query chain factory methods
public static <T> QueryChainWrapper<T> queryChain(BaseMapper<T> baseMapper);
public static <T> QueryChainWrapper<T> queryChain(Class<T> entityClass);
public static <T> LambdaQueryChainWrapper<T> lambdaQueryChain(BaseMapper<T> baseMapper);
public static <T> LambdaQueryChainWrapper<T> lambdaQueryChain(Class<T> entityClass);
public static <T> KtQueryChainWrapper<T> ktQueryChain(BaseMapper<T> baseMapper);
public static <T> KtQueryChainWrapper<T> ktQueryChain(Class<T> entityClass);
// Update chain factory methods
public static <T> UpdateChainWrapper<T> updateChain(BaseMapper<T> baseMapper);
public static <T> UpdateChainWrapper<T> updateChain(Class<T> entityClass);
public static <T> LambdaUpdateChainWrapper<T> lambdaUpdateChain(BaseMapper<T> baseMapper);
public static <T> LambdaUpdateChainWrapper<T> lambdaUpdateChain(Class<T> entityClass);
public static <T> KtUpdateChainWrapper<T> ktUpdateChain(BaseMapper<T> baseMapper);
public static <T> KtUpdateChainWrapper<T> ktUpdateChain(Class<T> entityClass);
}// Save single entity
User user = new User("John Doe", "john@example.com");
boolean saved = Db.save(user);
if (saved) {
System.out.println("User saved with ID: " + user.getId());
}
// Save batch
List<User> users = Arrays.asList(
new User("Alice", "alice@example.com"),
new User("Bob", "bob@example.com"),
new User("Charlie", "charlie@example.com")
);
boolean allSaved = Db.saveBatch(users);
// Save batch with custom batch size
boolean saved = Db.saveBatch(users, 50);
// Save or update
User existingUser = Db.getById(User.class, 1L);
if (existingUser != null) {
existingUser.setEmail("newemail@example.com");
boolean updated = Db.saveOrUpdate(existingUser);
}// Get by ID
User user = Db.getById(User.class, 1L);
if (user != null) {
System.out.println("Found user: " + user.getName());
}
// Get with Optional
Optional<User> optionalUser = Db.getOptById(User.class, 1L);
optionalUser.ifPresent(u -> System.out.println("User: " + u.getName()));
// Get single with conditions
User activeUser = Db.getOne(User.class,
new QueryWrapper<User>().eq("active", true).eq("email", "john@example.com"));
// Get single with Optional
Optional<User> optUser = Db.getOneOpt(User.class,
new QueryWrapper<User>().eq("email", "unique@example.com"));
// List all
List<User> allUsers = Db.list(User.class);
// List with conditions
List<User> activeUsers = Db.list(User.class,
new QueryWrapper<User>().eq("active", true));
// List by IDs
List<User> specificUsers = Db.listByIds(User.class, Arrays.asList(1L, 2L, 3L));
// List by column map
Map<String, Object> conditions = new HashMap<>();
conditions.put("active", true);
conditions.put("age", 30);
List<User> users = Db.listByMap(User.class, conditions);// Count all
long totalUsers = Db.count(User.class);
System.out.println("Total users: " + totalUsers);
// Count with conditions
long activeUsers = Db.count(User.class,
new QueryWrapper<User>().eq("active", true));
long adultUsers = Db.count(User.class,
new QueryWrapper<User>().ge("age", 18));
// Check existence
boolean hasActiveUsers = Db.exists(User.class,
new QueryWrapper<User>().eq("active", true));
if (hasActiveUsers) {
System.out.println("Active users exist");
}// Update by ID
User user = Db.getById(User.class, 1L);
if (user != null) {
user.setEmail("updated@example.com");
user.setUpdatedTime(LocalDateTime.now());
boolean updated = Db.updateById(user);
}
// Update with conditions (using wrapper only)
boolean updated = Db.update(User.class,
new UpdateWrapper<User>()
.set("active", false)
.set("updated_time", LocalDateTime.now())
.eq("last_login", null)
);
// Update with entity and conditions
User updateEntity = new User();
updateEntity.setActive(false);
boolean updated = Db.update(User.class, updateEntity,
new UpdateWrapper<User>().gt("age", 65));
// Batch update by IDs
List<User> usersToUpdate = Db.listByIds(User.class, Arrays.asList(1L, 2L, 3L));
usersToUpdate.forEach(user -> user.setActive(true));
boolean allUpdated = Db.updateBatchById(usersToUpdate);// Remove by entity (uses entity's ID)
User user = Db.getById(User.class, 1L);
boolean removed = Db.removeById(user);
// Remove by class and ID
boolean removed = Db.removeById(User.class, 1L);
// Remove by IDs
boolean removed = Db.removeByIds(User.class, Arrays.asList(1L, 2L, 3L));
// Remove by column map
Map<String, Object> conditions = new HashMap<>();
conditions.put("active", false);
conditions.put("last_login", null);
boolean removed = Db.removeByMap(User.class, conditions);
// Remove with conditions
boolean removed = Db.remove(User.class,
new QueryWrapper<User>()
.eq("active", false)
.lt("created_time", LocalDateTime.now().minusYears(1))
);// Basic pagination
Page<User> page = new Page<>(1, 10);
Page<User> result = Db.page(User.class, page);
List<User> users = result.getRecords();
long total = result.getTotal();
// Pagination with conditions
Page<User> conditionPage = Db.page(User.class, new Page<>(1, 15),
new QueryWrapper<User>().eq("active", true).orderByDesc("created_time"));
// Paginate map results
Page<Map<String, Object>> mapPage = Db.pageMaps(User.class, new Page<>(1, 10),
new QueryWrapper<User>().select("id", "name", "email"));// Get as map
Map<String, Object> userMap = Db.getMap(User.class,
new QueryWrapper<User>().eq("id", 1L));
// List as maps
List<Map<String, Object>> userMaps = Db.listMaps(User.class,
new QueryWrapper<User>().eq("active", true));
// List specific objects
List<String> emails = Db.listObjs(User.class,
new QueryWrapper<User>().select("email").eq("active", true),
Object::toString);
// List all emails
List<String> allEmails = Db.listObjs(User.class, Object::toString);// Query chains
List<User> activeUsers = Db.query(User.class)
.eq("active", true)
.gt("age", 18)
.orderByDesc("created_time")
.list();
User user = Db.lambdaQuery(User.class)
.eq(User::getActive, true)
.eq(User::getEmail, "john@example.com")
.one();
// Update chains
boolean updated = Db.update(User.class)
.set("last_login", LocalDateTime.now())
.eq("id", 1L)
.update();
boolean deactivated = Db.lambdaUpdate(User.class)
.set(User::getActive, false)
.isNull(User::getLastLogin)
.update();
// Remove with chains
boolean removed = Db.update(User.class)
.eq("active", false)
.lt("created_time", LocalDateTime.now().minusMonths(6))
.remove();// Using ChainWrappers with entity class
List<User> users = ChainWrappers.queryChain(User.class)
.eq("department", "IT")
.isNotNull("email")
.orderByAsc("name")
.list();
boolean updated = ChainWrappers.updateChain(User.class)
.set("department", "Engineering")
.eq("department", "IT")
.update();
// Lambda chains with ChainWrappers
List<User> managers = ChainWrappers.lambdaQueryChain(User.class)
.eq(User::getRole, "MANAGER")
.isNotNull(User::getTeamId)
.orderByDesc(User::getCreatedTime)
.list();
boolean updated = ChainWrappers.lambdaUpdateChain(User.class)
.set(User::getStatus, "ACTIVE")
.eq(User::getRole, "USER")
.update();public class UserUtils {
// Static utility methods using Db class
public static List<User> findActiveUsersByDepartment(String department) {
return Db.list(User.class,
new QueryWrapper<User>()
.eq("active", true)
.eq("department", department)
.orderByAsc("name")
);
}
public static boolean deactivateInactiveUsers(int inactiveDays) {
LocalDateTime cutoffDate = LocalDateTime.now().minusDays(inactiveDays);
return Db.update(User.class,
new UpdateWrapper<User>()
.set("active", false)
.set("deactivated_time", LocalDateTime.now())
.lt("last_login", cutoffDate)
.eq("active", true)
);
}
public static long countUsersByRole(String role) {
return Db.count(User.class,
new QueryWrapper<User>().eq("role", role).eq("active", true)
);
}
public static Page<User> searchUsers(String keyword, int page, int size) {
return Db.page(User.class, new Page<>(page, size),
new QueryWrapper<User>()
.and(wrapper -> wrapper
.like("name", keyword)
.or()
.like("email", keyword)
)
.eq("active", true)
.orderByDesc("created_time")
);
}
public static boolean bulkUpdateUserStatus(List<Long> userIds, String status) {
return Db.update(User.class,
new UpdateWrapper<User>()
.set("status", status)
.set("updated_time", LocalDateTime.now())
.in("id", userIds)
);
}
public static void cleanupOldInactiveUsers() {
LocalDateTime cutoffDate = LocalDateTime.now().minusYears(2);
Db.remove(User.class,
new QueryWrapper<User>()
.eq("active", false)
.lt("deactivated_time", cutoffDate)
);
}
}@Component
public class UserMaintenanceScheduler {
@Scheduled(cron = "0 0 2 * * ?") // Daily at 2 AM
public void deactivateInactiveUsers() {
// Deactivate users inactive for 90 days
LocalDateTime cutoffDate = LocalDateTime.now().minusDays(90);
long count = Db.update(User.class,
new UpdateWrapper<User>()
.set("active", false)
.set("deactivated_time", LocalDateTime.now())
.lt("last_login", cutoffDate)
.eq("active", true)
) ? 1 : 0;
if (count > 0) {
System.out.println("Deactivated inactive users");
}
}
@Scheduled(cron = "0 0 3 * * 0") // Weekly on Sunday at 3 AM
public void cleanupOldData() {
// Remove users inactive for over 2 years
LocalDateTime cutoffDate = LocalDateTime.now().minusYears(2);
boolean removed = Db.remove(User.class,
new QueryWrapper<User>()
.eq("active", false)
.lt("deactivated_time", cutoffDate)
);
if (removed) {
System.out.println("Cleaned up old inactive user data");
}
}
}public class DataMigrationUtils {
public static void migrateUserRoles() {
// Update old role format to new format
Db.update(User.class,
new UpdateWrapper<User>()
.set("role", "ADMIN")
.eq("role", "admin")
);
Db.update(User.class,
new UpdateWrapper<User>()
.setSql("role = UPPER(role)")
.ne("role", "ADMIN")
);
}
public static void addDefaultValues() {
// Add default values for users missing certain fields
Db.update(User.class,
new UpdateWrapper<User>()
.set("status", "ACTIVE")
.isNull("status")
);
Db.update(User.class,
new UpdateWrapper<User>()
.set("created_time", LocalDateTime.now())
.isNull("created_time")
);
}
public static void normalizeEmailAddresses() {
// Normalize email addresses to lowercase
List<User> users = Db.list(User.class,
new QueryWrapper<User>().isNotNull("email")
);
List<User> toUpdate = users.stream()
.filter(user -> !user.getEmail().equals(user.getEmail().toLowerCase()))
.peek(user -> user.setEmail(user.getEmail().toLowerCase()))
.collect(Collectors.toList());
if (!toUpdate.isEmpty()) {
Db.updateBatchById(toUpdate);
}
}
}@Component
public class UserCacheManager {
@Cacheable(value = "users", key = "#id")
public User getCachedUser(Long id) {
return Db.getById(User.class, id);
}
@CacheEvict(value = "users", key = "#user.id")
public boolean updateUserWithCacheEviction(User user) {
return Db.updateById(user);
}
@CacheEvict(value = "users", allEntries = true)
public void clearUserCache() {
// Cache will be cleared after method execution
}
public List<User> getActiveUsersWithCache() {
// Check cache first, then database
return Db.list(User.class,
new QueryWrapper<User>().eq("active", true)
);
}
}public class SafeDbOperations {
public static Optional<User> safeGetById(Long id) {
try {
return Db.getOptById(User.class, id);
} catch (Exception e) {
System.err.println("Error fetching user by ID " + id + ": " + e.getMessage());
return Optional.empty();
}
}
public static boolean safeSave(User user) {
try {
return Db.save(user);
} catch (Exception e) {
System.err.println("Error saving user: " + e.getMessage());
return false;
}
}
}public class ValidatedDbOperations {
public static List<User> findUsersByIds(Collection<Long> ids) {
if (ids == null || ids.isEmpty()) {
return Collections.emptyList();
}
return Db.listByIds(User.class, ids);
}
public static long countActiveUsers() {
return Db.count(User.class,
new QueryWrapper<User>().eq("active", true)
);
}
}public class PerformantDbOperations {
// Use batch operations for multiple records
public static boolean saveUsers(List<User> users) {
if (users.size() > 100) {
return Db.saveBatch(users, 50); // Custom batch size
} else {
return Db.saveBatch(users);
}
}
// Use specific field selection when possible
public static List<String> getUserEmails() {
return Db.listObjs(User.class,
new QueryWrapper<User>()
.select("email")
.eq("active", true),
Object::toString
);
}
// Use pagination for large result sets
public static Page<User> getLargeUserSet(int page, int size) {
return Db.page(User.class,
new Page<User>(page, size).setOptimizeCountSql(true)
);
}
}The static utility approach is particularly useful for:
Install with Tessl CLI
npx tessl i tessl/maven-com-baomidou--mybatis-plus-extension