1.mybatis的延迟加载

问题:在一对多中,当我们有一个用户,他有100个账户

在查询用户的时候,要不要把关联的账户查出来?

在查询账户的时候,要不要把关联的用户查出来?

解决:在查询用户的时候,用户下的账户信息应该是,什么时候使用,什么时候查询出来,如果每次查询用户的时候都把关联的账户信息查询出来,会浪费内存空间

但是在查询账户时,账所属的用户信息应该是随着账户查询时一起查询出来

1.1.什么是延迟加载:

延迟加载:在真正使用数据时才发起查询,不用的时候不查询,所以是按需加载(懒加载)。

1.2.延迟加载的优缺点

延迟加载的好处:先从单表查询,需要时再从关联表去关联查询,大大提高数

据库性能,因为查询单表要比关联查询多张表速度要快。

延迟加载的坏处:因为只有当需要用到数据时,才会进行数据库查询,这样在大批量数据查询时,因为查询工作也要消耗 时间,所以可能造成用户等待时间变长,造成用户体验下降。

2.多对一、一对一延迟加载的实现

使用assocation实现延迟加载

需求:查询账户信息同时查询用户信息

2.1 账户的持久层 DAO 接口

public interface IAccountDao {

    /**
*查询所有账户,同时获取账户的所属用户名称以及它的地址信息
* @return
*/ List<Account> findAll(); }

2.2. 账户的持久层映射文件

<?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">

<mapper namespace="com.itheima.dao.IAccountDao">

<!-- 建立对应关系 -->

<resultMap type="account" id="accountMap">

<id column="aid" property="id"/>

<result column="uid" property="uid"/> <result column="money" property="money"/> <!-- 它是用于指定从表方的引用实体属性的 --> <association property="user" javaType="user" select="com.itheima.dao.IUserDao.findById" column="uid"> </association> </resultMap> <select id="findAll" resultMap="accountMap"> select * from account </select> </mapper>

select: 填写我们要调用的 select 映射的 id

column : 填写我们要传递给 select 映射的参数

2.3.用户的持久层接口

public interface IUserDao { 

       /**

       *根据 id 查询

       * @param userId 

       * @return 

       */ 

        User findById(Integer userId);
}

2.4.用户的持久层映射文件

<?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">

<mapper namespace="com.itheima.dao.IUserDao">

<!-- 根据 id 查询 -->

<select id="findById" resultType="user" parameterType="int" >

select * from user where id = #{uid}

</select>
</mapper>

2.5.开启 Mybatis 的延迟加载策略

我们需要在 Mybatis 的配置文件 SqlMapConfig.xml 文件中添加延迟加载的配置。

<!-- 开启延迟加载的支持 -->

<settings>

 <setting name="lazyLoadingEnabled" value="true"/>

 <setting name="aggressiveLazyLoading" value="false"/>

</settings>

2.6.编写测试只查账户信息不查用户信息。

@Test
public void testFindAll(){ //执行操作 List<Account> accounts = accountDao.findAll();
}

3.一对多,多对多实现延迟加载

我们也可以在一对多关系配置的<collection>结点中配置延迟加载策略。

<collection>结点中也有 select 属性,column 属性。

需求: 完成加载用户对象时,查询该用户所拥有的账户信息。

3.1.在 User 实体类中加入 List<Account>属性

public class User implements Serializable { 

  private Integer id;
private String username;
private Date birthday;
private String sex;
private String address;
private List<Account> accounts;
public List<Account> getAccounts() {
return accounts; }
public void setAccounts(List<Account> accounts) {
this.accounts = accounts; }
public Integer getId() {
return id; }
public void setId(Integer id) {
this.id = id; }
public String getUsername() {
return username; }
public void setUsername(String username) {
this.username = username; }
public Date getBirthday() {
return birthday; }
public void setBirthday(Date birthday) {
this.birthday = birthday; }
public String getSex() {
return sex; }
public void setSex(String sex) {
this.sex = sex; }
public String getAddress() {
return address; }
public void setAddress(String address) {
this.address = address; }
@Override
public String toString() { return "User [id=" + id + ", username=" + username + ", birthday=" + birthday + ", sex=" + sex + ", address=" + address + "]"; } } 6

