# 前言
最初设计时,MyBatis 是一个 XML 驱动的框架。配置信息是基于 XML 的,而且映射语句也是定义在 XML 中的。而到了 MyBatis 3,有新的可用的选择了。MyBatis3 构建在基于全面而且强大的 Java 配置 API 之上。这个配置 API 是基于 XML 的 MyBatis 配置的基础,也是新的基于注解配置的基础。注解提供了一种简单的方式来实现简单映射语句,而不会引入大量的开销。
注意:不幸的是,Java 注解限制了它们的表现和灵活。最强大的 MyBatis 映射不能用注解来构建,那并不可笑,基于 Java 注解的配置离不开它的特性。
# 注解开发
之前需要编写对应的映射器并绑定到接口上,通过接口执行 sql 语句。注解开发实现无需 xml
映射器配置,直接使用注解在接口上进行配置。
在前言已经说过了,注解的表达能力和灵活性有限,并不是说完全抛弃 xml 配置。
复习一下接口映射:
之前使用 xml 需要编写映射器:在 xml 中定义映射规则和 SQL 语句,再绑定到接口的方法定义上:
<?xml version="1.0" encoding="UTF-8" ?> | |
<!DOCTYPE mapper | |
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" | |
"http://mybatis.org/dtd/mybatis-3-mapper.dtd"> | |
<!-- 映射 StudentMapper 接口,namespace 是接口的全类限定名 --> | |
<mapper namespace="com.cyan.mappers.StudentMapper"> | |
<select id="selectStudent" resultType="com.cyan.entity.Student"> | |
select * from student | |
</select> | |
</mapper> |
当然,使用全类限定名太麻烦,可以再 xml 中加上别名
<typeAliases> | |
<package name="com.cyan.entity" /> | |
<package name="com.cyan.mappers" /> | |
</typeAliases> |
现在使用注解实现:
@Insert("insert into student(sid, name) value(#{sid}, #{name})") | |
int addStudent(Student s); |
同时修改一下配置文件的映射器注册:
<mappers> | |
<mapper class="com.cyan.mapper.StudentMapper"/> | |
</mappers> |
使用的时候,还是直接向 SqlSession 传入接口 Class 即可:
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class); |
# 自定义映射
通过
@Result
进行自定义映射。
@Results({ | |
@Result(id = true, column = "sid", property = "sid"), | |
@Result(column = "name", property = "name") | |
}) | |
@Select("select * from student") | |
List<Student> getAllStudent(); |
左边的 column
其实就是查询结果组成的表的一列,所以我们为 Student 再加一个属性 sex
,我想让性别的结果映射到 Student 对象的 name 属性上,让 name 结果映射为 sex。
@Results({ | |
@Result(id = true, column = "sid", property = "sid"), | |
@Result(column = "sex", property = "name"), | |
@Result(column = "name", property = "sex") | |
}) | |
@Select("select * from student") | |
List<Student> getAllStudent(); |
我知道这种映射没有卵用,我只是举个🌰。
# 复杂查询
上一篇讲了一对多的复杂查询,teacher 对象有一个学生列表的属性,这里用注解实现:
@Select("select * from student inner join teach on student.sid = teach.sid where tid = #{tid}") | |
List<Student> getStudentByTid(int tid); | |
@Reuslt({ | |
@Result(id = true, column = "tid", property = "tid"), | |
@Result(column = "name", property = "name"), | |
@Result(column = "tid", property = "studentList", many = | |
@Many(select = "getStudentByTid")) | |
}) | |
@Select("Select * from teacher where tid = #{tid}") | |
Teacher getTeacherByTid(int tid); |
子查询结果作为 @Result
注解的一个 many 结果,代表子查询的所有结果都归入此集合中(也就是之前的 collection 标签)。
@Result
也提供了 @One
子注解来实现一对一的关系表示,类似于之前的 assocation
标签:
@Results({ | |
@Result(id = true, column = "sid", property = "sid"), | |
@Result(column = "sex", property = "name"), | |
@Result(column = "name", property = "sex"), | |
@Result(column = "sid", property = "teacher", one = | |
@One(select = "getTeacherBySid") | |
) | |
}) | |
@Select("select * from student") | |
List<Student> getAllStudent(); |
如果觉得在 Java 代码中编写映射规则不美观,可以使用 @ResultMap
标签,指定 xml 文件里的 resultMap
的 ID,就可以在该 ResultMap
编写映射规则了。
# 指定构造器与参数
使用 @ConstructorArgs
参数来指定构造器
@ConstructorArgs({ | |
@Arg(column = "sid", javaType = int.class), | |
@Arg(column = "name", javaType = String.class) | |
}) | |
@Select("select * from student where sid = #{sid} and sex = #{sex}") | |
Student getStudentBySidAndSex(@Param("sid") int sid, @Param("sex") String sex); |
参数列表中,参数个数超过两个时就必须要使用 @Param
来指定参数名称,不然 Mybatis 不明确哪个参数是什么。
如果传入的是一个对象,就需要在 sql 语句中指定属性来自哪:
@Insert("insert into student(sid, name, sex) values(#{sid}, #{student.name}, #{student.sex})") | |
int addStudent(@Param("sid") int sid, @Param("student") Student student); |
上文提到缓存机制,在注解开发中就需要使用:
@CacheNamespace(readWrite = false) | |
public interface MyMapper { | |
@Select("select * from student") | |
@Options(useCache = false) | |
List<Student> getAllStudent(); | |
} |
使用 @CacheNamespace
注解直接定义在接口上即可,然后我们可以通过使用 @Options
来控制单个操作的缓存启用。
# 参考
https://www.hxstrive.com/subject/mybatis/196.htm
https://www.yuque.com/qingkongxiaguang/javaweb/gn0syt#815f8cec