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 Active Record pattern support through the Model base class, enabling entity objects to perform their own database operations. This pattern allows entities to encapsulate both data and database behavior, providing a more object-oriented approach to data access.
The abstract Model<T> class that entities can extend to gain Active Record capabilities.
public abstract class Model<T extends Model<?>> implements Serializable, Cloneable {
// Insert operations
public boolean insert();
public boolean insertOrUpdate();
// Delete operations
public boolean deleteById();
public boolean deleteById(Serializable id);
public boolean delete(Wrapper<T> queryWrapper);
// Update operations
public boolean updateById();
public boolean update(Wrapper<T> updateWrapper);
// Select operations
public T selectById();
public T selectById(Serializable id);
public T selectOne(Wrapper<T> queryWrapper);
public List<T> selectAll();
public List<T> selectList(Wrapper<T> queryWrapper);
public List<T> selectByIds(Collection<? extends Serializable> idList);
public List<T> selectByMap(Map<String, Object> columnMap);
public <E extends IPage<T>> E selectPage(E page, Wrapper<T> queryWrapper);
public long selectCount(Wrapper<T> queryWrapper);
// Utility operations
public SqlRunner sql();
protected abstract Serializable pkVal();
}@TableName("user")
public class User extends Model<User> {
@TableId(type = IdType.AUTO)
private Long id;
private String name;
private String email;
private Integer age;
private Boolean active;
private LocalDateTime createdTime;
private LocalDateTime updatedTime;
// Constructors
public User() {}
public User(String name, String email) {
this.name = name;
this.email = email;
this.active = true;
this.createdTime = LocalDateTime.now();
}
// Required: implement pkVal() method
@Override
protected Serializable pkVal() {
return this.id;
}
// Getters and setters
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
public Integer getAge() { return age; }
public void setAge(Integer age) { this.age = age; }
public Boolean getActive() { return active; }
public void setActive(Boolean active) { this.active = active; }
public LocalDateTime getCreatedTime() { return createdTime; }
public void setCreatedTime(LocalDateTime createdTime) { this.createdTime = createdTime; }
public LocalDateTime getUpdatedTime() { return updatedTime; }
public void setUpdatedTime(LocalDateTime updatedTime) { this.updatedTime = updatedTime; }
}// Create and insert new user
User newUser = new User("John Doe", "john@example.com");
newUser.setAge(30);
boolean inserted = newUser.insert();
if (inserted) {
System.out.println("User inserted with ID: " + newUser.getId());
}
// Insert or update based on primary key
User user = new User("Jane Smith", "jane@example.com");
user.setId(1L); // If ID exists, it will update; otherwise insert
boolean success = user.insertOrUpdate();// Select by primary key
User user = new User();
User foundUser = user.selectById(1L);
if (foundUser != null) {
System.out.println("Found user: " + foundUser.getName());
}
// Select current instance by its ID
User user = new User();
user.setId(1L);
User reloaded = user.selectById(); // Uses the current instance's ID
// Select all users
User user = new User();
List<User> allUsers = user.selectAll();
// Select with conditions
User user = new User();
List<User> activeUsers = user.selectList(
new QueryWrapper<User>().eq("active", true)
);
// Select single user with conditions
User user = new User();
User activeUser = user.selectOne(
new QueryWrapper<User>()
.eq("active", true)
.eq("email", "john@example.com")
);
// Select by IDs
User user = new User();
List<User> users = user.selectByIds(Arrays.asList(1L, 2L, 3L));
// Select by column map
User user = new User();
Map<String, Object> conditions = new HashMap<>();
conditions.put("active", true);
conditions.put("age", 30);
List<User> users = user.selectByMap(conditions);// Update by primary key
User user = new User();
user.setId(1L);
user.setName("Updated Name");
user.setEmail("updated@example.com");
user.setUpdatedTime(LocalDateTime.now());
boolean updated = user.updateById();
if (updated) {
System.out.println("User updated successfully");
}
// Update with conditions
User user = new User();
user.setActive(false);
user.setUpdatedTime(LocalDateTime.now());
boolean updated = user.update(
new UpdateWrapper<User>().eq("age", 25)
);// Delete by primary key (current instance)
User user = new User();
user.setId(1L);
boolean deleted = user.deleteById();
// Delete by specific ID
User user = new User();
boolean deleted = user.deleteById(2L);
// Delete with conditions
User user = new User();
boolean deleted = user.delete(
new QueryWrapper<User>()
.eq("active", false)
.lt("created_time", LocalDateTime.now().minusYears(1))
);// Count all records
User user = new User();
long totalUsers = user.selectCount(null);
// Count with conditions
User user = new User();
long activeUsers = user.selectCount(
new QueryWrapper<User>().eq("active", true)
);
long adultUsers = user.selectCount(
new QueryWrapper<User>().ge("age", 18)
);// Paginated selection
User user = new User();
Page<User> page = new Page<>(1, 10);
Page<User> result = user.selectPage(page,
new QueryWrapper<User>().eq("active", true).orderByDesc("created_time")
);
List<User> users = result.getRecords();
long total = result.getTotal();
System.out.println("Found " + total + " active users");
// Pagination without conditions
Page<User> allUsersPage = user.selectPage(new Page<>(1, 20), null);@TableName("user")
public class User extends Model<User> {
// ... fields and basic methods ...
// Custom business methods using Active Record
public boolean deactivate() {
this.active = false;
this.updatedTime = LocalDateTime.now();
return this.updateById();
}
public boolean activate() {
this.active = true;
this.updatedTime = LocalDateTime.now();
return this.updateById();
}
public List<User> findSimilarUsers() {
return this.selectList(
new QueryWrapper<User>()
.eq("age", this.age)
.ne("id", this.id)
.eq("active", true)
);
}
public boolean isAdult() {
return this.age != null && this.age >= 18;
}
public long countOlderUsers() {
if (this.age == null) return 0;
return this.selectCount(
new QueryWrapper<User>().gt("age", this.age)
);
}
public User findByEmail(String email) {
return this.selectOne(
new QueryWrapper<User>().eq("email", email)
);
}
}// Using custom entity methods
User user = new User("John", "john@example.com");
user.setAge(25);
user.insert();
// Deactivate user
boolean deactivated = user.deactivate();
// Find similar users
List<User> similarUsers = user.findSimilarUsers();
// Count older users
long olderCount = user.countOlderUsers();
// Find by email
User foundUser = new User().findByEmail("john@example.com");@TableName("user")
public class User extends Model<User> {
// ... other methods ...
public List<Map<String, Object>> getDetailedStats() {
SqlRunner sqlRunner = this.sql();
return sqlRunner.selectList(
"SELECT age, COUNT(*) as count FROM user WHERE active = ? GROUP BY age ORDER BY age",
true
);
}
public boolean updateLastLoginTime() {
SqlRunner sqlRunner = this.sql();
int affected = sqlRunner.update(
"UPDATE user SET last_login = NOW() WHERE id = ?",
this.getId()
);
return affected > 0;
}
}// Complex query example
public class User extends Model<User> {
public List<User> findRecentActiveUsers(int days, int limit) {
return this.selectList(
new QueryWrapper<User>()
.eq("active", true)
.ge("last_login", LocalDateTime.now().minusDays(days))
.orderByDesc("last_login")
.last("LIMIT " + limit)
);
}
public Page<User> searchUsers(String keyword, int page, int size) {
return this.selectPage(
new Page<>(page, size),
new QueryWrapper<User>()
.and(wrapper -> wrapper
.like("name", keyword)
.or()
.like("email", keyword)
)
.eq("active", true)
.orderByDesc("created_time")
);
}
}While Active Record pattern works best with single entities, you can still handle relationships:
@TableName("user")
public class User extends Model<User> {
// ... basic fields ...
// Get user's orders (assuming Order entity exists)
public List<Order> getOrders() {
Order orderModel = new Order();
return orderModel.selectList(
new QueryWrapper<Order>().eq("user_id", this.getId())
);
}
// Get user's active orders
public List<Order> getActiveOrders() {
Order orderModel = new Order();
return orderModel.selectList(
new QueryWrapper<Order>()
.eq("user_id", this.getId())
.eq("status", "ACTIVE")
.orderByDesc("created_time")
);
}
// Count user's orders
public long getOrderCount() {
Order orderModel = new Order();
return orderModel.selectCount(
new QueryWrapper<Order>().eq("user_id", this.getId())
);
}
}@Override
protected Serializable pkVal() {
return this.id; // Return the primary key value
}public boolean updateIfExists() {
if (this.getId() == null) {
return false; // Cannot update without ID
}
return this.updateById();
}
public User reloadFromDatabase() {
if (this.getId() == null) {
return null;
}
return this.selectById();
}@Transactional
public boolean transferToInactiveStatus() {
// Update user status
this.active = false;
this.updatedTime = LocalDateTime.now();
boolean userUpdated = this.updateById();
if (!userUpdated) {
throw new RuntimeException("Failed to update user");
}
// Update related data using SQL Runner
SqlRunner sqlRunner = this.sql();
int affected = sqlRunner.update(
"UPDATE user_sessions SET active = 0 WHERE user_id = ?",
this.getId()
);
return affected >= 0;
}public boolean isValid() {
return this.name != null && !this.name.trim().isEmpty() &&
this.email != null && this.email.contains("@");
}
public boolean saveIfValid() {
if (!isValid()) {
return false;
}
return this.insert();
}public class User extends Model<User> {
public boolean safeUpdate() {
try {
if (this.getId() == null) {
System.err.println("Cannot update user without ID");
return false;
}
return this.updateById();
} catch (Exception e) {
System.err.println("Error updating user: " + e.getMessage());
return false;
}
}
public User safeSelectById(Long id) {
try {
return this.selectById(id);
} catch (Exception e) {
System.err.println("Error selecting user by ID " + id + ": " + e.getMessage());
return null;
}
}
}selectList() with conditions rather than selectAll() and filtering in JavaInstall with Tessl CLI
npx tessl i tessl/maven-com-baomidou--mybatis-plus-extension