3.2.编写用户持久层接口的方法

/**
*查询所有用户,同时获取出每个用户下的所有账户信息
*@return
*/
List<User> findAll();

3.3.编写账户持久层接口的方法

/**
* 根据用户 id 查询账户信息
* @param uid
* @return
*/
List<Account> findByUid(Integer uid);

3.4.编写用户持久层映射配置

<resultMap type="user" id="userMap">

 <id column="id" property="id"></id>

 <result column="username" property="username"/>

 <result column="address" property="address"/>

 <result column="sex" property="sex"/>

 <result column="birthday" property="birthday"/>

 <!-- collection 是用于建立一对多中集合属性的对应关系 ofType 用于指定集合元素的数据类型 select 是用于指定查询账户的唯一标识(账户的 dao 全限定类名加上方法名称) column 是用于指定使用哪个字段的值作为条件查询 -->

 <collection property="accounts" ofType="account" select="com.itheima.dao.IAccountDao.findByUid" column="id"> 

</collection>

 </resultMap>

<!-- 配置查询所有操作 -->

 <select id="findAll" resultMap="userMap">

 select * from user

 </select>

<collection>标签: 主要用于加载关联的集合对象

select 属性: 用于指定查询 account 列表的 sql 语句,所以填写的是该 sql 映射的 id

column 属性: 用于指定 select 属性的 sql 语句的参数来源,上面的参数来自于 user 的 id 列,所以就写成 id 这一 个字段名了

3.5.编写账户持久层映射配置

<!-- 根据用户 id 查询账户信息 -->

 <select id="findByUid" resultType="account" parameterType="int"> 

    select * from account where uid = #{uid}

 </select>

3.6.在主配置文件中配置延迟加载

<!-- 开启延迟加载的支持 -->

<settings>

 <setting name="lazyLoadingEnabled" value="true"/>

 <setting name="aggressiveLazyLoading" value="false"/>

</settings>

3.7.测试只加载用户信息

@Test
public void testFindAll() {
//6.执行操作 List<User> users = userDao.findAll();
}

4.立即加载

不管用不用,只要一调用方法,马上发起查询

在对应的四种表关系中:一对多,多对一,一对一,多对多

一对多、多对多:通常情况下我们都是采用延迟加载

多对一、一对一: 通常情况下我们都是采用立即加载

5.mybatis中的缓存

什么是缓存:存在于内存中的临时数据

为什么要使用缓存:减少和数据库的交互次数,提高执行效率

什么样的数据能使用缓存,什么样的数据不能使用缓存:

适用于缓存:经常查询并且不经常改变的。

数据的正确与否对最终的结果影响不大。

不适用于缓存:经常改变的数据

数据的正确与否对最终结果影响很大的。

例如:商品的库存,银行的汇率,股市的牌价

5.1.mybatis的一级缓存和二级缓存

一级缓存:它指的是mybatis中SqlSession对象的缓存(一级缓存是 SqlSession 级别的缓存,只要 SqlSession 没有 flush 或 close,它就存在。 )

当我们执行查询之后,查询的结果会同时存入到SqlSession为我们提供的一块区域中。

该区域的结果是一个Map,当我们再次查询同样的数据,mybatis会先去SqlSession中查询是否有,有的话直接拿出来用。

当SqlSession对象消失的时候,mybatis的一级缓存也就消失了。

二级缓存:它指的是mybatis中SqlSessionFactory对象的缓存。由同一个SqlSessionFactory对象创建的SqlSession共享其缓存。

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

使用配置文件开发使用步骤:

第一步:让mybatis框架支持二级缓存(在SqlMapConfig.xml中配置)
<settings>

 <!-- 开启二级缓存的支持 -->

 <setting name="cacheEnabled" value="true"/>

 </settings> 

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

第二步:让当前的映射文件支持二级缓存(在IUserDao.xml中配置)
<cache>标签表示当前这个 mapper 映射将使用二级缓存,区分的标准就看 mapper 的 namespace 值。

<?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">

<mapper namespace="com.itheima.dao.IUserDao">

