1.实体类SysUser.java
public class SysUser implements Serializable {
private static final long serialVersionUID = -328602757171077630L;
private Long id;
private String userName;
private String userPassword;
private String userEmail;
private String userInfo;
private byte[] headImg;
private Date createTime;
private SysRole role;
private List roleList;
}//setter、getter略
2.UserMapper.xml文件
3.UserMapper.java接口
public interface UserMapper {
SysUser selectById(Long id);
List selectAll();
List selectRolesByUserId(Long userId);
}
主要处理数据库一对一,一对多的查询,在MyBatis中使用存储过程的方法,处理存储过程的入参和出参方法,枚举方法和数据表字段的处理方法。
1.关联的嵌套结果映射需要关联多个表将所有需要的值一次性查询出来。这种方式的好处时减少数据库查询次数,减轻压力。
2.缺点:要写复杂的SQL,当一定会使用嵌套结果,并且整个复杂的SQL执行速度很快时,建议使用关联的嵌套结果映射。
使用resultMap配置一对一映射在XML映射文件中配置结果映射。
使用resultMap的association标签配置一对一映射。
SQL通过多次查询转换为需要的结果,最后将结果组合成一个对象。
association标签的嵌套查询常用的属性如下。
column:列名(或别名),将主查询中列的结果作为嵌套查询的次数,配置方式如column={prop1=coll,prop2=col2},prop1和prop2将作为嵌套查询的参数。
1.MyBatis延迟加载是通过动态代理实现的,当调用配置为延迟加载的属性方法时,动态代理的操作会被触发,这些额外的操作就是通过MyBatis的SqlSession去执行嵌套SQL的。
2.由于在和某些框架集成时,SqlSession的生命周期交给了框架来管理,因此当对象超出SqlSession生命周期调用时,会由于链接关闭等问题而抛出异常。在和Spring集成时,要确保只能在Service层调用延迟加载的属性,当结果从Service层返回至Controller层时,如果获取延迟加载的属性值,会因为SqlSession已经关闭而抛出异常。
一对多映射只有两种配置方式,都是使用collection标签进行的。
SysUser 中的属性可以直接通过继承u serMap 来使用sys_user 的映射关系, 其次在RoleMapper.xml 中的roleMap 映射包
含了sys_role 的映射关系,因此可以直接引用roleMap , 经过这两个方式的简化。
collection集合的嵌套结果映射
1.和association类似,集合的嵌套结果映射就是指通过一次SQL查询将所有的结果查询出来,然后通过配置的结果映射,将数据映射到不同的对象中去。在一对多的关系中,主表的一条数据会对应关联表中的多条数据,因此一般查询时会查询出多个结果,按照一对多的数据结果存储数据的时候,最终的结果数会小于等于查询的总记录数。
2.渐进式地去实现一个SQL,查询出所有用户和用户拥有的角色,以及角色所包含的所有权限信息的两层嵌套结果。
3.对应的属性必须是对象中的集合类型
4.MyBatis在处理结果的时候,会判断结果是否相同,如果是相同的结果,则只会保留第一个结果。
MyBatis判断结果是否相同时,最简单的情况就是在映射配置中至少有一个id标签,在userMap中配置如下。
1.我们对id(构造方法中为idArg)的理解一般是,它配置的字段为表的主键(联合主键时可以配置多个id标签), 因为MyBatis的resultMap只用配置结果如何映射,并不知道这个表具体如何。id的唯一作用就是在嵌套的映射配置时判断数据是否相同,当配置id标签时,MyBatis只需要逐条比较所有数据中 id标签配置的字段值是否相同即可。在配置嵌套结果查询时,配置id标签可以提高处理效率。
2.没有配置id时,MyBatis就会将resultMap中配置的所有字段进行比较,如果所有字段的值都相同就合并,只要有一个字段不同,就不合并。
3.在嵌套结果配置id属性时,如果查询语句中没有查询id属性配置的列,就会导致id对应的值为null.这种情况下,所有值的id都相同,因此会使用嵌套的集合中只有一条数据。所以在配置id列时,查询语句中必须包含该列。MyBatis会对嵌套的每一级对象都进行属性比较。
association关联的嵌套查询这种方式会执行额外的SQL查询,映射配置会简单很多。通过一次查询将结果映射到不同对象的方式,称之为关联的嵌套结果映射。因为所有嵌套查询都配置为延迟加载,因此不存在N+1的问题。
在MyBatis的全局配置中,有一个参数为aggressiveLazyLoading.这个参数的含义是,当该参数设置为true时,对任意延迟属性的调用会使用带有延迟加载属性的对象完整加载,反之,每种属性都将按需加载。
MyBatis仍然提供了参数lazyLoadTriggerMethods帮助解决这个问题,这个参数的含义是,当调用配置种的方法时,加载全部的延迟加载数据。默认值为:equals,clone,hashCode,toString.
有时一个单独的数据查询会返回很多不同数据类型(希望有些关联)的结果集。
discriminator鉴别器标签就是用来处理这种情况的。
discriminator标签常用的两个属性如下。
discriminator标签可以有一个或多个case标签,case标签包含以下三个属性。
case标签下面可以包含的标签和resultMap一样,用法也一样。
1.在MyBatis映射的Java类中,不推荐使用基本类型,数据库BLOB类型对象的Java类型通常都是写成byte[]字节数组的形式的,因为byte[]数组不存在默认值的问题,所以不影响一般的使用。
2.但是在不指定javaType的情况下,MyBatis默认使用Byte类型。由于byte是基本类型,所以设置javaType时要使用带下划线的方式,在这里就是_byte[]._byte对应的是基本类型,byte对应的是Byte类型。
3.使用出参方式时,通常情况下会使用对象中的属性接收出参的值,或者使用Map类型接收返回值。
4.这两种情况有很大的区别,当使用JavaBean对象接收出参时,必须保证所有出参在这样的错误。
5.这是由于JavaBean对象中不存在出参对应的setter方法,使用Map类型时就不需要保证所有出参都有对应的属性,当Map接收了存储过程的出参时,可以提供Map对象的get("属性名")方法获取出参的值。
error:parameter number x is not an OUT parameter
6.产生这个错误可能是因为调用的存储过程不车子,或者MyBatis中写的出参和数据库存储过程的出参无法对应。
第二个存储过程。
第三个和第四个存储过程
使用枚举或其他对象
1.在数据库中不存在一个和Enabled枚举对应的数据库类型,因此在和数据库交互的时候,不能直接使用枚举类型,在查询数据时,需要将数据库int类型的值转换为Java中的枚举值。在保存、更新数据或者作为查询条件时,需要将枚举值转换为数据库中的int类型。
2.MyBatis在处理Java类型和数据库类型时,使用TypeHandler(类型处理器)对这两者进行转换。
3.MyBatis为Java和数据库jdbc中的基本类型和常用的类型提供了TypeHandler接口的实现。MyBatis在启动时会加载所有的JDBC对应的类型加载器,在处理枚举类型时默认使用org.apache.ibatis.type.EnumTyoeHandler处理器,这个处理器会将枚举类型转换为字符串类型的字面值并使用,对于Enabled而言便是disabled和enabled字符串。这个处理器只是对枚举的字面值进行处理。
MyBatis还提供了另一个org.apache.ibatis.type.EnumOrdinalTypeHandler处理器,这个处理器使用枚举的索引进行处理。
使用自定义的类型处理器
有时候,值既不是枚举的字面值,也不是枚举的索引值,这种情况下就需要自己来实现类型加载器了。
对Java8日期(JSR-310)的支持
BaseTypeHandler