MyBatis-Plus Extension module providing advanced features including service layers, Kotlin extensions, SQL parsers, caching mechanisms, and various interceptors for enhanced ORM functionality
—
The Service Layer is the core component of MyBatis-Plus Extension, providing a comprehensive abstraction over MyBatis CRUD operations. It consists of the IService interface that defines all common database operations and the ServiceImpl base class that provides ready-to-use implementations.
The IService<T> interface provides a complete set of CRUD operations for entity management.
public interface IService<T> {
int DEFAULT_BATCH_SIZE = 1000;
// Save operations
boolean save(T entity);
boolean saveBatch(Collection<T> entityList);
boolean saveBatch(Collection<T> entityList, int batchSize);
boolean saveOrUpdate(T entity);
boolean saveOrUpdateBatch(Collection<T> entityList);
boolean saveOrUpdateBatch(Collection<T> entityList, int batchSize);
// Remove operations
boolean removeById(Serializable id);
boolean removeByIds(Collection<? extends Serializable> idList);
boolean removeByMap(Map<String, Object> columnMap);
boolean remove(Wrapper<T> queryWrapper);
boolean removeBatchByIds(Collection<? extends Serializable> idList);
// Update operations
boolean updateById(T entity);
boolean update(T entity, Wrapper<T> updateWrapper);
boolean updateBatchById(Collection<T> entityList);
boolean updateBatchById(Collection<T> entityList, int batchSize);
// Query operations
T getById(Serializable id);
Optional<T> getOptById(Serializable id);
T getOne(Wrapper<T> queryWrapper);
Optional<T> getOneOpt(Wrapper<T> queryWrapper);
T getOne(Wrapper<T> queryWrapper, boolean throwEx);
Optional<T> getOneOpt(Wrapper<T> queryWrapper, boolean throwEx);
Map<String, Object> getMap(Wrapper<T> queryWrapper);
<V> V getObj(Wrapper<T> queryWrapper, Function<? super Object, V> mapper);
// List operations
List<T> list();
List<T> list(Wrapper<T> queryWrapper);
List<T> listByIds(Collection<? extends Serializable> idList);
List<T> listByMap(Map<String, Object> columnMap);
List<Map<String, Object>> listMaps();
List<Map<String, Object>> listMaps(Wrapper<T> queryWrapper);
<V> List<V> listObjs();
<V> List<V> listObjs(Function<? super Object, V> mapper);
<V> List<V> listObjs(Wrapper<T> queryWrapper);
<V> List<V> listObjs(Wrapper<T> queryWrapper, Function<? super Object, V> mapper);
// Count operations
long count();
long count(Wrapper<T> queryWrapper);
boolean exists(Wrapper<T> queryWrapper);
// Pagination operations
<E extends IPage<T>> E page(E page);
<E extends IPage<T>> E page(E page, Wrapper<T> queryWrapper);
<E extends IPage<Map<String, Object>>> E pageMaps(E page, Wrapper<T> queryWrapper);
// Chain operations
QueryChainWrapper<T> query();
LambdaQueryChainWrapper<T> lambdaQuery();
KtQueryChainWrapper<T> ktQuery();
UpdateChainWrapper<T> update();
LambdaUpdateChainWrapper<T> lambdaUpdate();
KtUpdateChainWrapper<T> ktUpdate();
}The ServiceImpl<M, T> abstract class provides default implementations for all IService methods.
public abstract class ServiceImpl<M extends BaseMapper<T>, T> implements IService<T> {
protected Log log = LogFactory.getLog(getClass());
@Autowired
protected M baseMapper;
// Access methods
public M getBaseMapper();
protected Class<T> getEntityClass();
protected Class<?> getMapperClass();
// Batch operations with optimized implementations
@Transactional(rollbackFor = Exception.class)
public boolean saveBatch(Collection<T> entityList, int batchSize);
@Transactional(rollbackFor = Exception.class)
public boolean saveOrUpdateBatch(Collection<T> entityList, int batchSize);
@Transactional(rollbackFor = Exception.class)
public boolean updateBatchById(Collection<T> entityList, int batchSize);
// Single entity operations
public boolean saveOrUpdate(T entity);
public T getOne(Wrapper<T> queryWrapper, boolean throwEx);
public Optional<T> getOneOpt(Wrapper<T> queryWrapper, boolean throwEx);
public Map<String, Object> getMap(Wrapper<T> queryWrapper);
public <V> V getObj(Wrapper<T> queryWrapper, Function<? super Object, V> mapper);
}// Define entity
@TableName("user")
public class User {
@TableId
private Long id;
private String name;
private String email;
private Boolean active;
// getters and setters
}
// Define service interface
public interface UserService extends IService<User> {
// Add custom methods if needed
List<User> findActiveUsers();
}
// Implement service
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
@Override
public List<User> findActiveUsers() {
return this.list(new QueryWrapper<User>().eq("active", true));
}
}@Autowired
private UserService userService;
// Save single entity
User user = new User();
user.setName("John Doe");
user.setEmail("john@example.com");
boolean saved = userService.save(user);
// Save batch
List<User> users = Arrays.asList(
new User("Alice", "alice@example.com"),
new User("Bob", "bob@example.com")
);
boolean allSaved = userService.saveBatch(users);
// Save or update (based on primary key presence)
User existingUser = userService.getById(1L);
existingUser.setEmail("newemail@example.com");
boolean updated = userService.saveOrUpdate(existingUser);// Get by ID
User user = userService.getById(1L);
Optional<User> optionalUser = userService.getOptById(1L);
// Get single with conditions
User activeUser = userService.getOne(
new QueryWrapper<User>()
.eq("active", true)
.eq("email", "john@example.com")
);
// List operations
List<User> allUsers = userService.list();
List<User> activeUsers = userService.list(
new QueryWrapper<User>().eq("active", true)
);
// Count operations
long totalUsers = userService.count();
long activeCount = userService.count(
new QueryWrapper<User>().eq("active", true)
);
// Check existence
boolean hasActiveUsers = userService.exists(
new QueryWrapper<User>().eq("active", true)
);// Update by ID
User user = userService.getById(1L);
user.setEmail("updated@example.com");
boolean updated = userService.updateById(user);
// Update with conditions
boolean updated = userService.update(
new User().setActive(false),
new UpdateWrapper<User>().eq("last_login", null)
);
// Batch update by IDs
List<User> users = userService.listByIds(Arrays.asList(1L, 2L, 3L));
users.forEach(user -> user.setActive(true));
boolean allUpdated = userService.updateBatchById(users);// Remove by ID
boolean removed = userService.removeById(1L);
// Remove by IDs
boolean allRemoved = userService.removeByIds(Arrays.asList(1L, 2L, 3L));
// Remove with conditions
boolean inactiveRemoved = userService.remove(
new QueryWrapper<User>().eq("active", false)
);
// Remove by column map
Map<String, Object> conditions = new HashMap<>();
conditions.put("active", false);
conditions.put("last_login", null);
boolean removed = userService.removeByMap(conditions);// Basic pagination
Page<User> page = new Page<>(1, 10); // current page 1, size 10
Page<User> result = userService.page(page);
List<User> records = result.getRecords();
long total = result.getTotal();
long pages = result.getPages();
// Pagination with conditions
Page<User> activePage = userService.page(
new Page<>(1, 10),
new QueryWrapper<User>().eq("active", true)
);
// Pagination with custom ordering
Page<User> orderedPage = new Page<User>(1, 10)
.addOrder(OrderItem.desc("created_time"));
Page<User> result = userService.page(orderedPage);// Query chains
List<User> users = userService.query()
.eq("active", true)
.gt("age", 18)
.list();
User user = userService.lambdaQuery()
.eq(User::getActive, true)
.eq(User::getEmail, "john@example.com")
.one();
// Update chains
boolean updated = userService.update()
.set("active", false)
.eq("last_login", null)
.update();
boolean updated = userService.lambdaUpdate()
.set(User::getActive, false)
.isNull(User::getLastLogin)
.update();// Use custom batch size for large datasets
List<User> largeUserList = createLargeUserList();
boolean saved = userService.saveBatch(largeUserList, 500); // batch size 500// Get specific fields as objects
List<String> emails = userService.listObjs(
new QueryWrapper<User>().select("email").eq("active", true),
Object::toString
);
// Get single field value
String email = userService.getObj(
new QueryWrapper<User>().select("email").eq("id", 1L),
Object::toString
);// Get results as maps for dynamic field access
List<Map<String, Object>> userMaps = userService.listMaps(
new QueryWrapper<User>().eq("active", true)
);
Map<String, Object> userMap = userService.getMap(
new QueryWrapper<User>().eq("id", 1L)
);The service layer methods return boolean values for modification operations and null/empty collections for query operations when no results are found. For methods that expect single results, you can use the throwEx parameter or Optional variants:
// Will throw exception if multiple results found
User user = userService.getOne(wrapper, true);
// Will return Optional.empty() if no result found
Optional<User> optionalUser = userService.getOneOpt(wrapper);
// Safe approach with Optional
Optional<User> user = userService.getOptById(1L);
if (user.isPresent()) {
// Process user
} else {
// Handle not found case
}Install with Tessl CLI
npx tessl i tessl/maven-com-baomidou--mybatis-plus-extension