<!-- 开启二级缓存的支持 -->

<cache></cache>

</mapper>
第三步:让当前的操作支持二级缓存(在select标签中配置)
<!-- 根据 id 查询 -->
<select id="findById" resultType="user" parameterType="int" useCache="true">
select * from user where id = #{uid} </select>

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

注意:针对每次查询都需要最新的数据 sql,要设置成 useCache=false,禁用二级缓存。

二级缓存存的是数据,不是对象,查找的时候会新创一个对象,把数据拿给他,这样前后两次就不是同一个对象了

一级缓存不用开启或者配置,自己就有的

6.mybatis注解开发

6.1.mybatis常用注解说明

@Insert:实现新增

@Update:实现更新

@Delete:实现删除

@Select:实现查询

@Result:实现结果集封装

@Results:可以与@Result 一起使用,封装多个结果集

@ResultMap:实现引用@Results 定义的封装

@One:实现一对一结果集封装

@Many:实现一对多结果集封装

@SelectProvider: 实现动态 SQL 映射

@CacheNamespace:实现注解二级缓存的使用

6.2.复杂关系映射的注解说明

  • @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 注解(一对一) 

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

@One 注解属性介绍:

select  指定用来多表查询的 sqlmapper

fetchType 会覆盖全局的配置参数 lazyLoadingEnabled。

使用格式:

@Result(column=" ",property="",one=@One(select=""))

  • @Many 注解(多对一)

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

注意:聚集元素用来处理“一对多”的关系。需要指定映射的 Java 实体类的属性,属性的 javaType (一般为 ArrayList)但是注解中可以不定义;

使用格式:

@Result(property="",column="",many=@Many(select=""))

6.3.使用mybatis注解实现多对一、一对一

需求:根据账户信息,查询对应的用户信息

6.3.1.编写用户实体类

public class User implements Serializable { 

  private Integer userId;

  private String userName;

  private Date userBirthday;

  private String userSex;

  private String userAddress;

  public Integer getUserId() {

   return userId;  }

  public void setUserId(Integer userId) {

   this.userId = userId;  }

  public String getUserName() {

   return userName;  }
public void setUserName(String userName) { this.userName = userName; } public Date getUserBirthday() { return userBirthday; } public void setUserBirthday(Date userBirthday) {
this.userBirthday = userBirthday; } public String getUserSex() { return userSex; } public void setUserSex(String userSex) { this.userSex = userSex; } public String getUserAddress() { return userAddress; } public void setUserAddress(String userAddress) {
this.userAddress = userAddress; } @Override public String toString() { return "User [userId=" + userId + ", userName=" + userName + ", userBirthday=" + userBirthday + ", userSex=" + userSex + ", userAddress=" + userAddress + "]"; }
}

6.3.2.编写账户的实体类

public class Account implements Serializable { 

  private Integer id;

  private Integer uid;

  private Double money;
//多对一关系映射:从表方应该包含一个主表方的对象引用 private User user; public User getUser() { return user; } public void setUser(User user) { this.user = user; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public Integer getUid() { return uid; } public void setUid(Integer uid) { this.uid = uid; } public Double getMoney() { return money; } public void setMoney(Double money) { this.money = money; } @Override public String toString() { return "Account [id=" + id + ", uid=" + uid + ", money=" + money + "]"; }
}

注意: 此处我们故意和数据库表的列名不一致。

6.3.3.添加账户的持久层接口并使用注解配置

public interface IAccountDao {
/**
* 查询所有账户,采用延迟加载的方式查询账户的所属用户
* @return
*/
@Select("select * from account") @Results(id="accountMap",value= { @Result(id=true,column="id",property="id"),
@Result(column="uid",property="uid"),
@Result(column="money",property="money"),
@Result(column="uid",property="user",one=@One(select="com.itheima.dao.IUserDao.findById",
fetchType=FetchType.LAZY)
)
})
List<Account> findAll();

一对一:(根据账户而言)

property对应要封装的user属性,用uid这个字段去查column=“uid”,指向select,select要找到实现功能的那个方法findbyId,写全限定类名(包名+类名+方法名)

one里边有select和fetchType

6.3.4.添加用户的持久层接口并使用注解配置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();

/**
* 根据 id 查询一个用户
* @param userId
* @return
*/
@Select("select * from user where id = #{uid} ")
@ResultMap("userMap")
User findById(Integer userId);
}

