0
# Mapping Annotations
1
2
Annotation-based SQL mapping system that provides a declarative approach to database operations. These annotations allow you to define SQL statements directly on mapper interface methods, eliminating the need for XML configuration files.
3
4
## Capabilities
5
6
### Core SQL Annotations
7
8
#### @Select
9
10
Defines SQL SELECT statements for data retrieval operations.
11
12
```java { .api }
13
/**
14
* Specifies SQL SELECT statement for retrieving records
15
*/
16
@interface Select {
17
/** SQL SELECT statement(s) */
18
String[] value();
19
}
20
```
21
22
**Usage Examples:**
23
24
```java
25
public interface UserMapper {
26
@Select("SELECT * FROM users WHERE id = #{id}")
27
User findById(@Param("id") Long id);
28
29
@Select("SELECT * FROM users WHERE status = #{status} ORDER BY name")
30
List<User> findByStatus(@Param("status") String status);
31
32
// Multi-statement select
33
@Select({
34
"SELECT u.*, p.name as profile_name",
35
"FROM users u",
36
"LEFT JOIN profiles p ON u.profile_id = p.id",
37
"WHERE u.active = #{active}"
38
})
39
List<UserProfile> findUsersWithProfiles(@Param("active") boolean active);
40
}
41
```
42
43
#### @Insert
44
45
Defines SQL INSERT statements for creating new records.
46
47
```java { .api }
48
/**
49
* Specifies SQL INSERT statement
50
*/
51
@interface Insert {
52
/** SQL INSERT statement(s) */
53
String[] value();
54
}
55
```
56
57
**Usage Examples:**
58
59
```java
60
public interface UserMapper {
61
@Insert("INSERT INTO users (name, email, status) VALUES (#{name}, #{email}, #{status})")
62
int insert(User user);
63
64
// Multi-statement insert
65
@Insert({
66
"INSERT INTO users (name, email, status)",
67
"VALUES (#{name}, #{email}, #{status})"
68
})
69
@Options(useGeneratedKeys = true, keyProperty = "id")
70
int insertWithGeneratedKey(User user);
71
}
72
```
73
74
#### @Update
75
76
Defines SQL UPDATE statements for modifying existing records.
77
78
```java { .api }
79
/**
80
* Specifies SQL UPDATE statement
81
*/
82
@interface Update {
83
/** SQL UPDATE statement(s) */
84
String[] value();
85
}
86
```
87
88
**Usage Examples:**
89
90
```java
91
public interface UserMapper {
92
@Update("UPDATE users SET name = #{name}, email = #{email} WHERE id = #{id}")
93
int update(User user);
94
95
@Update("UPDATE users SET status = #{status} WHERE id = #{id}")
96
int updateStatus(@Param("id") Long id, @Param("status") String status);
97
}
98
```
99
100
#### @Delete
101
102
Defines SQL DELETE statements for removing records.
103
104
```java { .api }
105
/**
106
* Specifies SQL DELETE statement
107
*/
108
@interface Delete {
109
/** SQL DELETE statement(s) */
110
String[] value();
111
}
112
```
113
114
**Usage Examples:**
115
116
```java
117
public interface UserMapper {
118
@Delete("DELETE FROM users WHERE id = #{id}")
119
int deleteById(@Param("id") Long id);
120
121
@Delete("DELETE FROM users WHERE status = #{status}")
122
int deleteByStatus(@Param("status") String status);
123
}
124
```
125
126
### Dynamic SQL Provider Annotations
127
128
For complex dynamic SQL that can't be expressed in simple annotations, use provider classes.
129
130
#### @SelectProvider
131
132
Uses a provider class method to generate dynamic SELECT statements.
133
134
```java { .api }
135
/**
136
* Specifies provider class/method for dynamic SELECT statements
137
*/
138
@interface SelectProvider {
139
/** Provider class containing the SQL generation method */
140
Class<?> type();
141
142
/** Method name in the provider class */
143
String method();
144
}
145
```
146
147
**Usage Examples:**
148
149
```java
150
public interface UserMapper {
151
@SelectProvider(type = UserSqlProvider.class, method = "findByConditions")
152
List<User> findByConditions(UserSearchCriteria criteria);
153
}
154
155
public class UserSqlProvider {
156
public String findByConditions(UserSearchCriteria criteria) {
157
return new SQL()
158
.SELECT("*")
159
.FROM("users")
160
.WHERE(criteria.getName() != null, "name LIKE #{name}")
161
.WHERE(criteria.getStatus() != null, "status = #{status}")
162
.WHERE(criteria.getMinAge() != null, "age >= #{minAge}")
163
.toString();
164
}
165
}
166
```
167
168
#### @InsertProvider
169
170
Uses a provider class method to generate dynamic INSERT statements.
171
172
```java { .api }
173
/**
174
* Specifies provider class/method for dynamic INSERT statements
175
*/
176
@interface InsertProvider {
177
/** Provider class containing the SQL generation method */
178
Class<?> type();
179
180
/** Method name in the provider class */
181
String method();
182
}
183
```
184
185
#### @UpdateProvider
186
187
Uses a provider class method to generate dynamic UPDATE statements.
188
189
```java { .api }
190
/**
191
* Specifies provider class/method for dynamic UPDATE statements
192
*/
193
@interface UpdateProvider {
194
/** Provider class containing the SQL generation method */
195
Class<?> type();
196
197
/** Method name in the provider class */
198
String method();
199
}
200
```
201
202
#### @DeleteProvider
203
204
Uses a provider class method to generate dynamic DELETE statements.
205
206
```java { .api }
207
/**
208
* Specifies provider class/method for dynamic DELETE statements
209
*/
210
@interface DeleteProvider {
211
/** Provider class containing the SQL generation method */
212
Class<?> type();
213
214
/** Method name in the provider class */
215
String method();
216
}
217
```
218
219
### Result Mapping Annotations
220
221
#### @Results
222
223
Container annotation for defining result mappings between database columns and Java object properties.
224
225
```java { .api }
226
/**
227
* Container for result mappings
228
*/
229
@interface Results {
230
/** Optional result map ID for reuse */
231
String id() default "";
232
233
/** Array of individual result mappings */
234
Result[] value();
235
}
236
```
237
238
#### @Result
239
240
Maps individual database columns to Java object properties.
241
242
```java { .api }
243
/**
244
* Maps column to property with optional type handling
245
*/
246
@interface Result {
247
/** Whether this column represents an ID/primary key */
248
boolean id() default false;
249
250
/** Database column name */
251
String column() default "";
252
253
/** Java property name */
254
String property() default "";
255
256
/** Java type for the property */
257
Class<?> javaType() default void.class;
258
259
/** JDBC type for the column */
260
JdbcType jdbcType() default JdbcType.UNDEFINED;
261
262
/** Custom type handler for conversion */
263
Class<? extends TypeHandler> typeHandler() default UnknownTypeHandler.class;
264
265
/** One-to-one association mapping */
266
One one() default @One;
267
268
/** One-to-many association mapping */
269
Many many() default @Many;
270
}
271
```
272
273
**Usage Examples:**
274
275
```java
276
public interface UserMapper {
277
@Select("SELECT id, user_name, email_addr, created_at FROM users WHERE id = #{id}")
278
@Results({
279
@Result(column = "id", property = "id", id = true),
280
@Result(column = "user_name", property = "name"),
281
@Result(column = "email_addr", property = "email"),
282
@Result(column = "created_at", property = "createdAt", javaType = LocalDateTime.class)
283
})
284
User findById(@Param("id") Long id);
285
286
// Reusable result map
287
@Select("SELECT id, user_name, email_addr FROM users")
288
@Results(id = "userResultMap", value = {
289
@Result(column = "id", property = "id", id = true),
290
@Result(column = "user_name", property = "name"),
291
@Result(column = "email_addr", property = "email")
292
})
293
List<User> findAll();
294
295
// Reference existing result map
296
@Select("SELECT id, user_name, email_addr FROM users WHERE status = #{status}")
297
@ResultMap("userResultMap")
298
List<User> findByStatus(@Param("status") String status);
299
}
300
```
301
302
### Association Annotations
303
304
#### @One
305
306
Defines one-to-one associations with nested object loading.
307
308
```java { .api }
309
/**
310
* One-to-one association mapping
311
*/
312
@interface One {
313
/** SELECT statement for loading the associated object */
314
String select() default "";
315
316
/** Fetch type - LAZY or EAGER */
317
FetchType fetchType() default FetchType.DEFAULT;
318
319
/** Result map for the association */
320
String resultMap() default "";
321
}
322
```
323
324
#### @Many
325
326
Defines one-to-many associations with collection loading.
327
328
```java { .api }
329
/**
330
* One-to-many association mapping
331
*/
332
@interface Many {
333
/** SELECT statement for loading the associated collection */
334
String select() default "";
335
336
/** Fetch type - LAZY or EAGER */
337
FetchType fetchType() default FetchType.DEFAULT;
338
339
/** Result map for the association */
340
String resultMap() default "";
341
}
342
```
343
344
**Usage Examples:**
345
346
```java
347
public interface UserMapper {
348
@Select("SELECT * FROM users WHERE id = #{id}")
349
@Results({
350
@Result(column = "id", property = "id", id = true),
351
@Result(column = "name", property = "name"),
352
@Result(column = "profile_id", property = "profile",
353
one = @One(select = "findProfileById", fetchType = FetchType.LAZY)),
354
@Result(column = "id", property = "orders",
355
many = @Many(select = "findOrdersByUserId", fetchType = FetchType.LAZY))
356
})
357
User findUserWithAssociations(@Param("id") Long id);
358
359
@Select("SELECT * FROM profiles WHERE id = #{id}")
360
Profile findProfileById(@Param("id") Long id);
361
362
@Select("SELECT * FROM orders WHERE user_id = #{userId}")
363
List<Order> findOrdersByUserId(@Param("userId") Long userId);
364
}
365
```
366
367
### Configuration Annotations
368
369
#### @Options
370
371
Configures various statement execution options.
372
373
```java { .api }
374
/**
375
* Specifies various statement options
376
*/
377
@interface Options {
378
/** Use cache for this statement */
379
boolean useCache() default true;
380
381
/** Flush cache before executing this statement */
382
boolean flushCache() default false;
383
384
/** Result set type */
385
ResultSetType resultSetType() default ResultSetType.DEFAULT;
386
387
/** Statement type */
388
StatementType statementType() default StatementType.PREPARED;
389
390
/** Fetch size hint for the driver */
391
int fetchSize() default -1;
392
393
/** Query timeout in seconds */
394
int timeout() default -1;
395
396
/** Use generated keys for insert statements */
397
boolean useGeneratedKeys() default false;
398
399
/** Property to store generated key value */
400
String keyProperty() default "";
401
402
/** Column name of the generated key */
403
String keyColumn() default "";
404
405
/** Result set names for procedures with multiple result sets */
406
String resultSets() default "";
407
}
408
```
409
410
**Usage Examples:**
411
412
```java
413
public interface UserMapper {
414
@Insert("INSERT INTO users (name, email) VALUES (#{name}, #{email})")
415
@Options(useGeneratedKeys = true, keyProperty = "id", keyColumn = "id")
416
int insert(User user);
417
418
@Select("SELECT * FROM users")
419
@Options(fetchSize = 100, timeout = 30, useCache = false)
420
List<User> findAllWithOptions();
421
422
@Update("UPDATE users SET status = 'INACTIVE'")
423
@Options(flushCache = true)
424
int deactivateAllUsers();
425
}
426
```
427
428
#### @Param
429
430
Specifies parameter names for SQL statements when method parameters don't match placeholders.
431
432
```java { .api }
433
/**
434
* Specifies parameter name for SQL statements
435
*/
436
@interface Param {
437
/** Parameter name to use in SQL */
438
String value();
439
}
440
```
441
442
**Usage Examples:**
443
444
```java
445
public interface UserMapper {
446
@Select("SELECT * FROM users WHERE name = #{userName} AND status = #{userStatus}")
447
List<User> findByNameAndStatus(@Param("userName") String name,
448
@Param("userStatus") String status);
449
450
@Update("UPDATE users SET email = #{newEmail} WHERE id = #{userId}")
451
int updateEmail(@Param("userId") Long id, @Param("newEmail") String email);
452
}
453
```
454
455
#### @SelectKey
456
457
Configures key generation for insert operations.
458
459
```java { .api }
460
/**
461
* Specifies key generation strategy
462
*/
463
@interface SelectKey {
464
/** SQL statement(s) for key generation */
465
String[] statement();
466
467
/** Property to store the generated key */
468
String keyProperty();
469
470
/** Column name of the generated key */
471
String keyColumn() default "";
472
473
/** Execute before the main statement (true) or after (false) */
474
boolean before();
475
476
/** Result type of the key */
477
Class<?> resultType();
478
479
/** Statement type for key generation */
480
StatementType statementType() default StatementType.PREPARED;
481
}
482
```
483
484
**Usage Examples:**
485
486
```java
487
public interface UserMapper {
488
// MySQL auto-increment key
489
@Insert("INSERT INTO users (name, email) VALUES (#{name}, #{email})")
490
@SelectKey(statement = "SELECT LAST_INSERT_ID()",
491
keyProperty = "id",
492
before = false,
493
resultType = Long.class)
494
int insertUser(User user);
495
496
// Oracle sequence key
497
@Insert("INSERT INTO users (id, name, email) VALUES (#{id}, #{name}, #{email})")
498
@SelectKey(statement = "SELECT user_seq.nextval FROM dual",
499
keyProperty = "id",
500
before = true,
501
resultType = Long.class)
502
int insertUserOracle(User user);
503
}
504
```
505
506
### Cache Configuration Annotations
507
508
#### @CacheNamespace
509
510
Configures caching behavior for the entire mapper interface.
511
512
```java { .api }
513
/**
514
* Specifies cache configuration for mapper
515
*/
516
@interface CacheNamespace {
517
/** Cache implementation class */
518
Class<? extends Cache> implementation() default PerpetualCache.class;
519
520
/** Eviction policy classes */
521
Class<? extends Cache> eviction() default LruCache.class;
522
523
/** Flush interval in milliseconds */
524
long flushInterval() default 0;
525
526
/** Maximum cache size */
527
int size() default 1024;
528
529
/** Read/write cache (true) or read-only cache (false) */
530
boolean readWrite() default true;
531
532
/** Use blocking cache to prevent cache stampede */
533
boolean blocking() default false;
534
535
/** Additional cache properties */
536
Property[] properties() default {};
537
}
538
539
@interface Property {
540
String name();
541
String value();
542
}
543
```
544
545
#### @CacheNamespaceRef
546
547
References cache configuration from another mapper.
548
549
```java { .api }
550
/**
551
* References cache configuration from another mapper
552
*/
553
@interface CacheNamespaceRef {
554
/** Referenced mapper class */
555
Class<?> value() default void.class;
556
557
/** Referenced namespace name */
558
String name() default "";
559
}
560
```
561
562
**Usage Examples:**
563
564
```java
565
@CacheNamespace(
566
implementation = PerpetualCache.class,
567
eviction = LruCache.class,
568
flushInterval = 60000,
569
size = 512,
570
readWrite = true,
571
blocking = true
572
)
573
public interface UserMapper {
574
@Select("SELECT * FROM users WHERE id = #{id}")
575
@Options(useCache = true)
576
User findById(@Param("id") Long id);
577
}
578
579
// Reference cache from another mapper
580
@CacheNamespaceRef(UserMapper.class)
581
public interface UserProfileMapper {
582
@Select("SELECT * FROM user_profiles WHERE user_id = #{userId}")
583
UserProfile findByUserId(@Param("userId") Long userId);
584
}
585
```
586
587
### Utility Annotations
588
589
#### @Mapper
590
591
Marks an interface as a MyBatis mapper for component scanning.
592
593
```java { .api }
594
/**
595
* Marks interface as MyBatis mapper
596
*/
597
@interface Mapper {
598
}
599
```
600
601
#### @Flush
602
603
Marks a method to flush batch statements.
604
605
```java { .api }
606
/**
607
* Marks method to flush batch statements
608
*/
609
@interface Flush {
610
}
611
```
612
613
#### @Lang
614
615
Specifies a custom language driver for dynamic SQL processing.
616
617
```java { .api }
618
/**
619
* Specifies language driver for dynamic SQL
620
*/
621
@interface Lang {
622
/** Language driver class */
623
Class<? extends LanguageDriver> value();
624
}
625
```
626
627
**Usage Examples:**
628
629
```java
630
@Mapper
631
public interface UserMapper {
632
@Select("SELECT * FROM users WHERE id = #{id}")
633
User findById(@Param("id") Long id);
634
635
@Flush
636
List<BatchResult> flush();
637
638
@Lang(XMLLanguageDriver.class)
639
@Select("SELECT * FROM users WHERE <if test='name != null'>name = #{name}</if>")
640
List<User> findByCondition(@Param("name") String name);
641
}
642
```
643
644
## Types
645
646
```java { .api }
647
/**
648
* Fetch types for associations
649
*/
650
enum FetchType {
651
/** Use global lazy loading setting */
652
DEFAULT,
653
654
/** Load association eagerly */
655
EAGER,
656
657
/** Load association lazily */
658
LAZY
659
}
660
661
/**
662
* Result set types
663
*/
664
enum ResultSetType {
665
/** Use driver default */
666
DEFAULT,
667
668
/** Forward-only result set */
669
FORWARD_ONLY,
670
671
/** Scroll-insensitive result set */
672
SCROLL_INSENSITIVE,
673
674
/** Scroll-sensitive result set */
675
SCROLL_SENSITIVE
676
}
677
678
/**
679
* Statement types
680
*/
681
enum StatementType {
682
/** Regular statement */
683
STATEMENT,
684
685
/** Prepared statement (default) */
686
PREPARED,
687
688
/** Callable statement for stored procedures */
689
CALLABLE
690
}
691
```