0
# Active Record Pattern
1
2
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.
3
4
## Capabilities
5
6
### Model Base Class
7
8
Abstract base class that entities can extend to gain Active Record functionality.
9
10
```java { .api }
11
/**
12
* Active Record pattern base class
13
* @param <T> Entity type extending Model
14
*/
15
public abstract class Model<T extends Model<?>> implements Serializable, Cloneable {
16
17
// ==================== Insert Operations ====================
18
19
/**
20
* Insert current entity
21
* @return true if successful
22
*/
23
public boolean insert();
24
25
/**
26
* Insert or update current entity
27
* @return true if successful
28
*/
29
public boolean insertOrUpdate();
30
31
// ==================== Update Operations ====================
32
33
/**
34
* Update current entity by primary key
35
* @return true if successful
36
*/
37
public boolean updateById();
38
39
/**
40
* Update entities by conditions
41
* @param updateWrapper Update conditions wrapper
42
* @return true if successful
43
*/
44
public boolean update(Wrapper<T> updateWrapper);
45
46
// ==================== Delete Operations ====================
47
48
/**
49
* Delete current entity by primary key
50
* @return true if successful
51
*/
52
public boolean deleteById();
53
54
/**
55
* Delete entities by conditions
56
* @param queryWrapper Query conditions wrapper
57
* @return true if successful
58
*/
59
public boolean delete(Wrapper<T> queryWrapper);
60
61
// ==================== Select Operations ====================
62
63
/**
64
* Select entity by primary key
65
* @return Entity or null
66
*/
67
public T selectById();
68
69
/**
70
* Select entity by primary key with specified ID
71
* @param id Primary key value
72
* @return Entity or null
73
*/
74
public T selectById(Serializable id);
75
76
/**
77
* Select one entity by conditions
78
* @param queryWrapper Query conditions wrapper
79
* @return Entity or null
80
*/
81
public T selectOne(Wrapper<T> queryWrapper);
82
83
/**
84
* Select list of entities by conditions
85
* @param queryWrapper Query conditions wrapper
86
* @return List of entities
87
*/
88
public List<T> selectList(Wrapper<T> queryWrapper);
89
90
/**
91
* Select all entities
92
* @return List of all entities
93
*/
94
public List<T> selectAll();
95
96
/**
97
* Select paginated entities
98
* @param page Pagination parameters
99
* @param queryWrapper Query conditions wrapper
100
* @return Paginated results
101
*/
102
public <E extends IPage<T>> E selectPage(E page, Wrapper<T> queryWrapper);
103
104
/**
105
* Count entities by conditions
106
* @param queryWrapper Query conditions wrapper
107
* @return Count
108
*/
109
public long selectCount(Wrapper<T> queryWrapper);
110
111
/**
112
* Count all entities
113
* @return Total count
114
*/
115
public long selectCount();
116
}
117
```
118
119
## Usage Examples
120
121
**Entity Setup with Active Record:**
122
123
```java
124
@TableName("user")
125
public class User extends Model<User> {
126
@TableId(type = IdType.AUTO)
127
private Long id;
128
129
private String name;
130
private Integer age;
131
private String email;
132
private LocalDateTime createTime;
133
134
// constructors, getters, setters...
135
}
136
```
137
138
**Insert Operations:**
139
140
```java
141
// Create and insert new user
142
User user = new User();
143
user.setName("John Doe");
144
user.setAge(25);
145
user.setEmail("john@example.com");
146
147
boolean success = user.insert();
148
// user.getId() will contain the generated ID
149
150
// Insert or update (upsert)
151
User user = new User();
152
user.setId(1L); // If exists, update; otherwise insert
153
user.setName("Updated Name");
154
user.setAge(26);
155
156
boolean success = user.insertOrUpdate();
157
```
158
159
**Update Operations:**
160
161
```java
162
// Update by primary key
163
User user = new User();
164
user.setId(1L);
165
user.setAge(26); // Only non-null fields are updated
166
167
boolean success = user.updateById();
168
169
// Update with conditions
170
User user = new User();
171
user.setAge(30);
172
173
UpdateWrapper<User> wrapper = new UpdateWrapper<>();
174
wrapper.eq("department", "IT").gt("age", 25);
175
176
boolean success = user.update(wrapper);
177
```
178
179
**Delete Operations:**
180
181
```java
182
// Delete by primary key
183
User user = new User();
184
user.setId(1L);
185
186
boolean success = user.deleteById();
187
188
// Delete with conditions
189
User user = new User();
190
QueryWrapper<User> wrapper = new QueryWrapper<>();
191
wrapper.eq("status", 0).lt("last_login", LocalDateTime.now().minusMonths(6));
192
193
boolean success = user.delete(wrapper);
194
```
195
196
**Select Operations:**
197
198
```java
199
// Select by primary key
200
User user = new User();
201
user.setId(1L);
202
User foundUser = user.selectById(); // Returns loaded user or null
203
204
// Select by specified ID
205
User user = new User();
206
User foundUser = user.selectById(1L);
207
208
// Select one by conditions
209
User user = new User();
210
QueryWrapper<User> wrapper = new QueryWrapper<>();
211
wrapper.eq("email", "john@example.com");
212
User foundUser = user.selectOne(wrapper);
213
214
// Select list by conditions
215
User user = new User();
216
QueryWrapper<User> wrapper = new QueryWrapper<>();
217
wrapper.eq("status", 1).orderByDesc("create_time");
218
List<User> users = user.selectList(wrapper);
219
220
// Select all
221
User user = new User();
222
List<User> allUsers = user.selectAll();
223
224
// Paginated select
225
User user = new User();
226
Page<User> page = new Page<>(1, 10);
227
QueryWrapper<User> wrapper = new QueryWrapper<>();
228
wrapper.eq("status", 1);
229
IPage<User> userPage = user.selectPage(page, wrapper);
230
231
// Count operations
232
User user = new User();
233
QueryWrapper<User> wrapper = new QueryWrapper<>();
234
wrapper.eq("status", 1);
235
long activeUsers = user.selectCount(wrapper);
236
237
long totalUsers = user.selectCount();
238
```
239
240
**Chaining Operations:**
241
242
```java
243
// Method chaining for fluent operations
244
User user = new User()
245
.setName("Alice")
246
.setAge(28)
247
.setEmail("alice@example.com");
248
249
if (user.insert()) {
250
System.out.println("User created with ID: " + user.getId());
251
252
// Update the same instance
253
user.setAge(29);
254
if (user.updateById()) {
255
System.out.println("User updated successfully");
256
}
257
}
258
```
259
260
**Complex Business Logic:**
261
262
```java
263
public class User extends Model<User> {
264
// ... fields and basic methods
265
266
// Custom business methods using Active Record
267
public boolean activate() {
268
this.setStatus(1);
269
this.setActiveTime(LocalDateTime.now());
270
return this.updateById();
271
}
272
273
public boolean deactivate() {
274
this.setStatus(0);
275
this.setInactiveTime(LocalDateTime.now());
276
return this.updateById();
277
}
278
279
public List<User> findSimilarUsers() {
280
QueryWrapper<User> wrapper = new QueryWrapper<>();
281
wrapper.eq("department", this.getDepartment())
282
.eq("role", this.getRole())
283
.ne("id", this.getId());
284
return this.selectList(wrapper);
285
}
286
287
public boolean hasSameEmail() {
288
QueryWrapper<User> wrapper = new QueryWrapper<>();
289
wrapper.eq("email", this.getEmail())
290
.ne("id", this.getId());
291
return this.selectCount(wrapper) > 0;
292
}
293
294
public boolean softDelete() {
295
this.setDeleted(1);
296
this.setDeleteTime(LocalDateTime.now());
297
return this.updateById();
298
}
299
}
300
301
// Usage of custom methods
302
User user = new User().selectById(1L);
303
if (user != null) {
304
if (!user.hasSameEmail()) {
305
user.activate();
306
List<User> similar = user.findSimilarUsers();
307
System.out.println("Found " + similar.size() + " similar users");
308
}
309
}
310
```
311
312
**Error Handling:**
313
314
```java
315
try {
316
User user = new User();
317
user.setName("Test User");
318
user.setEmail("test@example.com");
319
320
if (user.insert()) {
321
System.out.println("User created successfully");
322
} else {
323
System.out.println("Failed to create user");
324
}
325
} catch (Exception e) {
326
System.err.println("Database error: " + e.getMessage());
327
// Handle specific exceptions like duplicate key, constraint violations, etc.
328
}
329
```
330
331
**Performance Considerations:**
332
333
```java
334
// Use batch operations at service layer for multiple records
335
// Active Record is best for single entity operations
336
337
// Good: Single entity operations
338
User user = new User().selectById(id);
339
if (user != null) {
340
user.setLastLogin(LocalDateTime.now());
341
user.updateById();
342
}
343
344
// Better for bulk operations: Use service layer
345
// userService.updateBatchById(users);
346
347
// Use Active Record for business logic methods
348
public class Order extends Model<Order> {
349
public boolean canCancel() {
350
return this.getStatus() == OrderStatus.PENDING
351
&& this.getCreateTime().isAfter(LocalDateTime.now().minusMinutes(30));
352
}
353
354
public boolean cancel() {
355
if (!canCancel()) {
356
return false;
357
}
358
this.setStatus(OrderStatus.CANCELLED);
359
this.setCancelTime(LocalDateTime.now());
360
return this.updateById();
361
}
362
}
363
```
364
365
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.