6.3.5.测试

6.4.使用mybatis注解实现多对多、一对多

需求:当查询用户信息的时候,也要查询出对应的账户信息

6.4.1.用户实体类

public class User implements Serializable { 

  private Integer userId;

  private String userName;

  private Date userBirthday;

  private String userSex;

  private String userAddress;   

 //一对多关系映射:主表方法应该包含一个从表方的集合引用
private List<Account> accounts; public List<Account> getAccounts() {
return accounts; } public void setAccounts(List<Account> accounts) {
this.accounts = accounts; }
public Integer getUserId() { return userId; } public void setUserId(Integer userId) { this.userId = userId; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public Date getUserBirthday() { return userBirthday; } public void setUserBirthday(Date userBirthday) {
this.userBirthday = userBirthday; } public String getUserSex() { return userSex; } public void setUserSex(String userSex) { this.userSex = userSex; } public String getUserAddress() { return userAddress; } public void setUserAddress(String userAddress) {
this.userAddress = userAddress; } @Override
public String toString() { return "User [userId=" + userId + ", userName=" + userName + ", userBirthday=" + userBirthday + ", userSex=" + userSex + ", userAddress=" + userAddress + "]"; }
}

6.4.2.编写用户的持久层接口并使用注解配置

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"),
@Result(column="id",property="accounts",many=@Many(select="com.itheima.dao.IAccountDao.findByUid",
fetchType=FetchType.LAZY)
)
})
List<User> findAll();
}

@Many: 相当于<collection>的配置 select 属性:代表将要执行的 sql 语句

fetchType 属性:代表加载方式,一般如果要延迟加载都设置为 LAZY 的值

6.4.3.编写账户的持久层接口并使用注解配置

public interface IAccountDao {

    /**
*根据用户 id 查询用户下的所有账户
*@param userId * @return
*/ @Select("select * from account where uid = #{uid} ") List<Account> findByUid(Integer userId);
}

6.4.4.测试

7.mybatis 基于注解的二级缓存

7.1.在 SqlMapConfig 中开启二级缓存支持

<!-- 配置二级缓存 -->
<settings>
<!-- 开启二级缓存的支持 -->
<setting name="cacheEnabled" value="true"/>
</settings>

7.2.在持久层接口中使用注解配置二级缓存

@CacheNamespace(blocking=true)
//mybatis 基于注解方式实现配置二级缓存
public interface IUserDao {......}

mybatis学习日记3的更多相关文章

  1. mybatis学习日记-day01

    Mybatis说明: MyBatis 使用简单的 XML或注解用于配置和原始映射,将接口和 Java 的POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的 ...

  2. MyBatis学习日记(一):拜见小主——MyBatis

    近日学习MyBatis,特将学习过程及一点心得记录于此. MyBatis为何物? MyBatis 是支持定制化SQL.存储过程以及高级映射的优秀的持久层框架.MyBatis 避免了几乎所有的 JDBC ...

  3. MyBatis学习日记(三):戏说MyBatis配置文件

    properties标签 properties标签可以用来加载别的配置文件,比如可以加载数据库的配置文件,jdbc.properties. 下面是jdbc.properties jdbc.driver ...

  4. MyBatis学习日记(二): MyBatis Say Hello

    首先在Eclipse中创建一个maven工程: 在maven工程下的pom.xml文件中添加MyBatis.MySQL.Junit依赖: <project xmlns="http:// ...

  5. Linux学习日记-使用EF6 Code First(四)

    一.在linux上使用EF 开发环境 VS2013+mono 3.10.0 +EF 6.1.0 先检测一下EF是不是6的 如果不是  请参阅 Linux学习日记-EF6的安装升级(三) 由于我的数据库 ...

  6. MyBatis学习总结(二)——使用MyBatis对表执行CRUD操作(转载)

    本文转载自:http://www.cnblogs.com/jpf-java/p/6013540.html 上一篇博文MyBatis学习总结(一)--MyBatis快速入门中我们讲了如何使用Mybati ...

  7. MyBatis学习总结(八)——Mybatis3.x与Spring4.x整合(转载)

      孤傲苍狼 只为成功找方法,不为失败找借口! MyBatis学习总结(八)--Mybatis3.x与Spring4.x整合 一.搭建开发环境 1.1.使用Maven创建Web项目 执行如下命令: m ...

  8. MyBatis学习总结(七)——Mybatis缓存(转载)

      孤傲苍狼 只为成功找方法,不为失败找借口! MyBatis学习总结(七)--Mybatis缓存 一.MyBatis缓存介绍 正如大多数持久层框架一样,MyBatis 同样提供了一级缓存和二级缓存的 ...

  9. (原创)mybatis学习二,spring和mybatis的融合

    mybatis学习一夯实基础 上文介绍了mybatis的相关知识,这一节主要来介绍mybaits和spring的融合 一,环境搭建 1,jar包下载,下载路径为jar包 2,将包导入到java工程中 ...

  10. (原创)mybatis学习一,夯实基础

    一,what?(是什么) MyBatis是一个支持普通SQL查询,存储过程和高级映射的优秀持久层框架.MyBatis消除了几乎所有的JDBC代码和参数的手工设置以及对结果集的检索封装.MyBatis可 ...

