SQL mapping framework that eliminates JDBC boilerplate and couples objects with stored procedures or SQL statements using XML descriptors or annotations.
—
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.
Defines SQL SELECT statements for data retrieval operations.
/**
* Specifies SQL SELECT statement for retrieving records
*/
@interface Select {
/** SQL SELECT statement(s) */
String[] value();
}Usage Examples:
public interface UserMapper {
@Select("SELECT * FROM users WHERE id = #{id}")
User findById(@Param("id") Long id);
@Select("SELECT * FROM users WHERE status = #{status} ORDER BY name")
List<User> findByStatus(@Param("status") String status);
// Multi-statement select
@Select({
"SELECT u.*, p.name as profile_name",
"FROM users u",
"LEFT JOIN profiles p ON u.profile_id = p.id",
"WHERE u.active = #{active}"
})
List<UserProfile> findUsersWithProfiles(@Param("active") boolean active);
}Defines SQL INSERT statements for creating new records.
/**
* Specifies SQL INSERT statement
*/
@interface Insert {
/** SQL INSERT statement(s) */
String[] value();
}Usage Examples:
public interface UserMapper {
@Insert("INSERT INTO users (name, email, status) VALUES (#{name}, #{email}, #{status})")
int insert(User user);
// Multi-statement insert
@Insert({
"INSERT INTO users (name, email, status)",
"VALUES (#{name}, #{email}, #{status})"
})
@Options(useGeneratedKeys = true, keyProperty = "id")
int insertWithGeneratedKey(User user);
}Defines SQL UPDATE statements for modifying existing records.
/**
* Specifies SQL UPDATE statement
*/
@interface Update {
/** SQL UPDATE statement(s) */
String[] value();
}Usage Examples:
public interface UserMapper {
@Update("UPDATE users SET name = #{name}, email = #{email} WHERE id = #{id}")
int update(User user);
@Update("UPDATE users SET status = #{status} WHERE id = #{id}")
int updateStatus(@Param("id") Long id, @Param("status") String status);
}Defines SQL DELETE statements for removing records.
/**
* Specifies SQL DELETE statement
*/
@interface Delete {
/** SQL DELETE statement(s) */
String[] value();
}Usage Examples:
public interface UserMapper {
@Delete("DELETE FROM users WHERE id = #{id}")
int deleteById(@Param("id") Long id);
@Delete("DELETE FROM users WHERE status = #{status}")
int deleteByStatus(@Param("status") String status);
}For complex dynamic SQL that can't be expressed in simple annotations, use provider classes.
Uses a provider class method to generate dynamic SELECT statements.
/**
* Specifies provider class/method for dynamic SELECT statements
*/
@interface SelectProvider {
/** Provider class containing the SQL generation method */
Class<?> type();
/** Method name in the provider class */
String method();
}Usage Examples:
public interface UserMapper {
@SelectProvider(type = UserSqlProvider.class, method = "findByConditions")
List<User> findByConditions(UserSearchCriteria criteria);
}
public class UserSqlProvider {
public String findByConditions(UserSearchCriteria criteria) {
return new SQL()
.SELECT("*")
.FROM("users")
.WHERE(criteria.getName() != null, "name LIKE #{name}")
.WHERE(criteria.getStatus() != null, "status = #{status}")
.WHERE(criteria.getMinAge() != null, "age >= #{minAge}")
.toString();
}
}Uses a provider class method to generate dynamic INSERT statements.
/**
* Specifies provider class/method for dynamic INSERT statements
*/
@interface InsertProvider {
/** Provider class containing the SQL generation method */
Class<?> type();
/** Method name in the provider class */
String method();
}Uses a provider class method to generate dynamic UPDATE statements.
/**
* Specifies provider class/method for dynamic UPDATE statements
*/
@interface UpdateProvider {
/** Provider class containing the SQL generation method */
Class<?> type();
/** Method name in the provider class */
String method();
}Uses a provider class method to generate dynamic DELETE statements.
/**
* Specifies provider class/method for dynamic DELETE statements
*/
@interface DeleteProvider {
/** Provider class containing the SQL generation method */
Class<?> type();
/** Method name in the provider class */
String method();
}Container annotation for defining result mappings between database columns and Java object properties.
/**
* Container for result mappings
*/
@interface Results {
/** Optional result map ID for reuse */
String id() default "";
/** Array of individual result mappings */
Result[] value();
}Maps individual database columns to Java object properties.
/**
* Maps column to property with optional type handling
*/
@interface Result {
/** Whether this column represents an ID/primary key */
boolean id() default false;
/** Database column name */
String column() default "";
/** Java property name */
String property() default "";
/** Java type for the property */
Class<?> javaType() default void.class;
/** JDBC type for the column */
JdbcType jdbcType() default JdbcType.UNDEFINED;
/** Custom type handler for conversion */
Class<? extends TypeHandler> typeHandler() default UnknownTypeHandler.class;
/** One-to-one association mapping */
One one() default @One;
/** One-to-many association mapping */
Many many() default @Many;
}Usage Examples:
public interface UserMapper {
@Select("SELECT id, user_name, email_addr, created_at FROM users WHERE id = #{id}")
@Results({
@Result(column = "id", property = "id", id = true),
@Result(column = "user_name", property = "name"),
@Result(column = "email_addr", property = "email"),
@Result(column = "created_at", property = "createdAt", javaType = LocalDateTime.class)
})
User findById(@Param("id") Long id);
// Reusable result map
@Select("SELECT id, user_name, email_addr FROM users")
@Results(id = "userResultMap", value = {
@Result(column = "id", property = "id", id = true),
@Result(column = "user_name", property = "name"),
@Result(column = "email_addr", property = "email")
})
List<User> findAll();
// Reference existing result map
@Select("SELECT id, user_name, email_addr FROM users WHERE status = #{status}")
@ResultMap("userResultMap")
List<User> findByStatus(@Param("status") String status);
}Defines one-to-one associations with nested object loading.
/**
* One-to-one association mapping
*/
@interface One {
/** SELECT statement for loading the associated object */
String select() default "";
/** Fetch type - LAZY or EAGER */
FetchType fetchType() default FetchType.DEFAULT;
/** Result map for the association */
String resultMap() default "";
}Defines one-to-many associations with collection loading.
/**
* One-to-many association mapping
*/
@interface Many {
/** SELECT statement for loading the associated collection */
String select() default "";
/** Fetch type - LAZY or EAGER */
FetchType fetchType() default FetchType.DEFAULT;
/** Result map for the association */
String resultMap() default "";
}Usage Examples:
public interface UserMapper {
@Select("SELECT * FROM users WHERE id = #{id}")
@Results({
@Result(column = "id", property = "id", id = true),
@Result(column = "name", property = "name"),
@Result(column = "profile_id", property = "profile",
one = @One(select = "findProfileById", fetchType = FetchType.LAZY)),
@Result(column = "id", property = "orders",
many = @Many(select = "findOrdersByUserId", fetchType = FetchType.LAZY))
})
User findUserWithAssociations(@Param("id") Long id);
@Select("SELECT * FROM profiles WHERE id = #{id}")
Profile findProfileById(@Param("id") Long id);
@Select("SELECT * FROM orders WHERE user_id = #{userId}")
List<Order> findOrdersByUserId(@Param("userId") Long userId);
}Configures various statement execution options.
/**
* Specifies various statement options
*/
@interface Options {
/** Use cache for this statement */
boolean useCache() default true;
/** Flush cache before executing this statement */
boolean flushCache() default false;
/** Result set type */
ResultSetType resultSetType() default ResultSetType.DEFAULT;
/** Statement type */
StatementType statementType() default StatementType.PREPARED;
/** Fetch size hint for the driver */
int fetchSize() default -1;
/** Query timeout in seconds */
int timeout() default -1;
/** Use generated keys for insert statements */
boolean useGeneratedKeys() default false;
/** Property to store generated key value */
String keyProperty() default "";
/** Column name of the generated key */
String keyColumn() default "";
/** Result set names for procedures with multiple result sets */
String resultSets() default "";
}Usage Examples:
public interface UserMapper {
@Insert("INSERT INTO users (name, email) VALUES (#{name}, #{email})")
@Options(useGeneratedKeys = true, keyProperty = "id", keyColumn = "id")
int insert(User user);
@Select("SELECT * FROM users")
@Options(fetchSize = 100, timeout = 30, useCache = false)
List<User> findAllWithOptions();
@Update("UPDATE users SET status = 'INACTIVE'")
@Options(flushCache = true)
int deactivateAllUsers();
}Specifies parameter names for SQL statements when method parameters don't match placeholders.
/**
* Specifies parameter name for SQL statements
*/
@interface Param {
/** Parameter name to use in SQL */
String value();
}Usage Examples:
public interface UserMapper {
@Select("SELECT * FROM users WHERE name = #{userName} AND status = #{userStatus}")
List<User> findByNameAndStatus(@Param("userName") String name,
@Param("userStatus") String status);
@Update("UPDATE users SET email = #{newEmail} WHERE id = #{userId}")
int updateEmail(@Param("userId") Long id, @Param("newEmail") String email);
}Configures key generation for insert operations.
/**
* Specifies key generation strategy
*/
@interface SelectKey {
/** SQL statement(s) for key generation */
String[] statement();
/** Property to store the generated key */
String keyProperty();
/** Column name of the generated key */
String keyColumn() default "";
/** Execute before the main statement (true) or after (false) */
boolean before();
/** Result type of the key */
Class<?> resultType();
/** Statement type for key generation */
StatementType statementType() default StatementType.PREPARED;
}Usage Examples:
public interface UserMapper {
// MySQL auto-increment key
@Insert("INSERT INTO users (name, email) VALUES (#{name}, #{email})")
@SelectKey(statement = "SELECT LAST_INSERT_ID()",
keyProperty = "id",
before = false,
resultType = Long.class)
int insertUser(User user);
// Oracle sequence key
@Insert("INSERT INTO users (id, name, email) VALUES (#{id}, #{name}, #{email})")
@SelectKey(statement = "SELECT user_seq.nextval FROM dual",
keyProperty = "id",
before = true,
resultType = Long.class)
int insertUserOracle(User user);
}Configures caching behavior for the entire mapper interface.
/**
* Specifies cache configuration for mapper
*/
@interface CacheNamespace {
/** Cache implementation class */
Class<? extends Cache> implementation() default PerpetualCache.class;
/** Eviction policy classes */
Class<? extends Cache> eviction() default LruCache.class;
/** Flush interval in milliseconds */
long flushInterval() default 0;
/** Maximum cache size */
int size() default 1024;
/** Read/write cache (true) or read-only cache (false) */
boolean readWrite() default true;
/** Use blocking cache to prevent cache stampede */
boolean blocking() default false;
/** Additional cache properties */
Property[] properties() default {};
}
@interface Property {
String name();
String value();
}References cache configuration from another mapper.
/**
* References cache configuration from another mapper
*/
@interface CacheNamespaceRef {
/** Referenced mapper class */
Class<?> value() default void.class;
/** Referenced namespace name */
String name() default "";
}Usage Examples:
@CacheNamespace(
implementation = PerpetualCache.class,
eviction = LruCache.class,
flushInterval = 60000,
size = 512,
readWrite = true,
blocking = true
)
public interface UserMapper {
@Select("SELECT * FROM users WHERE id = #{id}")
@Options(useCache = true)
User findById(@Param("id") Long id);
}
// Reference cache from another mapper
@CacheNamespaceRef(UserMapper.class)
public interface UserProfileMapper {
@Select("SELECT * FROM user_profiles WHERE user_id = #{userId}")
UserProfile findByUserId(@Param("userId") Long userId);
}Marks an interface as a MyBatis mapper for component scanning.
/**
* Marks interface as MyBatis mapper
*/
@interface Mapper {
}Marks a method to flush batch statements.
/**
* Marks method to flush batch statements
*/
@interface Flush {
}Specifies a custom language driver for dynamic SQL processing.
/**
* Specifies language driver for dynamic SQL
*/
@interface Lang {
/** Language driver class */
Class<? extends LanguageDriver> value();
}Usage Examples:
@Mapper
public interface UserMapper {
@Select("SELECT * FROM users WHERE id = #{id}")
User findById(@Param("id") Long id);
@Flush
List<BatchResult> flush();
@Lang(XMLLanguageDriver.class)
@Select("SELECT * FROM users WHERE <if test='name != null'>name = #{name}</if>")
List<User> findByCondition(@Param("name") String name);
}/**
* Fetch types for associations
*/
enum FetchType {
/** Use global lazy loading setting */
DEFAULT,
/** Load association eagerly */
EAGER,
/** Load association lazily */
LAZY
}
/**
* Result set types
*/
enum ResultSetType {
/** Use driver default */
DEFAULT,
/** Forward-only result set */
FORWARD_ONLY,
/** Scroll-insensitive result set */
SCROLL_INSENSITIVE,
/** Scroll-sensitive result set */
SCROLL_SENSITIVE
}
/**
* Statement types
*/
enum StatementType {
/** Regular statement */
STATEMENT,
/** Prepared statement (default) */
PREPARED,
/** Callable statement for stored procedures */
CALLABLE
}Install with Tessl CLI
npx tessl i tessl/maven-org-mybatis--mybatis