Mybatis--04

    技术2025-09-25  70

    文章目录

    1.Mybatis中的延迟加载1.1延迟加载和立即加载1.2一对一的延迟加载1.3一对多实现延迟加载 2.Mybatis中的缓存2.1 Mybaits中的一级缓存2.2Mybatis中的二级缓存 3.Mybatis中的注解开发3.1Mybatis的常用注解3.2使用Mybatis注解实现单表CRUD3.3使用注解实现复杂关系映射的开发

    1.Mybatis中的延迟加载


    1.1延迟加载和立即加载

    在用户和账户的关系中,假设此时我们有1个用户,该用户有100个账户。那么此时有这样一个问题。

    当我们查询用户时,要不要把关联的账户也一起查询出来?当我们查询账户时,要不要把关联的用户也一起查询出来?

    显然当我们查询用户时,它的账户信息需要的时候再去查询,因为它有100个账户,如果全部查询出来非常的耗时,这就是所谓的延迟加载。而查询账户时,我们就可以同时把它对应的用户信息就查询出来,因为它只对应一个用户。这就是立即加载。

    延迟加载:

    在需要用到数据时才进行加载,不需要用到数据时就不加载数据。延迟加载也称懒加载。在一对多或多对多的关系中通常采用延迟加载。

    立即加载:

    不管是否需要数据,只要一进行查询,就会把相关联的数据一并查询出来。在多对一或一对一的关系中通常采用立即加载。

    1.2一对一的延迟加载

    需求:查询账户信息时,实现延迟加载,如果不需要用户信息,只查询账户信息。账户的持久层映射文件: <mapper namespace="com.zut.dao.IAccountDao"> <!-- 定义可以封装带有User的Account的 resultMap --> <resultMap id="AccountUserMap" type="Account"> <id property="id" column="id"></id> <result property="uid" column="uid"></result> <result property="money" column="money"></result> <!-- 关联User对象 --> <association property="user" javaType="User" column="uid" select="com.zut.dao.IUserDao.getUserById"></association> </resultMap> <select id="findAll" resultMap="AccountUserMap"> SELECT * FROM account </select> </mapper> assocation标签中的select属性表示我们要调用的映射语句的id,它会从column属性指定的列中检索数据,作为参数传递给目标select语句column指定我们要传递给select映射的参数。 用户的持久层映射文件: <mapper namespace="com.zut.dao.IUserDao"> <select id="getUserById" parameterType="java.lang.Integer" resultType="User"> select * from user where id=#{aa} </select> </mapper> 上面的都完成之后,我们需要在Mybatis的主配置文件中添加开启延迟加载的配置: <!-- 开启延迟加载 --> <settings> <setting name="lazyLoadingEnabled" value="true"/> <setting name="aggressiveLazyLoading" value="false"/> </settings> 注意在写setting标签时要写到正确的位置。具体参考Mybatis的官方文档:Mybatis的XML配置 测试结果如下: 我们发现只是将Account对象查询出来,而没有查询User对象。

    1.3一对多实现延迟加载

    需求:查询用户时实现延迟加载。用户的持久层映射文件: <mapper namespace="com.zut.dao.IUserDao"> <!-- 配置User的resultMap --> <resultMap id="UserAccountMap" type="User"> <id property="id" column="id"></id> <result property="username" column="username"></result> <result property="sex" column="sex"></result> <result property="birthday" column="birthday"></result> <result property="address" column="address"></result> <!-- 配置user对象中accounts集合的映射 --> <collection property="accounts" ofType="Account" select="com.zut.dao.IAccountDao.getAccountById" column="id"></collection> </resultMap> <select id="findAll" resultMap="UserAccountMap"> SELECT * from user </select> </mapper> 这里同样在collection标签中使用 select属性和column属性,作用和之前的一样。 账户的持久层映射文件: <mapper namespace="com.zut.dao.IAccountDao"> <select id="getAccountById" parameterType="java.lang.Integer" resultType="account"> select * from account where uid = #{uid} </select> </mapper> 测试结果如下:

    同样没有加载账户的信息。

    2.Mybatis中的缓存

    什么是缓存? 存在内存中的临时数据,减少和数据库的交互次数,提高执行效率。 什么样的数据能使用缓存,什么样的数据不能使用 适用于缓存: 经常查询并且不经常改变的数据的正确与否对最终结果影响不大的 不适用于缓存: 经常改变的数据数据的正确与否,对结果影响很大的例如:商品的库存、银行的汇率、股市的牌价

    2.1 Mybaits中的一级缓存

    一级缓存:

    它指的是Mybatis中SqlSession对象的缓存。当我们执行查询之后,查询的结果会同时存入到SqlSession为我们提供的一块区域中。该区域的结构是一个Map。当我们再次查询同样的数据,mybatis会先去sqlsession中查询是否有,有的话就直接拿出来用。当SqlSession对象消失时,Mybatis的一级缓存就消失了一级缓存是 SqlSession 级别的缓存,只要 SqlSession 没有 flush 或 close,它就会存在。当调用 SqlSession 的修改、添加、删除、commit()、close()、clearCache() 等方法时,就会清空一级缓存。

    一级缓存的流程图如下:

    第一次发起查询用户 id 为 1 的用户信息,Mybatis 会先去找缓存中是否有 id 为 1 的用户信息,如果没有,从数据库查询用户信息。得到用户信息,将用户信息存储到一级缓存中。如果 sqlSession 去执行 commit 操作(执行插入、更新、删除),那么 Mybatis 就会清空 SqlSession 中的一级缓存,这样做的目的为了让缓存中存储的是最新的信息,避免脏读第二次发起查询用户 id 为 1 的用户信息,先去找缓存中是否有 id 为 1 的用户信息,缓存中有,直接从缓存中获取用户信息 Mybatis中默认就是使用一级缓存的,不需要配置。一级缓存中存放的是对象(其实就是Map结构)

    2.2Mybatis中的二级缓存

    它指的是Mybatis中的SqlSessionFactry对象的缓存。由同一个SqlSessionFactory对象创建的SqlSession共享其缓存.

    二级缓存是 mapper 映射级别的缓存,多个 SqlSession 去操作同一个 Mapper 映射的 sql 语句,多个SqlSession 可以共用二级缓存,二级缓存是跨 SqlSession 的。

    二级缓存的流程图如下:

    意味同一个SqlSessionFactory创建的SqlSession可以共享二级缓存的内容

    如果要使用二级缓存,需要做以下配置:让Mybatis框架支持二级缓存,即在主配置文件中配置: <settings> <!-- 开启二级缓存的支持 --> <setting name="cacheEnabled" value="true"/> </settings>

    因为 cacheEnabled 的取值默认就为 true,所以这一步可以省略不配置。为 true 代表开启二级缓存;为false 代表不开启二级缓存。

    让当前的映射文件支持二级缓存,即在映射配置文件中配置: <mapper namespace="cn.ykf.mapper.UserMapper"> <!-- 使用缓存 --> <cache/> </mapper> 让当前的操作支持二级缓存: <select id="findById" resultType="user" parameterType="int" useCache="true"> select * from user where id = #{uid} </select>

    将 UserDao.xml 映射文件中的select标签中设置 useCache=”true”代表当前这个 statement 要使用二级缓存,如果不使用二级缓存可以设置为 false。

    注意:当我们使用二级缓存的时候,所缓存的类一定要实现 java.io.Serializable 接口,这样才可以使用序列化的方式来保存对象。由于是序列化保存对象,所以二级缓存中存放的是数据,而不是整个对象。

    3.Mybatis中的注解开发


    3.1Mybatis的常用注解

    注解作用@Insert实现新增@Update实现更新@Delete实现删除@Select实现查询@Result实现结果集封装@Results可以与@Result 一起使用,封装多个结果集@ResultMap实现引用@Results 定义的封装@One实现一对一结果集封装@Many实现一对多结果集封装@SelectProvider实现动态 SQL 映射@CacheNamespace实现注解二级缓存的使用

    3.2使用Mybatis注解实现单表CRUD

    用户实体类接口层的IUserDao的代码如下: /** * 在mybatis中,针对CRUD一共有四个注解 * @Select @Insert @Update @Delete */ public interface IUserDao { /** * 查询所有用户 * @return */ @Select("select * from user") List<User> findAll(); /** * 保存用户 * @param user */ @Insert("insert into user(username,address,sex,birthday) values(#{username},#{address},#{sex},#{birthday})") void saveUser(User user); /** * 更新用户 * @param user */ @Update("update user set username=#{username},address=#{address},birthday=#{birthday},sex=#{sex} where id=#{id}") void updateUser(User user); /** * 删除用户 * @param id */ @Delete("delete from user where id=#{aa}") void deleteUser(Integer id); }

    上面的写法要求数据库里的列名和实体类中的属性一致,如果出现不一致的情况,要使用@Result、@Results、@ResultMap等标签。如下所示:

    public interface IUserDao { /** * 查询所有用户 * @return */ @Select("select * from user") @Results(id="userMap", value= { @Result(id=true,column="id",property="userId"), @Result(column="username",property="userName"), @Result(column="sex",property="userSex"), @Result(column="address",property="userAddress"), @Result(column="birthday",property="userBirthday") }) List<User> findAll();

    3.3使用注解实现复杂关系映射的开发

    实现复杂关系映射之前我们可以在映射文件中通过配置来实现,在使用注解开发时我们需要借 助@Results 注解,@Result 注解,@One 注解,@Many注解。

    @Results 注解: 代替的是标签resultMap 该注解中可以使用单个@Result 注解,也可以使用@Result 集合 @Results({@Result(),@Result()})或@Results(@Result())

    @Resutl 注解 代替了 id标签和result标签 @Result 中 属性介绍: id : 是否是主键字段 column: 数据库的列名 property: 需要装配的属性名 one : 需要使用的@One 注解(@Result(one=@One)())) many: 需要使用的@Many 注解(@Result(many=@many)()))

    @One 注解(一对一)

    代替了标签,是多表查询的关键,在注解中用来指定子查询返回单一对象。

    @One 注解属性介绍:

    select 指定用来多表查询的 sqlmapper fetchType 会覆盖全局的配置参数 lazyLoadingEnabled。 使用格式: @Result(column=" “,property=”",one=@One(select=""))

    @Many 注解(多对一)

    代替了标签,是是多表查询的关键,在注解中用来指定子查询返回对象集合。 注意:聚集元素用来处理“一对多”的关系。需要指定映射的 Java 实体类的属性,属性的 javaType(一般为 ArrayList)但是注解中可以不定义; 使用格式: @Result(property="",column="",many=@Many(select=""))
    Processed: 0.013, SQL: 9