随机推荐

  1. 关于python统计一个列表中每个元素出现的频率

    第一种写法: a = ['h','h','e','a','a'] result = {} for i in a: if i not in result: result[i] = 1 else: res ...

  2. Docker使用Calico配置网络模式

    一.Calico介绍 Calico是一种容器之间互通的网络方案,在虚拟化平台中,比如OpenStack.Docker等都需要实现workloads之间互连,但同时也需要对容器做隔离控制,就像在Inte ...

  3. 社论 22.10.14 区间在线去重k小

    浅谈区间在线去重k小 关于讨论 https://www.luogu.com.cn/discuss/509205 本文将描述一种分块做法以及讨论中提出的各种 \(O(n \ \text{polylog} ...

  4. SpringCloud Alibaba(六) - Seata 分布式事务锁

    1.Seata 简介 1.1 Seata是什么 Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务.Seata 将为用户提供了 AT.TCC.SAGA 和 XA 事 ...

  5. Type Script 在流程设计器的落地实践

    流程设计器项目介绍 从事过BPM行业的大佬必然对流程建模工具非常熟悉,做为WFMC三大体系结构模型中的核心模块,它是工作流的能力模型,其他模块都围绕工作流定义来构建. 成熟的建模工具通过可视化的操作界 ...

  6. JavaEE Day07 HTML

    今日内容 Web概念概述 HTML 一.Web概念概述 1. JavaWeb:使用Java语言开发的基于互联网的项目 2.软件架构 C/S架构:Client/Server--- 客户端/服务器端(安卓 ...

  7. Mybatis04:延迟加载、一二级缓存、注解开发

    今日内容 mybatis中的延迟加载 延迟加载的概念 立即加载的概念 如果实现延迟加载 Mybatis中的缓存 什么是缓存 为什么使用缓存 什么数据可以使用缓存,什么样的数据不能使用缓存 Mybati ...

  8. 【Java SE进阶】Day02 Collection、Iterator、泛型

    一.Collection集合 1.概述 数组存元素,集合存对象(类型可以不一样) 2.框架分类 单列:Collection List ArrayList LinkedList Set HashSet ...

  9. 【每日一题】【排序sort重载】【工具类】2021年12月23日-31. 下一个排列

    实现获取 下一个排列 的函数,算法需要将给定数字序列重新排列成字典序中下一个更大的排列(即,组合出下一个更大的整数). 如果不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排列). 必须 ...

  10. 一篇文章教你实战Docker容器数据卷

    在上一篇中,咱们对Docker中的容器数据卷做了介绍.已经知道了容器数据卷是什么?能干什么用.那么本篇咱们就来实战容器数据卷,Docker容器数据卷案例主要做以下三个案例 1:宿主机(也就是Docke ...