MyBatis-Plus is an enhanced toolkit for MyBatis providing CRUD operations, query wrappers, pagination, code generation, and Spring Boot integration.
—
MyBatis-Plus supports the Active Record pattern, allowing entities to perform database operations directly without requiring separate mapper or service classes, providing a more object-oriented approach to data persistence.
Abstract base class that entities can extend to gain Active Record functionality.
/**
* Active Record pattern base class
* @param <T> Entity type extending Model
*/
public abstract class Model<T extends Model<?>> implements Serializable, Cloneable {
// ==================== Insert Operations ====================
/**
* Insert current entity
* @return true if successful
*/
public boolean insert();
/**
* Insert or update current entity
* @return true if successful
*/
public boolean insertOrUpdate();
// ==================== Update Operations ====================
/**
* Update current entity by primary key
* @return true if successful
*/
public boolean updateById();
/**
* Update entities by conditions
* @param updateWrapper Update conditions wrapper
* @return true if successful
*/
public boolean update(Wrapper<T> updateWrapper);
// ==================== Delete Operations ====================
/**
* Delete current entity by primary key
* @return true if successful
*/
public boolean deleteById();
/**
* Delete entities by conditions
* @param queryWrapper Query conditions wrapper
* @return true if successful
*/
public boolean delete(Wrapper<T> queryWrapper);
// ==================== Select Operations ====================
/**
* Select entity by primary key
* @return Entity or null
*/
public T selectById();
/**
* Select entity by primary key with specified ID
* @param id Primary key value
* @return Entity or null
*/
public T selectById(Serializable id);
/**
* Select one entity by conditions
* @param queryWrapper Query conditions wrapper
* @return Entity or null
*/
public T selectOne(Wrapper<T> queryWrapper);
/**
* Select list of entities by conditions
* @param queryWrapper Query conditions wrapper
* @return List of entities
*/
public List<T> selectList(Wrapper<T> queryWrapper);
/**
* Select all entities
* @return List of all entities
*/
public List<T> selectAll();
/**
* Select paginated entities
* @param page Pagination parameters
* @param queryWrapper Query conditions wrapper
* @return Paginated results
*/
public <E extends IPage<T>> E selectPage(E page, Wrapper<T> queryWrapper);
/**
* Count entities by conditions
* @param queryWrapper Query conditions wrapper
* @return Count
*/
public long selectCount(Wrapper<T> queryWrapper);
/**
* Count all entities
* @return Total count
*/
public long selectCount();
}Entity Setup with Active Record:
@TableName("user")
public class User extends Model<User> {
@TableId(type = IdType.AUTO)
private Long id;
private String name;
private Integer age;
private String email;
private LocalDateTime createTime;
// constructors, getters, setters...
}Insert Operations:
// Create and insert new user
User user = new User();
user.setName("John Doe");
user.setAge(25);
user.setEmail("john@example.com");
boolean success = user.insert();
// user.getId() will contain the generated ID
// Insert or update (upsert)
User user = new User();
user.setId(1L); // If exists, update; otherwise insert
user.setName("Updated Name");
user.setAge(26);
boolean success = user.insertOrUpdate();Update Operations:
// Update by primary key
User user = new User();
user.setId(1L);
user.setAge(26); // Only non-null fields are updated
boolean success = user.updateById();
// Update with conditions
User user = new User();
user.setAge(30);
UpdateWrapper<User> wrapper = new UpdateWrapper<>();
wrapper.eq("department", "IT").gt("age", 25);
boolean success = user.update(wrapper);Delete Operations:
// Delete by primary key
User user = new User();
user.setId(1L);
boolean success = user.deleteById();
// Delete with conditions
User user = new User();
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.eq("status", 0).lt("last_login", LocalDateTime.now().minusMonths(6));
boolean success = user.delete(wrapper);Select Operations:
// Select by primary key
User user = new User();
user.setId(1L);
User foundUser = user.selectById(); // Returns loaded user or null
// Select by specified ID
User user = new User();
User foundUser = user.selectById(1L);
// Select one by conditions
User user = new User();
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.eq("email", "john@example.com");
User foundUser = user.selectOne(wrapper);
// Select list by conditions
User user = new User();
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.eq("status", 1).orderByDesc("create_time");
List<User> users = user.selectList(wrapper);
// Select all
User user = new User();
List<User> allUsers = user.selectAll();
// Paginated select
User user = new User();
Page<User> page = new Page<>(1, 10);
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.eq("status", 1);
IPage<User> userPage = user.selectPage(page, wrapper);
// Count operations
User user = new User();
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.eq("status", 1);
long activeUsers = user.selectCount(wrapper);
long totalUsers = user.selectCount();Chaining Operations:
// Method chaining for fluent operations
User user = new User()
.setName("Alice")
.setAge(28)
.setEmail("alice@example.com");
if (user.insert()) {
System.out.println("User created with ID: " + user.getId());
// Update the same instance
user.setAge(29);
if (user.updateById()) {
System.out.println("User updated successfully");
}
}Complex Business Logic:
public class User extends Model<User> {
// ... fields and basic methods
// Custom business methods using Active Record
public boolean activate() {
this.setStatus(1);
this.setActiveTime(LocalDateTime.now());
return this.updateById();
}
public boolean deactivate() {
this.setStatus(0);
this.setInactiveTime(LocalDateTime.now());
return this.updateById();
}
public List<User> findSimilarUsers() {
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.eq("department", this.getDepartment())
.eq("role", this.getRole())
.ne("id", this.getId());
return this.selectList(wrapper);
}
public boolean hasSameEmail() {
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.eq("email", this.getEmail())
.ne("id", this.getId());
return this.selectCount(wrapper) > 0;
}
public boolean softDelete() {
this.setDeleted(1);
this.setDeleteTime(LocalDateTime.now());
return this.updateById();
}
}
// Usage of custom methods
User user = new User().selectById(1L);
if (user != null) {
if (!user.hasSameEmail()) {
user.activate();
List<User> similar = user.findSimilarUsers();
System.out.println("Found " + similar.size() + " similar users");
}
}Error Handling:
try {
User user = new User();
user.setName("Test User");
user.setEmail("test@example.com");
if (user.insert()) {
System.out.println("User created successfully");
} else {
System.out.println("Failed to create user");
}
} catch (Exception e) {
System.err.println("Database error: " + e.getMessage());
// Handle specific exceptions like duplicate key, constraint violations, etc.
}Performance Considerations:
// Use batch operations at service layer for multiple records
// Active Record is best for single entity operations
// Good: Single entity operations
User user = new User().selectById(id);
if (user != null) {
user.setLastLogin(LocalDateTime.now());
user.updateById();
}
// Better for bulk operations: Use service layer
// userService.updateBatchById(users);
// Use Active Record for business logic methods
public class Order extends Model<Order> {
public boolean canCancel() {
return this.getStatus() == OrderStatus.PENDING
&& this.getCreateTime().isAfter(LocalDateTime.now().minusMinutes(30));
}
public boolean cancel() {
if (!canCancel()) {
return false;
}
this.setStatus(OrderStatus.CANCELLED);
this.setCancelTime(LocalDateTime.now());
return this.updateById();
}
}The Active Record pattern in MyBatis-Plus provides an intuitive, object-oriented approach to database operations while maintaining the full power of the underlying BaseMapper functionality.
Install with Tessl CLI
npx tessl i tessl/maven-com-baomidou--mybatis-plus