MyBatis 的 接口绑定机制 是其核心功能之一,允许开发者通过定义 Java 接口直接操作数据库,而无需手动编写实现类。以下是接口绑定的详细解析:
一、接口绑定的核心原理
1. 动态代理生成实现类
- 机制:MyBatis 在运行时通过 JDK 动态代理,为 Mapper 接口生成代理对象。
- 触发时机:当调用
SqlSession.getMapper(Class<T> type)方法时,生成接口的代理实例。 - 代理逻辑:代理对象拦截接口方法调用,根据方法名和参数,查找对应的 SQL 语句并执行。
2. 接口与 SQL 的绑定规则
-
XML 映射文件:
- namespace 必须与接口的全限定名一致。
- SQL 标签的 id 必须与接口方法名一致。
<!-- UserMapper.xml --> <mapper namespace="com.example.UserMapper"> <select id="selectUserById" resultType="User"> SELECT * FROM user WHERE id = #{id} </select> </mapper> -
注解方式: 在接口方法上直接使用
@Select,@Insert等注解定义 SQL。public interface UserMapper { @Select("SELECT * FROM user WHERE id = #{id}") User selectUserById(int id); }
3. XML 与注解的优先级
-
默认规则:
- 若同一方法同时存在 XML 和注解配置,XML 优先级高于注解。
- 若仅有一种配置方式,MyBatis 按配置加载。
二、接口方法的参数映射
1. 参数传递规则
-
单个参数:
- 可直接通过
#{参数名}引用,参数名任意(如#{id})。
User selectUserById(int id); - 可直接通过
-
多个参数:
- 需使用
@Param注解指定参数名,否则按索引(arg0,arg1)或param1,param2引用。
User selectUserByNameAndAge(@Param("name") String name, @Param("age") int age); - 需使用
-
对象参数:
- 直接通过属性名引用(如
#{user.name})。
void insertUser(@Param("user") User user); - 直接通过属性名引用(如
2. 参数类型处理
- MyBatis 自动处理基本类型、POJO、Map、集合等参数类型。
- 复杂参数(如集合)可通过
<foreach>动态生成 SQL。
三、返回结果映射
1. 返回类型配置
-
resultType:指定返回的 Java 类型(如resultType="User")。 -
resultMap:通过自定义映射规则处理复杂结果集。<resultMap id="userMap" type="User"> <id property="id" column="user_id"/> <result property="name" column="user_name"/> </resultMap> <select id="selectUser" resultMap="userMap"> SELECT user_id, user_name FROM user </select>
2. 返回集合类型
-
接口方法可直接返回
List<T>或Map类型,MyBatis 自动处理。List<User> selectAllUsers();
3. 返回复杂对象
-
支持嵌套对象(
association)和集合(collection)映射。<resultMap id="userWithOrdersMap" type="User"> <collection property="orders" ofType="Order"> <id property="orderId" column="order_id"/> </collection> </resultMap>
四、高级特性
1. 注解扩展
-
@Options:设置执行选项(如超时、自增主键)。@Options(useGeneratedKeys = true, keyProperty = "id") @Insert("INSERT INTO user(name) VALUES(#{name})") void insertUser(User user); -
@ResultMap:引用 XML 中定义的resultMap。@ResultMap("userMap") @Select("SELECT * FROM user") List<User> selectAll();
2. 动态 SQL 支持
-
在接口方法中结合
@SelectProvider,@UpdateProvider等注解,动态生成 SQL。@SelectProvider(type = UserSqlBuilder.class, method = "buildSelectByName") List<User> selectByName(String name); // SQL 构建类 class UserSqlBuilder { public static String buildSelectByName(String name) { return new SQL() .SELECT("*") .FROM("user") .WHERE("name = #{name}") .toString(); } }
五、错误处理与注意事项
1. 方法未绑定 SQL
-
启动时报错:若接口方法未在 XML 或注解中定义 SQL,MyBatis 会在初始化时抛出
BindingException。org.apache.ibatis.binding.BindingException: Invalid bound statement (not found)
2. 接口默认方法
-
支持情况:MyBatis 3.5+ 支持接口默认方法,但默认方法不能绑定 SQL。
public interface UserMapper { default User defaultSelectUser() { // 需手动调用其他方法 return selectUserById(1); } }
六、与 Spring 集成
1. 接口扫描配置
-
在 Spring 中通过
@MapperScan注解扫描 Mapper 接口。@Configuration @MapperScan("com.example.mapper") public class MyBatisConfig {}
2. 事务管理
-
结合 Spring 的
@Transactional注解管理事务。@Transactional public void updateUser(User user) { userMapper.updateUser(user); }
七、总结
- 核心机制:动态代理实现接口与 SQL 的绑定,XML 和注解两种配置方式。
- 参数处理:支持简单类型、对象、集合等参数,通过
@Param注解解决多参数问题。 - 结果映射:灵活使用
resultType和resultMap处理简单或复杂结果集。 - 高级功能:注解扩展、动态 SQL、与 Spring 无缝集成。
- 适用场景:适用于需要精细控制 SQL 且追求代码简洁性的项目。