映射文件中的查询语句中一定要写返回类型,那么resultType和resultMap有什么区别?
前面学习中,我们知道POJO类中的属性名一定要与数据库表中的字段名一致(一对一进行映射),那么如果不一致时,则可以使用resultMap
MyBatis多个参数输入
案例:根据用户名和密码找到用户
首先我们想到的是@param注解,底层map映射是以注解的值为键参数为值
@Select("select * from user where name=#{name} and pwd=#{pwd}")
User getUser(@Param("name") String name,@Param("pwd") String pwd);
如果不使用注解,直接输入参数的话
@Select("select * from user where name=#{name} and pwd=#{pwd}")
User getUser(String name,String pwd);
结果报错,提示说name找不到,可以使用arg和param解决
@Select("select * from user where name=#{arg0} and pwd=#{arg1}")
User getUser(String name,String pwd);
@Select("select * from user where name=#{param1} and pwd=#{param2}")
User getUser(String name,String pwd);
最终结果都输出成功,那么arg0、param1和arg1、param2分别代表的就是参数一和参数二,当然也可以组合一起使用
MyBatis常用的类型都设置了类型别名
例如:java.lang.Integer —— int || integer
int —— _int || _integer
Map——map
List ——list
MyBatis批量删除
Sql语句:delete from user where id in (1,2,3);
所以xml的sql语句应该使用${}传参(不会自动加单引号)
MyBatis获取添加功能自增的主键
@Test
public void addUser(){
User user = new User(null,"name","123132");
SqlSession sqlSession = MyBatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
mapper.addUser(user);
sqlSession.commit();
System.out.println(user);
}
UseGeneratedKeys即是否返回主键,keyProperty表示主键返回到属性上,上述例子中,创建的user对象id为null,但是最后输出id为7,是因为keyProperty将主键值赋给了User的id.
MyBatis驼峰命名映射
一般在数据库中字段名使用‘_’连接
但是实体类使用的是驼峰命名,这样查询的结果无法映射进实体类中
针对以上问题,可以在MyBatis的配置文件中设置setting标签将驼峰转化设为true,默认为false
<settings>
<setting name=”mapUnderscoreToCamelCase” value=”true”/>
</settings>
而在SpringBoot项目中没有其配置文件,在application.properties中加入:
Mybatis.configuration.mapUnderscoreToCamelCase=true
通过resultMap解决字段名和属性名的映射
resultMap
<resultMap id="teacherMap" type="com.wang.pojo.Teacher">
<id property="id" column="id"></id>
<result property="TName" column="t_name"></result>
<result property="schoolId" column="schoolId"></result>
</resultMap>
resultMap中,id标签代表主键,result代表其他的
property属性即实体类的属性,column即数据库字段
多对一关系映射
例子:学校表和老师表,老师表和学校表进行左连接,按照学校唯一标识ID查找老师的信息
那么我们可以在老师实体类中加入,学校类属性
select teacher.id,t_name,schoolId,school.id as s_id,s_name from teacher left join school on teacher.schoolId = school.id where school.id=#{id};
要注意的是两表的主键都为id,where后面的id写明具体表的id,否则报错,得到的字段取别名以便分辨(学校id为s_id)
public class Teacher {
private Integer id;
private String TName;
private Integer SchoolId;
private School school;
public School getSchool() {
return school;
}
public void setSchool(School school) {
this.school = school;
}
@Override
public String toString() {
return "Teacher{" +
"id=" + id +
", TName='" + TName + '\'' +
", SchoolId=" + SchoolId +
", school=" + school +
'}';
}
public Integer getSchoolId() {
return SchoolId;
}
public void setSchoolId(Integer schoolId) {
SchoolId = schoolId;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getTName() {
return TName;
}
public void setTName(String TName) {
this.TName = TName;
}
}
方法一:级联属性赋值
<resultMap id="teacherSchoolMap" type="com.wang.pojo.Teacher">
<id property="id" column="id"></id>
<result property="TName" column="t_name"></result>
<result property="schoolId" column="schoolId"></result>
<result property="school.id" column="s_id"></result>
<result property="school.sName" column="s_name"></result>
</resultMap>
老师实体类的学校类属性的具体属性和表名一一对应
方法二:associate
<resultMap id="teacherSchoolMap2" type="com.wang.pojo.Teacher">
<id property="id" column="id"></id>
<result property="TName" column="t_name"></result>
<result property="schoolId" column="schoolId"></result>
<association property="school">
<id property="id" column="s_id"></id>
<id property="sName" column="s_name"></id>
</association>
</resultMap>
方法三:分步查询
即执行两条sql语句分两步:先查出老师信息,再根据老师信息中的学校ID去学校表中查询信息
SchoolMapper
public interface SchoolMapper {
public List<School> getAll();
public School getOneById(int id);
public School getSchoolAndTeacherById(int id);
}
<select id="getOneById" resultType="School">
select * from school where id=#{id}
</select>
结果如下:
延迟加载(懒加载)
表示按需加载,当前要访问的信息执行相对应的sql语句,如果当前不访问则不执行。(主要由分布查询来实现)
例子:根据老师的id查询所有信息(包括对应学校的信息)
<select id="getTeacherById" resultMap="getTeacherById">
select * from teacher where id=#{id}
</select>
<resultMap id="getTeacherById" type="Teacher">
<id property="id" column="id"></id>
<result property="TName" column="t_name"></result>
<result property="schoolId" column="schoolId"></result>
<association property="school" select="com.wang.dao.SchoolMapper.getOneById" column="schoolId" fetchType="lazy"></association>
</resultMap>
首先分两步走,根据老师的唯一标识查询老师的所有信息,然后老师类中的学校属性根据association执行SchoolMapper的getOneById方法根据返回的schoolId查询学校信息。即:
select * from teacher where id=1 //设id为1,查出schoolId=1,传入第二条sql
select * from school where id=1 //将信息与学校类一一映射,作为老师类的学校信息属性
懒加载即如果只需要查询老师的信息,不涉及学校,只执行第一条sql语句,需要用到学校信息时才进行第二条sql。例如:
此时不设为懒加载,输出如下:
懒加载配置:
lazyLoadingEnabled:实现延迟加载,在核心配置文件设置,默认为false
aggressiveLazyLoading:任何方法调用都会加载该对象的所有属性,默认flase
所以开启懒加载,lazyLoadingEnabled开启true aggressiveLazyLoading保持false
则,全局的分步式都可以延迟加载
如果有的功能无需设置延迟加载,将fetchType设置立即加载或延迟加载
开启懒加载测试结果如下:
开始只需要老师的信息,根据按需加载不会执行第二条sql语句,当需要学校的信息时,再次按需加载第二条sql语句