Mybatis--04

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=""))
基于SSM框架的智能家政保洁预约系统,是一个旨在提高家政保洁服务预约效率和管理水平的平台。该系统通过集成现代信息技术,为家政公司、家政服务人员和消费者提供了一个便捷的在线预约和管理系统。 系统的主要功能包括: 1. **用户管理**:允许消费者注册、登录,并管理他们的个人资料和预约历史。 2. **家政人员管理**:家政服务人员可以注册并更新自己的个人信息、服务类别和服务时间。 3. **服务预约**:消费者可以浏览不同的家政服务选项,选择合适的服务人员,并在线预约服务。 4. **订单管理**:系统支持订单的创建、跟踪和管理,包括订单的确认、完成和评价。 5. **评价系统**:消费者可以在家政服务完成后对服务进行评价,帮助提高服务质量和透明度。 6. **后台管理**:管理员可以管理用户、家政人员信息、服务类别、预约订单以及处理用户反馈。 系统采用Java语言开发,使用MySQL数据库进行数据存储,通过B/S架构实现用户与服务的在线交互。系统设计考虑了不同用户角色的需求,包括管理员、家政服务人员和普通用户,每个角色都有相应的权限和功能。此外,系统还采用了软件组件化、精化体系结构、分离逻辑和数据等方法,以便于未来的系统升级和维护。 智能家政保洁预约系统通过提供一个集中的平台,不仅方便了消费者的预约和管理,也为家政服务人员提供了一个展示和推广自己服务的机会。同时,系统的后台管理功能为家政公司提供了强大的数据支持和决策辅助,有助于提高服务质量和管理效率。该系统的设计与实现,标志着家政保洁服务向现代化和网络化的转型,为管理决策和控制提供保障,是行业发展中的重要里程碑。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值