在对应的四种表关系中:一对多,多对一,一对一,多对多
一对多,多对多:通常情况下我们都是采用延迟加载。
多对一,一对一:通常情况下我们都是采用立即加载。
延迟加载:
就是在需要用到数据时才进行加载,不需要用到数据时就不加载数据。延迟加载也称懒加载。
在实际的开发过程中很多时候我们并不需要总是在加载用户信息时就一定要加载他的账户信息。这就是我们所说的延迟加载。
在真正使用数据时才发起查询,不用的时候不查询。按需加载(懒加载)。
好处:
先从单表查询,需要时再从关联表去关联查询,大大提高数据库性能,因为查询单表要比关联查询多张表速度要快。
坏处:
因为只有当需要用到数据时,才会进行数据库查询,这样在大批量数据查询时,因为查询工作也要消耗时间,所以可能造成用户等待时间变长,造成用户体验下降。
查询账户信息同时查询用户信息。一对一实现延迟加载。
Account:
package com.keafmd.domain;
import java.io.Serializable;
/**
* Keafmd
*
* @ClassName: Account
* @Description:
* @author: 牛哄哄的柯南
* @date: 2021-02-10 21:43
*/
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 +
'}';
}
}
IAccountDao:
package com.keafmd.dao;
import com.keafmd.domain.Account;
import java.util.List;
/**
* Keafmd
*
* @ClassName: IAccountDao
* @Description:
* @author: 牛哄哄的柯南
* @date: 2021-02-10 21:46
*/
public interface IAccountDao {
/**
* 查询所有账户,同时还要获取当前账户的所属用户信息
* @return
*/
List<Account> findAll();
/**
* 根据用户id查询账户信息
* @return
*/
List<Account> findAccountByUid(Integer uid);
}
IAccountDao.xml:
<mapper namespace="com.keafmd.dao.IAccountDao">
<resultMap id="accountUserMap" type="account">
<id property="id" column="id">id>
<result property="uid" column="uid">result>
<result property="money" column="money">result>
<association property="user" column="uid" javaType="user" select="com.keafmd.dao.IUserDao.findById">
association>
resultMap>
<select id="findAll" resultMap="accountUserMap">
select * from account
select>
<select id="findAccountByUid" resultType="account">
select * from account where uid = #{uid}
select>
mapper>
IUserDao:
package com.keafmd.dao;
import com.keafmd.domain.User;
import java.util.List;
/**
* Keafmd
*
* @ClassName: IUserDao
* @Description: 用户的持久层接口
* @author: 牛哄哄的柯南
* @date: 2021-02-06 19:29
*/
public interface IUserDao {
/**
* 查询所有用户,同时获取到用户下所有账户的信息
* @return
*/
List<User> findAll();
/**
* 根据id查新用户信息
* @param id
* @return
*/
User findById(Integer id);
}
IUserDao.xml:
<mapper namespace="com.keafmd.dao.IUserDao">
<select id="findById" parameterType="Integer" resultType="user">
select * from user where id = #{id}
select>
mapper>
在 Mybatis 的配置文件 SqlMapConfig.xml 文件中添加延迟加载的配置。
<settings>
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>
settings>
AccountTest:
package com.keafmd.test;
import com.keafmd.dao.IAccountDao;
import com.keafmd.domain.Account;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.InputStream;
import java.util.List;
/**
* Keafmd
*
* @ClassName: MybatisTest
* @Description: 测试类
* @author: 牛哄哄的柯南
* @date: 2021-02-08 15:24
*/
public class AccountTest {
private InputStream in;
private SqlSession sqlsession;
private IAccountDao accountDao;
@Before // 用于在测试方法执行前执行
public void init()throws Exception{
//1.读取配置文件,生成字节输入流
in = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.创建SqlSessionFactory工厂
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(in);
//3.使用工厂生产SqlSession对象
sqlsession = factory.openSession(); //里面写个true,下面每次就不用了写 sqlsession.commit(); 了
//4.使用SqlSession创建Dao接口的代理对象
accountDao = sqlsession.getMapper(IAccountDao.class);
}
@After // 用于在测试方法执行后执行
public void destory() throws Exception{
//提交事务
sqlsession.commit();
//6.释放资源
sqlsession.close();
in.close();
}
/**
* 查询所有 一对一实现延迟加载测试
* @throws Exception
*/
@Test
public void testFindAll() {
List<Account> accounts = accountDao.findAll();
for (Account account : accounts) {
System.out.println("------------每个account的信息-------");
System.out.println(account);
System.out.println(account.getUser());
}
}
}
运行结果:
2021-02-14 16:15:59,771 620 [ main] DEBUG ansaction.jdbc.JdbcTransaction - Opening JDBC Connection
2021-02-14 16:16:00,072 921 [ main] DEBUG source.pooled.PooledDataSource - Created connection 1783047508.
2021-02-14 16:16:00,072 921 [ main] DEBUG ansaction.jdbc.JdbcTransaction - Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@6a472554]
2021-02-14 16:16:00,076 925 [ main] DEBUG keafmd.dao.IAccountDao.findAll - ==> Preparing: select * from account
2021-02-14 16:16:00,099 948 [ main] DEBUG keafmd.dao.IAccountDao.findAll - ==> Parameters:
2021-02-14 16:16:00,156 1005 [ main] DEBUG keafmd.dao.IAccountDao.findAll - <== Total: 3
------------每个account的信息-------
2021-02-14 16:16:00,156 1005 [ main] DEBUG m.keafmd.dao.IUserDao.findById - ==> Preparing: select * from user where id = ?
2021-02-14 16:16:00,156 1005 [ main] DEBUG m.keafmd.dao.IUserDao.findById - ==> Parameters: 41(Integer)
2021-02-14 16:16:00,159 1008 [ main] DEBUG m.keafmd.dao.IUserDao.findById - <== Total: 1
Account{
id=1, uid=41, money=1000.0}
User{
id=41, username='老王', sex='男', address='北京', birthday=Tue Feb 27 17:47:08 CST 2018}
------------每个account的信息-------
2021-02-14 16:16:00,160 1009 [ main] DEBUG m.keafmd.dao.IUserDao.findById - ==> Preparing: select * from user where id = ?
2021-02-14 16:16:00,160 1009 [ main] DEBUG m.keafmd.dao.IUserDao.findById - ==> Parameters: 45(Integer)
2021-02-14 16:16:00,161 1010 [ main] DEBUG m.keafmd.dao.IUserDao.findById - <== Total: 1
Account{
id=2, uid=45, money=1000.0}
User{
id=45, username='新一', sex='男', address='北京', birthday=Sun Mar 04 12:04:06 CST 2018}
------------每个account的信息-------
Account{
id=3, uid=41, money=2000.0}
User{
id=41, username='老王', sex='男', address='北京', birthday=Tue Feb 27 17:47:08 CST 2018}
2021-02-14 16:16:00,161 1010 [ main] DEBUG ansaction.jdbc.JdbcTransaction - Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@6a472554]
2021-02-14 16:16:00,161 1010 [ main] DEBUG ansaction.jdbc.JdbcTransaction - Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@6a472554]
2021-02-14 16:16:00,162 1011 [ main] DEBUG source.pooled.PooledDataSource - Returned connection 1783047508 to pool.
Process finished with exit code 0
当我们把测试代码改写成下面这样,只查账户信息不查用户信息。
/**
* 查询所有 一对一实现延迟加载测试
* @throws Exception
*/
@Test
public void testFindAll() {
List<Account> accounts = accountDao.findAll();
/*for (Account account : accounts) {
System.out.println("------------每个account的信息-------");
System.out.println(account);
System.out.println(account.getUser());
}*/
}
运行结果:
2021-02-14 16:17:27,554 185 [ main] DEBUG ansaction.jdbc.JdbcTransaction - Opening JDBC Connection
2021-02-14 16:17:27,811 442 [ main] DEBUG source.pooled.PooledDataSource - Created connection 1641313620.
2021-02-14 16:17:27,811 442 [ main] DEBUG ansaction.jdbc.JdbcTransaction - Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@61d47554]
2021-02-14 16:17:27,815 446 [ main] DEBUG keafmd.dao.IAccountDao.findAll - ==> Preparing: select * from account
2021-02-14 16:17:27,845 476 [ main] DEBUG keafmd.dao.IAccountDao.findAll - ==> Parameters:
2021-02-14 16:17:27,901 532 [ main] DEBUG keafmd.dao.IAccountDao.findAll - <== Total: 3
2021-02-14 16:17:27,901 532 [ main] DEBUG ansaction.jdbc.JdbcTransaction - Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@61d47554]
2021-02-14 16:17:27,902 533 [ main] DEBUG ansaction.jdbc.JdbcTransaction - Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@61d47554]
2021-02-14 16:17:27,902 533 [ main] DEBUG source.pooled.PooledDataSource - Returned connection 1641313620 to pool.
Process finished with exit code 0
对比上面的测试输出可以很明显的看出来:因为本次只是将 Account对象查询出来放入 List 集合中,并没有涉及到 User对象,所以就没有发出 SQL 语句查询账户所关联的 User 对象的查询。
我们也可以在一对多关系配置的
结点中配置延迟加载策略。
结点中也有 select 属性,column 属性。
完成加载用户对象时,查询该用户所拥有的账户信息。
User:
package com.keafmd.domain;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
/**
* Keafmd
*
* @ClassName: User
* @Description:
* @author: 牛哄哄的柯南
* @date: 2021-02-08 15:16
*/
public class User implements Serializable {
private Integer id;
private String username;
private String sex;
private String address;
private Date birthday;
//一对多关系映射,主表实体应该包含从表实体的集合引用
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 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;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", sex='" + sex + '\'' +
", address='" + address + '\'' +
", birthday=" + birthday +
'}';
}
}
IUserDao:
package com.keafmd.dao;
import com.keafmd.domain.User;
import java.util.List;
/**
* Keafmd
*
* @ClassName: IUserDao
* @Description: 用户的持久层接口
* @author: 牛哄哄的柯南
* @date: 2021-02-06 19:29
*/
public interface IUserDao {
/**
* 查询所有用户,同时获取到用户下所有账户的信息
* @return
*/
List<User> findAll();
/**
* 根据id查新用户信息
* @param id
* @return
*/
User findById(Integer id);
}
IUserDao.xml:
<mapper namespace="com.keafmd.dao.IUserDao">
<resultMap id="userAccountMap" type="user">
<id property="id" column="id">id>
<result property="username" column="username">result>
<result property="address" column="address">result>
<result property="sex" column="sex">result>
<result property="birthday" column="birthday">result>
<collection property="accounts" ofType="account" select="com.keafmd.dao.IAccountDao.findAccountByUid" column="id">collection>
resultMap>
<select id="findAll" resultMap="userAccountMap">
select * from user
select>
<select id="findById" parameterType="Integer" resultType="user">
select * from user where id = #{id}
select>
mapper>
IAccountDao:
package com.keafmd.dao;
import com.keafmd.domain.Account;
import java.util.List;
/**
* Keafmd
*
* @ClassName: IAccountDao
* @Description:
* @author: 牛哄哄的柯南
* @date: 2021-02-10 21:46
*/
public interface IAccountDao {
/**
* 查询所有账户,同时还要获取当前账户的所属用户信息
* @return
*/
List<Account> findAll();
/**
* 根据用户id查询账户信息
* @return
*/
List<Account> findAccountByUid(Integer uid);
}
IAccountDao.xml:
<mapper namespace="com.keafmd.dao.IAccountDao">
<select id="findAccountByUid" resultType="account">
select * from account where uid = #{uid}
select>
mapper>
package com.keafmd.test;
import com.keafmd.dao.IUserDao;
import com.keafmd.domain.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.InputStream;
import java.util.List;
/**
* Keafmd
*
* @ClassName: MybatisTest
* @Description: 测试类,测试crud操作
* @author: 牛哄哄的柯南
* @date: 2021-02-08 15:24
*/
public class UserTest {
private InputStream in;
private SqlSession sqlsession;
private IUserDao userDao;
@Before // 用于在测试方法执行前执行
public void init()throws Exception{
//1.读取配置文件,生成字节输入流
in = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.创建SqlSessionFactory工厂
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(in);
//3.使用工厂生产SqlSession对象
sqlsession = factory.openSession(); //里面写个true,下面每次就不用了写 sqlsession.commit(); 了
//4.使用SqlSession创建Dao接口的代理对象
userDao = sqlsession.getMapper(IUserDao.class);
}
@After // 用于在测试方法执行后执行
public void destory() throws Exception{
//提交事务
sqlsession.commit();
//6.释放资源
sqlsession.close();
in.close();
}
/**
* 查询所有 ,一对多实现延迟加载
* @throws Exception
*/
@Test
public void testFindAll() {
List<User> users = userDao.findAll();
for (User user : users) {
System.out.println("--------每个用户的信息---------");
System.out.println(user);
System.out.println(user.getAccounts());
}
}
}
运行结果:
2021-02-14 16:29:07,023 208 [ main] DEBUG ansaction.jdbc.JdbcTransaction - Opening JDBC Connection
2021-02-14 16:29:07,272 457 [ main] DEBUG source.pooled.PooledDataSource - Created connection 1641313620.
2021-02-14 16:29:07,272 457 [ main] DEBUG ansaction.jdbc.JdbcTransaction - Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@61d47554]
2021-02-14 16:29:07,276 461 [ main] DEBUG om.keafmd.dao.IUserDao.findAll - ==> Preparing: select * from user
2021-02-14 16:29:07,303 488 [ main] DEBUG om.keafmd.dao.IUserDao.findAll - ==> Parameters:
2021-02-14 16:29:07,371 556 [ main] DEBUG om.keafmd.dao.IUserDao.findAll - <== Total: 9
--------每个用户的信息---------
2021-02-14 16:29:07,372 557 [ main] DEBUG o.IAccountDao.findAccountByUid - ==> Preparing: select * from account where uid = ?
2021-02-14 16:29:07,372 557 [ main] DEBUG o.IAccountDao.findAccountByUid - ==> Parameters: 41(Integer)
2021-02-14 16:29:07,375 560 [ main] DEBUG o.IAccountDao.findAccountByUid - <== Total: 2
User{
id=41, username='老王', sex='男', address='北京', birthday=Tue Feb 27 17:47:08 CST 2018}
[Account{
id=1, uid=41, money=1000.0}, Account{
id=3, uid=41, money=2000.0}]
--------每个用户的信息---------
2021-02-14 16:29:07,376 561 [ main] DEBUG o.IAccountDao.findAccountByUid - ==> Preparing: select * from account where uid = ?
2021-02-14 16:29:07,376 561 [ main] DEBUG o.IAccountDao.findAccountByUid - ==> Parameters: 42(Integer)
2021-02-14 16:29:07,377 562 [ main] DEBUG o.IAccountDao.findAccountByUid - <== Total: 0
User{
id=42, username='update', sex='男', address='XXXXXXX', birthday=Mon Feb 08 19:37:31 CST 2021}
[]
--------每个用户的信息---------
2021-02-14 16:29:07,377 562 [ main] DEBUG o.IAccountDao.findAccountByUid - ==> Preparing: select * from account where uid = ?
2021-02-14 16:29:07,377 562 [ main] DEBUG o.IAccountDao.findAccountByUid - ==> Parameters: 43(Integer)
2021-02-14 16:29:07,378 563 [ main] DEBUG o.IAccountDao.findAccountByUid - <== Total: 0
User{
id=43, username='小二王', sex='女', address='北京', birthday=Sun Mar 04 11:34:34 CST 2018}
[]
--------每个用户的信息---------
2021-02-14 16:29:07,379 564 [ main] DEBUG o.IAccountDao.findAccountByUid - ==> Preparing: select * from account where uid = ?
2021-02-14 16:29:07,383 568 [ main] DEBUG o.IAccountDao.findAccountByUid - ==> Parameters: 45(Integer)
2021-02-14 16:29:07,385 570 [ main] DEBUG o.IAccountDao.findAccountByUid - <== Total: 1
User{
id=45, username='新一', sex='男', address='北京', birthday=Sun Mar 04 12:04:06 CST 2018}
[Account{
id=2, uid=45, money=1000.0}]
--------每个用户的信息---------
2021-02-14 16:29:07,386 571 [ main] DEBUG o.IAccountDao.findAccountByUid - ==> Preparing: select * from account where uid = ?
2021-02-14 16:29:07,386 571 [ main] DEBUG o.IAccountDao.findAccountByUid - ==> Parameters: 50(Integer)
2021-02-14 16:29:07,387 572 [ main] DEBUG o.IAccountDao.findAccountByUid - <== Total: 0
User{
id=50, username='Keafmd', sex='男', address='XXXXXXX', birthday=Mon Feb 08 15:44:01 CST 2021}
[]
--------每个用户的信息---------
2021-02-14 16:29:07,387 572 [ main] DEBUG o.IAccountDao.findAccountByUid - ==> Preparing: select * from account where uid = ?
2021-02-14 16:29:07,387 572 [ main] DEBUG o.IAccountDao.findAccountByUid - ==> Parameters: 51(Integer)
2021-02-14 16:29:07,389 574 [ main] DEBUG o.IAccountDao.findAccountByUid - <== Total: 0
User{
id=51, username='update DAO', sex='男', address='XXXXXXX', birthday=Tue Feb 09 11:31:38 CST 2021}
[]
--------每个用户的信息---------
2021-02-14 16:29:07,389 574 [ main] DEBUG o.IAccountDao.findAccountByUid - ==> Preparing: select * from account where uid = ?
2021-02-14 16:29:07,390 575 [ main] DEBUG o.IAccountDao.findAccountByUid - ==> Parameters: 52(Integer)
2021-02-14 16:29:07,391 576 [ main] DEBUG o.IAccountDao.findAccountByUid - <== Total: 0
User{
id=52, username='Keafmd DAO', sex='男', address='XXXXXXX', birthday=Tue Feb 09 11:29:41 CST 2021}
[]
--------每个用户的信息---------
2021-02-14 16:29:07,391 576 [ main] DEBUG o.IAccountDao.findAccountByUid - ==> Preparing: select * from account where uid = ?
2021-02-14 16:29:07,391 576 [ main] DEBUG o.IAccountDao.findAccountByUid - ==> Parameters: 53(Integer)
2021-02-14 16:29:07,392 577 [ main] DEBUG o.IAccountDao.findAccountByUid - <== Total: 0
User{
id=53, username='Keafmd laset insertid 1', sex='男', address='XXXXXXX', birthday=Fri Feb 12 20:53:46 CST 2021}
[]
--------每个用户的信息---------
2021-02-14 16:29:07,392 577 [ main] DEBUG o.IAccountDao.findAccountByUid - ==> Preparing: select * from account where uid = ?
2021-02-14 16:29:07,392 577 [ main] DEBUG o.IAccountDao.findAccountByUid - ==> Parameters: 54(Integer)
2021-02-14 16:29:07,392 577 [ main] DEBUG o.IAccountDao.findAccountByUid - <== Total: 0
User{
id=54, username='Keafmd laset insertid 2 auto', sex='男', address='XXXXXXX', birthday=Fri Feb 12 21:02:12 CST 2021}
[]
2021-02-14 16:29:07,392 577 [ main] DEBUG ansaction.jdbc.JdbcTransaction - Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@61d47554]
2021-02-14 16:29:07,393 578 [ main] DEBUG ansaction.jdbc.JdbcTransaction - Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@61d47554]
2021-02-14 16:29:07,393 578 [ main] DEBUG source.pooled.PooledDataSource - Returned connection 1641313620 to pool.
Process finished with exit code 0
同理我们直接注释掉输出语句就不会进行账户信息的查询了。
/**
* 查询所有 ,一对多实现延迟加载
* @throws Exception
*/
@Test
public void testFindAll() {
List<User> users = userDao.findAll();
/*for (User user : users) {
System.out.println("--------每个用户的信息---------");
System.out.println(user);
System.out.println(user.getAccounts());
}*/
}
运行结果:
2021-02-14 16:30:33,239 191 [ main] DEBUG ansaction.jdbc.JdbcTransaction - Opening JDBC Connection
2021-02-14 16:30:33,493 445 [ main] DEBUG source.pooled.PooledDataSource - Created connection 1641313620.
2021-02-14 16:30:33,494 446 [ main] DEBUG ansaction.jdbc.JdbcTransaction - Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@61d47554]
2021-02-14 16:30:33,498 450 [ main] DEBUG om.keafmd.dao.IUserDao.findAll - ==> Preparing: select * from user
2021-02-14 16:30:33,521 473 [ main] DEBUG om.keafmd.dao.IUserDao.findAll - ==> Parameters:
2021-02-14 16:30:33,583 535 [ main] DEBUG om.keafmd.dao.IUserDao.findAll - <== Total: 9
2021-02-14 16:30:33,584 536 [ main] DEBUG ansaction.jdbc.JdbcTransaction - Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@61d47554]
2021-02-14 16:30:33,584 536 [ main] DEBUG ansaction.jdbc.JdbcTransaction - Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@61d47554]
2021-02-14 16:30:33,585 537 [ main] DEBUG source.pooled.PooledDataSource - Returned connection 1641313620 to pool.
Process finished with exit code 0
我们这时就可以发现并没有加载 Account 账户信息,没有执行查询账户信息的sql语句。
以上就是Mybatis延迟加载策略的全部内容。
看完如果对你有帮助,感谢点赞支持!
如果你是电脑端的话,看到右下角的 “一键三连” 了吗,没错点它[哈哈]
加油!
共同努力!
Keafmd