文章目录
MyBatis
01-表关系回顾-[★★]
一对一
主键是外键:从表的主键和主表的主键形成主外键关系
外键唯一:从表添加一列作为外键列,引用主表的主键列的值,外键列添加唯一约束。
一对多
从表(多方)添加一列作为外键列引用主表(1方)的主键列的值
多对多
创建一张中间表,至少有两个字段:分别作为外键引用各种一方的主键,这两个字段一起作为联合主键:共同确定记录的唯一性。
用户和账号:
从用户角度:一个用户有多个账号:1对多关系
从账号角度:一个账号只属于1个用户:1对1关系
用户和角色:多对多关系
1个用户可以拥有多个角色
1个角色可以分配给多个用户
02-多表查询之1对1关系-环境搭建与类设计-[★★]
案例需求
-
表关系介绍:
-
一个用户,有多个银行账户。(用户与账户:一对多)
-
一个账户,只能对应一个人。(账户与用户:一对一)
-
-
实现查询一个账户同时关联查询所属用户信息,实现1对1关联查询
环境搭建
- 准备账号表
DROP TABLE IF EXISTS `USER`;
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(32) NOT NULL COMMENT '用户名称',
`birthday` datetime DEFAULT NULL COMMENT '生日',
`sex` char(1) DEFAULT NULL COMMENT '性别',
`address` varchar(256) DEFAULT NULL COMMENT '地址',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=56 DEFAULT CHARSET=utf8;
insert into `user`(`id`,`username`,`birthday`,`sex`,`address`) values (41,'老王','2018-02-27 17:47:08','男','中山'),(42,'小二王','2018-03-02 15:09:37','女','中山金燕龙'),(45,'中山青软','2018-03-04 12:04:06','男','中山金燕龙'),(46,'老王','2018-03-07 17:37:26','男','中山');
DROP TABLE IF EXISTS account;
CREATE TABLE account (
accountId int(11) NOT NULL COMMENT '编号',
UID int(11) default NULL COMMENT '用户编号',
MONEY double default NULL COMMENT '金额',
PRIMARY KEY (accountId),
KEY FK_Reference_8 (UID),
CONSTRAINT FK_Reference_8 FOREIGN KEY (UID) REFERENCES user (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
insert into account(accountId,UID,MONEY) values (1,46,1000),(2,45,1000),(3,46,2000);
- 复制项目创建新项目
- 设计Account类
- User类已有,不用重新设计
- Account类:一个账号对应一个用户
package com.pkx.entity;
/**
* 账户实体类
* 查询账号信息同时查询该账号对应的用户信息
*/
public class Account {
private int accountId;
private int uid;
private double money;
// 账号对应的用户:1对1关系
private User user;
public Account(int accountId, int uid, double money) {
this.accountId = accountId;
this.uid = uid;
this.money = money;
}
public Account() {
}
public int getAccountId() {
return accountId;
}
public void setAccountId(int accountId) {
this.accountId = accountId;
}
public int getUid() {
return uid;
}
public void setUid(int uid) {
this.uid = uid;
}
public double getMoney() {
return money;
}
public void setMoney(double money) {
this.money = money;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
@Override
public String toString() {
return "Account{" +
"accountId=" + accountId +
", uid=" + uid +
", money=" + money +
", user=" + user +
'}';
}
}
- 如何设计账号类实现账号与用户的一对一关联?
在账号类中添加一个成员变量关联对应的用户:private User user;
03-多表查询之1对1关系-代码实现-[★★★★★]
association标签的作用:用来配置一对一关联查询
association标签常用属性
property:要映射的属性名
javaType:映射属性名的类型
-
需求:实现1对1的多表查询:实现查询账户同时查询所属用户信息。
-
实现步骤:
1.在lAccountDao接口中定义查询方法findAll0,多表查询返回List,每个Account包含2个表信息
2.在lAccountDao.xml映射文件配置对应方法与sql语句
3.配置返回数据类型resultMap,配置1对1关系缺射【重点】
4.测类 -
IAccountDao代码
/**
* 数据访问层接口:对账号表进行增删改查操作
*/
public interface IAccountDao {
/***
* 查询所有账号:关联查询每个账号的用户信息
*/
List<Account> findAll();
}
- IAccountDao.xml 配置文件代码
<?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.pkx.dao.IAccountDao">
<!--配置数据表字段与实体类属性的对应关系-->
<resultMap id="accountResultMap" type="account">
<!--封装Account表数据-->
<id column="accountId" property="accountId"></id>
<result column="uid" property="uid"></result>
<result column="money" property="money"></result>
<!--封装User表数据
association标签的作用:用来封装一对一关联查询的数据
property属性:关联实体类的属性名
javaType属性:要映射属性的类型
-->
<association property="user"
javaType="User">
<id column="id" property="id"></id>
<result column="username" property="username"></result>
<result column="birthday" property="birthday"></result>
<result column="sex" property="sex"></result>
<result column="address" property="address"></result>
</association>
</resultMap>
<!--查询所有账号:关联查询每个账号的用户信息-->
<select id="findAll" resultMap="accountResultMap">
select * from account a inner join user u on a.`UID` = u.id
</select>
</mapper>
- 测试类代码
public class TestAccountDao {
private static SqlSessionFactory sqlSessionFactory = null;
private SqlSession sqlSession = null;
// 该方法在所有测试方法执行之前执行1次
@BeforeClass
public static void init() throws Exception{
// 1. 获取字节输入流:关联mybatis主配置文件
InputStream in = Resources.getResourceAsStream("sqlMapConfig.xml");
// 2. 创建SqlSessionFactoryBuilder对象
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
// 3. 根据字节输入流获取SqlSessionFactory对象
sqlSessionFactory = builder.build(in);
}
// 该方法会在每个测试方法执行之前执行1次
@Before
public void before(){
// 4. 获取SqlSession对象:等价连接对象
// true:事务自动提交,false:不自动提交,默认值
sqlSession = sqlSessionFactory.openSession();
}
// 在每个测试方法执行之后执行1次
@After
public void after(){
// 7. 关闭连接释放资源
sqlSession.close();
}
// 查询所有账号:关联查询用户信息
@Test
public void testFindAll(){
// 1. 获得接口实现类对象
IAccountDao accountDao = sqlSession.getMapper(IAccountDao.class);
// 2. 查询所有账号
List<Account> accountList = accountDao.findAll();
// 3. 遍历输出所有账号
for (Account account : accountList) {
System.out.println(account);
}
}
}
04-多表查询之1对多关系-代码实现-[★★★★★]
- collection标签的作用:用来配置一对多关联查询
- collection标签常用属性
property:要映射的属性名称
javaType:要映射的属性类型
ofType:集合中存储对象的类型
-
需求:掌握1对多关系多表查询:实现查询用户信息同时查询所属账号信息。
-
实现步骤
1.设计POJO的User类,增加账户的成是List
2.在IUserDao接口中增加findAll0查询多表
3.在UserDao.xml映射文件配置对应方法,配置1对多关系映射【重点】
4.测试类 -
User类代码
-
修改 User类,添加成员变量:accountList
/**用户实体类对象 */
public class User {
private Integer id;
private String username;
private Date birthday;
private String sex;
private String address;
// 用户的账号列表:
// 用户与账号的关系:1对多
private List<Account> accountList;
- IUserDao接口代码
/**
数据访问层接口:对用户进行增删改查操作
*/
public interface IUserDao {
/**
* 查询所有用户:关联查询每个用户的所有账号信息
*/
List<User> findAll();
}
- IUserDao.xml 配置文件代码
<?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.pkx.dao.IUserDao">
<!--配置一对多的关联查询的映射-->
<resultMap id="userMap" type="user">
<!--封装user表数据-->
<id column="id" property="id"></id>
<result column="username" property="username"></result>
<result column="birthday" property="birthday"></result>
<result column="sex" property="sex"></result>
<result column="address" property="address"></result>
<!--collection标签:用来映射一对多关联查询的数据
property:要映射的属性名
javaType:要映射属性的类型
ofType:集合存储的数据类型
-->
<collection property="accountList"
javaType="list"
ofType="account">
<!--封装account表的数据-->
<id column="accountId" property="accountId"></id>
<result column="uid" property="uid"></result>
<result column="money" property="money"></result>
</collection>
</resultMap>
<!--目标:查询所有用户:关联每个用户的所有账号信息 -->
<select id="findAll" resultMap="userMap">
select *
from user u
left join account a
on a.uid = u.id
</select>
</mapper>
- 测试代码
// 查询所有用户:关联用户的所有账号
@Test
public void testFindAll(){
// 1. 获得接口代理对象
IUserDao userDao = sqlSession.getMapper(IUserDao.class);
// 2. 查询所有用户
List<User> userList = userDao.findAll();
// 3. 遍历所有用户
for (User user : userList) {
System.out.println(user);
}
}
05-多表查询之多对多关系-环境搭建与类设计-[★★]
在多对多关系的实体类中,各自添加一个类型为List的成员变量:存储对方类型的对象。
- 需求:掌握多对多关系关联表查询
- 用户与角色, 多对多关系
- 描述
- 一个用户,有多个角色
- 一个角色,有多个用户
- 实现用户与角色多对多关系多表查询
- 环境搭建
- 数据表
CREATE TABLE role (
id int(11) NOT NULL COMMENT '编号',
role_name varchar(30) default NULL COMMENT '角色名称',
role_desc varchar(60) default NULL COMMENT '角色描述',
PRIMARY KEY (ID)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
insert into role(id,role_name,role_desc) values (1,'院长','管理整个学院'),(2,'总裁','管理整个公司'),(3,'校长','管理整个学校');
DROP TABLE IF EXISTS user_role;
CREATE TABLE user_role (
uid int(11) NOT NULL COMMENT '用户编号',
rid int(11) NOT NULL COMMENT '角色编号',
PRIMARY KEY (uid,rid),
KEY FK_Reference_10 (rid),
CONSTRAINT FK_Reference_10 FOREIGN KEY (rid) REFERENCES role (id),
CONSTRAINT FK_Reference_9 FOREIGN KEY (uid) REFERENCES user (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
insert into user_role(uid,rid) values (41,1),(45,1),(41,2);
- 设计Role角色类
/**
* 角色实体类:用来封装角色表的数据
*/
public class Role {
private int id;
private String role_name;
private String role_desc;
// 用来封装角色对应的所有用户:1对多
private List<User> userList;
public Role(int id, String role_name, String role_desc) {
this.id = id;
this.role_name = role_name;
this.role_desc = role_desc;
}
public Role() {
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getRole_name() {
return role_name;
}
public void setRole_name(String role_name) {
this.role_name = role_name;
}
public String getRole_desc() {
return role_desc;
}
public void setRole_desc(String role_desc) {
this.role_desc = role_desc;
}
public List<User> getUserList() {
return userList;
}
public void setUserList(List<User> userList) {
this.userList = userList;
}
@Override
public String toString() {
return "Role{" +
"id=" + id +
", role_name='" + role_name + '\'' +
", role_desc='" + role_desc + '\'' +
", userList=" + userList +
'}';
}
}
- 设计User类
/**用户实体类对象 */
public class User {
private Integer id;
private String username;
private Date birthday;
private String sex;
private String address;
// 用来封装用户对应的角色信息:1个用户可以拥有多个角色
private List<Role> roleList;
public User() {
}
public User(Integer id, String username, Date birthday, String sex, String address) {
this.id = id;
this.username = username;
this.birthday = birthday;
this.sex = sex;
this.address = address;
}
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;
}
public List<Role> getRoleList() {
return roleList;
}
public void setRoleList(List<Role> roleList) {
this.roleList = roleList;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", birthday=" + birthday +
", sex='" + sex + '\'' +
", address='" + address + '\'' +
", roleList=" + roleList +
'}';
}
}
06-多表查询之多对多关系-用户与角色1对多关系配置-[★★★★★]
- 需求:实现用户与角色1对多关系映射配置
- 实现步骤:
1.IUserDao接口中增加findAll()方法
2.IUserDao.xml映射配置对应方法,重点配置1对多关系映射
3.测试类 - IUserDao接口代码
public interface IUserDao {
/**
* 查询所有用户:关联查询每个用户的所有账号信息
*/
List<User> findAll();
}
- IUserDao.xml 配置文件代码
<?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.pkx.dao.IUserDao">
<!--设置实体类属性和数据表字段的关系-->
<resultMap id="userResultMap" type="user">
<!--封装User表数据-->
<id column="id" property="id"></id>
<result column="username" property="username"></result>
<result column="birthday" property="birthday"></result>
<result column="sex" property="sex"></result>
<result column="address" property="address"></result>
<!--封装Role表数据-->
<!--1对多数据封装:一个用户对应多个角色-->
<collection property="roleList" javaType="list" ofType="role">
<id column="rid" property="id"></id>
<result column="roleName" property="roleName"></result>
<result column="roleDesc" property="roleDesc"></result>
</collection>
</resultMap>
<!--查询所有用户:关联查询每个用户的所有账号信息-->
<select id="findAll" resultMap="userResultMap">
select r.id rid, r.`role_name` roleName, r.`role_desc` roleDesc ,u.*
from user u
inner join user_role ur
on u.id = ur.`uid`
inner join role r
on r.`id` = ur.`rid`
</select>
</mapper>
- 测试类代码
// 查询所有用户:关联查询角色信息
@Test
public void testFindAll(){
// 1. 获得接口实现类对象
IUserDao userDao = sqlSession.getMapper(IUserDao.class);
// 2. 查询所有用户
List<User> userList = userDao.findAll();
// 3. 遍历输出所有用户
for (User user : userList) {
System.out.println(user);
}
07-多表查询之多对多关系-角色与用户1对多关系配置-[★★★★★]
-
需求:实现角色与用户1对多关系映射配置
-
实现步骤:
1.IRoleDao接口中增加findAll()方法
2.IRoleDao.xml映射配置对应方法,重点配置1对多关系映射
3.测试类 -
IRoleDao接口代码
public interface IRoleDao {
// 查询所有角色:关联查询角色对应的所有用户信息
List<Role> findAll();
}
- IRoleDao.xml 配置文件代码
<?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.pkx.dao.IRoleDao">
<resultMap id="roleMap" type="role">
<!--封装role表数据-->
<id column="rid" property="id"></id>
<result column="roleName" property="roleName"></result>
<result column="roleDesc" property="roleDesc"></result>
<!--封装user表数据
1个角色对应多个用户:1对多关系,使用collection标签映射
-->
<collection property="userList" javaType="list" ofType="user">
<id column="id" property="id"></id>
<result column="username" property="username"></result>
<result column="birthday" property="birthday"></result>
<result column="sex" property="sex"></result>
<result column="address" property="address"></result>
</collection>
</resultMap>
<!-- 查询所有角色:关联查询角色对应的所有用户信息 -->
<select id="findAll" resultMap="roleMap">
select r.id rid,r.role_name roleName , r.role_desc roleDesc ,u.*
from role r
left join user_role ur
on r.id = ur.rid
left join user u
on u.id = ur.uid;
</select>
</mapper>
- 测试类代码
// 查询所有用户:关联查询角色信息
@Test
public void testFindAll(){
// 1. 获得接口实现类对象
IRoleDao roleDao = sqlSession.getMapper(IRoleDao.class);
// 2. 查询所有角色
List<Role> roleList = roleDao.findAll();
// 3. 遍历输出所有角色
for (Role role : roleList) {
System.out.println(role);
}
}
08-Mybatis延迟加载介绍-[★★]
- 目标:理解什么是及时加载,什么是延时加载
延迟加载介绍
-
延迟加载:就是在需要用到数据时才进行加载,不需要用到数据时就不加载数据。延迟加载也称懒加载.
-
延迟加载优点:先从单表查询,需要时再从关联表去关联查询,大大提高数据库性能,因为查询单表要比关联查询多张表速度要快。
-
延迟加载缺点:因为只有当需要用到数据时,才会进行数据库查询,这样在大批量数据查询时,因为查询也要消耗时间,所以可能造成用户等待时间变长,造成用户体验下降。
-
小结
- 什么是延迟加载:需要使用到数据时才执行SQL语句加载数据
- 什么是及时加载:立即加载表的数据