1.表与表之间的关系及其举例

表之间的关系有4种:一对多、多对一、一对一、多对多。
举例:
  (1)用户和订单就是一对多

    一个用户可以下多个订单
  (2)订单和用户就是多对一
    多个订单属于同一个用户

  (3)人和身份证号就是一对一
    一个人只能有一个身份证号
    一个身份证号只能属于一个人

  (4)老师和学生之间就是多对多
    一个学生可以被多个老师教过
    一个老师可以交多个学生

2.mybatis中的多表查询
示例:用户和账户
  一个用户可以有多个账户
  一个账户只能属于一个用户(多个账户也可以属于同一个用户)
步骤:
  1、建立两张表:用户表,账户表
    让用户表和账户表之间具备一对多的关系:需要使用外键在账户表中添加
  2、建立两个实体类:用户实体类和账户实体类
    让用户和账户的实体类能体现出来一对多的关系
  3、建立两个配置文件
    用户的配置文件
    账户的配置文件
  4、实现配置:
    当我们查询用户时,可以同时得到用户下所包含的账户信息
    当我们查询账户时,可以同时得到账户的所属用户信息

3.@Results注解用法总结:

MyBatis中使用@Results注解来映射查询结果集到实体类属性
(1)@Results的基本用法。当数据库字段名与实体类对应的属性名不一致时,可以使用@Results映射来将其对应起来。column为数据库字段名,porperty为实体类属性名,jdbcType为数据库字段数据类型,id为是否为主键。

  1. @Select({"select id, name, class_id from my_student"})
  2. @Results({
  3. @Result(column="id", property="id", jdbcType=JdbcType.INTEGER, id=true),
  4. @Result(column="name", property="name", jdbcType=JdbcType.VARCHAR),
  5. @Result(column="class_id", property="classId", jdbcType=JdbcType.INTEGER)
  6. })
  7. List<Student> selectAll();

如上所示的数据库字段名class_id与实体类属性名classId,就通过这种方式建立了映射关系。

(2)@ResultMap的用法。当这段@Results代码需要在多个方法用到时,为了提高代码复用性,我们可以为这个@Results注解设置id,然后使用@ResultMap注解来复用这段代码。

  1. @Select({"select id, name, class_id from my_student"})
  2. @Results(id="studentMap", value={
  3. @Result(column="id", property="id", jdbcType=JdbcType.INTEGER, id=true),
  4. @Result(column="class_id", property="classId", jdbcType=JdbcType.INTEGER)
  5. })
  6. List<Student> selectAll();
  7.  
  8. @Select({"select id, name, class_id from my_student where id = #{id}"})
  9. @ResultMap(value="studentMap")
  10. Student selectById(integer id);

(3)@One的用法。当我们需要通过查询到的一个字段值作为参数,去执行另外一个方法来查询关联的内容,而且两者是一对一关系时,可以使用@One注解来便捷的实现。比如当我们需要查询学生信息以及其所属班级信息时,需要以查询到的class_id为参数,来执行ClassesMapper中的selectById方法,从而获得学生所属的班级信息。可以使用如下代码。

  1. @Select({"select id, name, class_id from my_student"})
  2. @Results(id="studentMap", value={
  3. @Result(column="id", property="id", jdbcType=JdbcType.INTEGER, id=true),
  4. @Result(column="class_id", property="myClass", javaType=MyClass.class,
  5. one=@One(select="com.example.demo.mapper.MyClassMapper.selectById"))
  6. })
  7. List<Student> selectAllAndClassMsg();

(4)@Many的用法。与@One类似,只不过如果使用@One查询到的结果是多行,会抛出TooManyResultException异常,这种时候应该使用的是@Many注解,实现一对多的查询。比如在需要查询学生信息和每次考试的成绩信息时。

  1. @Select({"select id, name, class_id from my_student"})
  2. @Results(id="studentMap", value={
  3. @Result(column="id", property="id", jdbcType=JdbcType.INTEGER, id=true),
  4. @Result(column="class_id", property="classId", jdbcType=JdbcType.INTEGER),
  5. @Result(column="id", property="gradeList", javaType=List.class,
  6. many=@Many(select="com.example.demo.mapper.GradeMapper.selectByStudentId"))
  7. })
  8. List<Student> selectAllAndGrade();

参考文献:https://blog.csdn.net/cherlshall/article/details/80950150

4.操作案例

(1)案例1

查询所有查询所有账户,及其用户名和地址信息(逻辑为:账户表account-----》用户信息表user)

<1>对数据库表Account对应的实体类Account.java进行改造,加入User对象作为成员变量

  1. package domain;
  2.  
  3. import java.io.Serializable;
  4.  
  5. /**
  6. * 数据库的account表对应的实体类
  7. */
  8. public class Account implements Serializable {
  9. private Integer id;
  10. private Integer uid;
  11. private Double money;
  12. //从表实体应该包含一个主表实体的对象引用
  13. private User user;
  14.  
  15. public User getUser() {
  16. return user;
  17. }
  18.  
  19. public void setUser(User user) {
  20. this.user = user;
  21. }
  22.  
  23. public Integer getId() {
  24. return id;
  25. }
  26.  
  27. public void setId(Integer id) {
  28. this.id = id;
  29. }
  30.  
  31. public Integer getUid() {
  32. return uid;
  33. }
  34.  
  35. public void setUid(Integer uid) {
  36. this.uid = uid;
  37. }
  38.  
  39. public Double getMoney() {
  40. return money;
  41. }
  42.  
  43. public void setMoney(Double money) {
  44. this.money = money;
  45. }
  46.  
  47. @Override
  48. public String toString() {
  49. return "Account{" +
  50. "id=" + id +
  51. ", uid=" + uid +
  52. ", money=" + money +
  53. '}';
  54. }
  55. }

<2>IAccountDao中添加findAll()方法

  1. package dao;
  2.  
  3. import domain.Account;
  4. import domain.AccountUser;
  5.  
  6. import java.util.List;
  7.  
  8. public interface IAccountDao {
  9.  
  10. /**
  11. * 查询所有查询所有账户,及其用户名和地址信息
  12. * @return
  13. */
  14. List<Account> findAll();
  15.  
  16. }

<3>映射关系配置

(1)IAccountDao.xml配置

ResultMap标签基本作用:建立SQL查询结果字段与实体属性的映射关系信息

标签属性id和type的含义:

  id:该resultMap的标志
  type:返回值的类名

子标签含义:

  id:用于设置主键字段与领域模型属性的映射关系,此处主键为ID,对应id。
  result:用于设置普通字段与领域模型属性的映射关系
  association 为关联关系,是实现一对一的关键
    1. property 为javabean中容器对应字段名     
    2. javaType 指定关联的类型,当使用select属性时,无需指定关联的类型
    3. select 使用另一个select查询封装的结果
    4. column 为数据库中的列名,与select配合使用

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!DOCTYPE mapper
  3. PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  4. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  5.  
  6. <mapper namespace="dao.IAccountDao">
  7.  
  8. <resultMap id="accountUserMap" type="domain.Account">
  9. <id property="id" column="aid"></id>
  10. <result property="uid" column="uid"></result>
  11. <result property="money" column="money"></result>
  12. <!--配置所外键所关联表user的内容-->
  13. <association property="user" column="uid" javaType="domain.User">
  14. <id property="id" column="id"></id>
  15. <result property="username" column="username"></result>
  16. <result property="birthday" column="birthday"></result>
  17. <result property="sex" column="sex"></result>
  18. <result property="address" column="address"></result>
  19. </association>
  20. </resultMap>
  21.  
  22. <!-- 查询所有查询所有账户,及其用户名和地址信息:方法1(更通用) -->
  23. <!--account a 给account表起一个别名-->
  24. <select id="findAll" resultMap="accountUserMap">
  25. select u.*,a.id as aid,a.uid,a.money from account a , user u where u.id = a.uid;
  26. </select>
  27.  
  28. </mapper>

注解配置:IAccountDao.java文件中进行如下配置

  1. /**
  2. * 查询所有查询所有账户,及其用户名和地址信息
  3. * 注解中的第四个result的column为uid(外键),连接到user表,select调用dao.IUserDao.findById()方法
  4. * @return
  5. */
  6. @Select("select * from account")
  7. @Results(id="accountMap",value = {
  8. @Result(id=true,column = "id",property = "id"),
  9. @Result(column = "uid",property = "uid"),
  10. @Result(column = "money",property = "money"),
  11. @Result(column = "uid",property = "user",one=@One(select = "dao.IUserDao.findById",fetchType = FetchType.EAGER))
  12. })
  13. List<Account> findAll();

<4>测试代码

  1. package test;
  2.  
  3. import dao.IAccountDao;
  4. import dao.IUserDao;
  5. import domain.Account;
  6. import domain.AccountUser;
  7. import org.apache.ibatis.io.Resources;
  8. import org.apache.ibatis.session.SqlSession;
  9. import org.apache.ibatis.session.SqlSessionFactory;
  10. import org.apache.ibatis.session.SqlSessionFactoryBuilder;
  11. import org.junit.Test;
  12.  
  13. import java.io.InputStream;
  14. import java.util.List;
  15.  
  16. public class MybatisTest01 {
  17.  
  18. private InputStream in;
  19. private SqlSession sqlSession;
  20. private IAccountDao accountDao;
  21.  
  22. /**
  23. * 初始化MyBatis
  24. * @throws Exception
  25. */
  26. public void initMyBatis() throws Exception{
  27. //1.读取配置文件
  28. in = Resources.getResourceAsStream("SqlMapConfig.xml");
  29. //2.创建SqlSessionFactory
  30. SqlSessionFactoryBuilder builder=new SqlSessionFactoryBuilder(); //创建SqlSessionFactory的构建者builder
  31. SqlSessionFactory factory=builder.build(in); //利用构建者builder创建SqlSessionFactory
  32. //3.使用工厂生产SqlSession对象
  33. sqlSession = factory.openSession();
  34. //4.使用SqlSessions对象创建Dao接口的代理对象
  35. accountDao = sqlSession.getMapper(IAccountDao.class);
  36. }
  37.  
  38. /**
  39. * 释放资源
  40. * @throws Exception
  41. */
  42. public void destroy() throws Exception{
  43. sqlSession.commit();//提交事务
  44. sqlSession.close();
  45. in.close();
  46. }
  47.  
  48. /**
  49. * 查询所有
  50. * @throws Exception
  51. */
  52. @Test
  53. public void testFindAll()throws Exception{
  54. initMyBatis();
  55. List<Account> accounts = accountDao.findAll();
  56. for (Account account : accounts) {
  57. System.out.println(account);
  58. System.out.println(account.getUser());
  59. }
  60. destroy();
  61. }
  62.  
  63. }

效果图:

(2)案例2

查询所有查询用户信息,及其拥有的账户信息(逻辑为:用户信息表user-----》账户表account)

<1>对数据库表user对应的实体类User.java进行改造,加入List<Account>作为成员变量

  1. package domain;
  2.  
  3. import java.io.Serializable;
  4. import java.util.Date;
  5. import java.util.List;
  6.  
  7. /**
  8. * 数据库表对应的实体类
  9. */
  10. public class User implements Serializable {
  11. //实体类的成员变量名称应该与数据库中的列名一致
  12. private Integer id;
  13. private String username;
  14. private Date birthday;
  15. private String sex;
  16. private String address;
  17. private List<Account> accounts;
  18.  
  19. public List<Account> getAccounts() {
  20. return accounts;
  21. }
  22.  
  23. public void setAccounts(List<Account> accounts) {
  24. this.accounts = accounts;
  25. }
  26.  
  27. public Integer getId() {
  28. return id;
  29. }
  30.  
  31. public void setId(Integer id) {
  32. this.id = id;
  33. }
  34.  
  35. public String getUsername() {
  36. return username;
  37. }
  38.  
  39. public void setUsername(String username) {
  40. this.username = username;
  41. }
  42.  
  43. public Date getBirthday() {
  44. return birthday;
  45. }
  46.  
  47. public void setBirthday(Date birthday) {
  48. this.birthday = birthday;
  49. }
  50.  
  51. public String getSex() {
  52. return sex;
  53. }
  54.  
  55. public void setSex(String sex) {
  56. this.sex = sex;
  57. }
  58.  
  59. public String getAddress() {
  60. return address;
  61. }
  62.  
  63. public void setAddress(String address) {
  64. this.address = address;
  65. }
  66.  
  67. @Override
  68. public String toString() {
  69. return "User{" +
  70. "id=" + id +
  71. ", username='" + username + '\'' +
  72. ", birthday=" + birthday +
  73. ", sex='" + sex + '\'' +
  74. ", address='" + address + '\'' +
  75. '}';
  76. }
  77. }

<2>IUserDao中添加findAll()方法

  1. package dao;
  2.  
  3. import domain.User;
  4.  
  5. import java.util.List;
  6.  
  7. /**
  8. *
  9. */
  10. public interface IUserDao {
  11. /**
  12. * 查询所有
  13. * @return
  14. */
  15. List<User> findAll();
  16.  
  17. }

<3>IUserDao.xml

ResultMap标签基本作用:建立SQL查询结果字段与实体属性的映射关系信息

标签属性id和type的含义:

  id:该resultMap的标志
  type:返回值的类名

子标签含义:

  id:用于设置主键字段与领域模型属性的映射关系,此处主键为ID,对应id。
  result:用于设置普通字段与领域模型属性的映射关系
  association 为关联关系,是实现一对一的关键 
    1. property 为javabean中容器对应字段名     
    2. javaType 指定关联的类型,当使用select属性时,无需指定关联的类型
    3. select 使用另一个select查询封装的结果
    4. column 为数据库中的列名

  collection 为关联关系,是实现一对多的关键
    1. property 为javabean中容器对应字段名
    2. ofType 指定集合中元素的对象类型
    3. select 使用另一个查询封装的结果
    4. column 为数据库中的列名,与select配合使用

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!DOCTYPE mapper
  3. PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  4. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  5.  
  6. <mapper namespace="dao.IUserDao">
  7.  
  8. <resultMap id="userAccountMap" type="domain.User">
  9. <id property="id" column="id"></id>
  10. <result property="username" column="username"></result>
  11. <result property="birthday" column="birthday"></result>
  12. <result property="sex" column="sex"></result>
  13. <result property="address" column="address"></result>
  14. <!--配置user对象中accounts集合的映射-->
  15. <collection property="accounts" ofType="domain.Account">
  16. <id property="id" column="aid"></id>
  17. <result property="uid" column="uid"></result>
  18. <result property="money" column="money"></result>
  19. </collection>
  20. </resultMap>
  21. <!-- 查询所有 -->
  22. <select id="findAll" resultMap="userAccountMap">
  23. select * from user u left outer join account a on u.id = a.uid
  24. </select>
  25.  
  26. </mapper>

注解配置:IUserDao.java文件中进行如下配置

  1. /**
  2. * 查询所有
  3. * @return
  4. */
  5. @Select("select * from user")
  6. @Results(id="userMap",value = {
  7. @Result(id=true,column = "id",property = "id"),
  8. @Result(column = "username",property = "username"),
  9. @Result(column = "address",property = "address"),
  10. @Result(column = "sex",property = "sex"),
  11. @Result(column = "birthday",property = "birthday"),
  12. @Result(column = "id",property ="accounts",many =@Many(select = "dao.IAccountDao.findAccountById",fetchType = FetchType.EAGER))
  13. })
  14. List<User> findAll();

<4>测试代码

  1. package test;
  2.  
  3. import dao.IAccountDao;
  4. import dao.IUserDao;
  5. import domain.Account;
  6. import domain.AccountUser;
  7. import domain.User;
  8. import org.apache.ibatis.io.Resources;
  9. import org.apache.ibatis.session.SqlSession;
  10. import org.apache.ibatis.session.SqlSessionFactory;
  11. import org.apache.ibatis.session.SqlSessionFactoryBuilder;
  12. import org.junit.Test;
  13.  
  14. import java.io.InputStream;
  15. import java.util.List;
  16.  
  17. public class MybatisTest02_User {
  18.  
  19. private InputStream in;
  20. private SqlSession sqlSession;
  21. private IUserDao userDao;
  22.  
  23. /**
  24. * 初始化MyBatis
  25. * @throws Exception
  26. */
  27. public void initMyBatis() throws Exception{
  28. //1.读取配置文件
  29. in = Resources.getResourceAsStream("SqlMapConfig.xml");
  30. //2.创建SqlSessionFactory
  31. SqlSessionFactoryBuilder builder=new SqlSessionFactoryBuilder(); //创建SqlSessionFactory的构建者builder
  32. SqlSessionFactory factory=builder.build(in); //利用构建者builder创建SqlSessionFactory
  33. //3.使用工厂生产SqlSession对象
  34. sqlSession = factory.openSession();
  35. //4.使用SqlSessions对象创建Dao接口的代理对象
  36. userDao = sqlSession.getMapper(IUserDao.class);
  37. }
  38.  
  39. /**
  40. * 释放资源
  41. * @throws Exception
  42. */
  43. public void destroy() throws Exception{
  44. sqlSession.commit();//提交事务
  45. sqlSession.close();
  46. in.close();
  47. }
  48.  
  49. /**
  50. * 查询所有
  51. * @throws Exception
  52. */
  53. @Test
  54. public void testFindAll()throws Exception{
  55. initMyBatis();
  56. List<User> users = userDao.findAll();
  57. for (User user : users) {
  58. System.out.println(user);
  59. System.out.println(user.getAccounts());
  60. }
  61. destroy();
  62. }
  63.  
  64. }

效果图:

4.Mybatis中的缓存
(1)什么是缓存
  存在于内存中的临时数据。
(2)为什么使用缓存
  减少和数据库的交互次数,提高执行效率。
(3)什么样的数据能使用缓存,什么样的数据不能使用
  <1>适用于缓存:
    经常查询并且不经常改变的。
    数据的正确与否对最终结果影响不大的。
  <2>不适用于缓存:
    经常改变的数据
    数据的正确与否对最终结果影响很大的。
    例如:商品的库存,银行的汇率,股市的牌价。
5.Mybatis中的一级缓存和二级缓存
(1)一级缓存:
  它指的是Mybatis中SqlSession对象的缓存。
  当我们执行查询之后,查询的结果会同时存入到SqlSession为我们提供一块区域中。
  该区域的结构是一个Map。当我们再次查询同样的数据,mybatis会先去sqlsession中
  查询是否有,有的话直接拿出来用。
  当SqlSession对象消失时,mybatis的一级缓存也就消失了。

(2)二级缓存:
  它指的是Mybatis中SqlSessionFactory对象的缓存。由同一个SqlSessionFactory对象创建的SqlSession共享其缓存。
  二级缓存的使用步骤:
    第一步:让Mybatis框架支持二级缓存(在SqlMapConfig.xml中配置)
    第二步:让当前的映射文件支持二级缓存(在IUserDao.xml中配置)
    第三步:让当前的操作支持二级缓存(在select标签中配置)

07 Mybatis的多表查询1----1对多和多对1---@Results注解用法总结的更多相关文章

  1. 使用Mybatis进行连表查询、left join---https://blog.csdn.net/jinzhencs/article/details/51980518

    使用Mybatis进行连表查询.left join https://blog.csdn.net/jinzhencs/article/details/51980518

  2. SpringBoot集成Mybatis实现多表查询的两种方式(基于xml)

     下面将在用户和账户进行一对一查询的基础上进行介绍SpringBoot集成Mybatis实现多表查询的基于xml的两种方式.   首先我们先创建两个数据库表,分别是user用户表和account账户表 ...

  3. MyBatis的多表查询笔记

    MyBatis的多表查询 随着学习的进步,需求的提高,我们在实际开发中用的最多的还是多表查询,就让我们一起学习MyBatis中的多表查询. 数据库准备 Class表 Student表 项目结构 这次使 ...

  4. MyBatis框架——多表查询

    MyBatis多表查询, 从表中映射主表,使用 association 标签,通过设置 javaType 属性关联实体类: 主表映射从表,使用 collection 标签,通过 ofType 属性关联 ...

  5. MyBatis实现关联表查询

    一.一对一关联 1.1.提出需求 根据班级id查询班级信息(带老师的信息) 1.2.创建表和数据 创建一张教师表和班级表,这里我们假设一个老师只负责教一个班,那么老师和班级之间的关系就是一种一对一的关 ...

  6. MyBatis——实现关联表查询

    原文:http://www.cnblogs.com/xdp-gacl/p/4264440.html 一.一对一关联 1.1.提出需求 根据班级id查询班级信息(带老师的信息) 1.2.创建表和数据 创 ...

  7. Mybatis系列(三):Mybatis实现关联表查询

    原文链接:http://www.cnblogs.com/xdp-gacl/p/4264440.html 一.一对一关联 1.1.提出需求 根据班级id查询班级信息(带老师的信息) 1.2.创建表和数据 ...

  8. Mybatis多表查询(一对一、一对多、多对多)

    Mybatis的多表级联查询 . 一对一可以通过<association>实现,一对多和多对多通过<collection>实现. <discriminator> 元 ...

  9. MyBatis—实现关联表查询

    一.一对一关联 1.1.提出需求 根据班级id查询班级信息(带老师的信息) 1.2.创建表和数据 创建一张教师表和班级表,这里我们假设一个老师只负责教一个班,那么老师和班级之间的关系就是一种一对一的关 ...

随机推荐

  1. 分享STM32 FLASH 擦除(以及防止误擦除程序代码)、写入

    编译环境:我用的是(Keil)MDK4.7.2   stm32库版本:我用的是3.5.0一.本文不对FLASH的基础知识做详细的介绍,不懂得地方请查阅有关资料. 对STM32 内部FLASH进行编程操 ...

  2. Django ContentTypes框架使用场景

    Django contenttypes是一个非常有用的框架,主要用来创建模型间的通用关系(generic relation).不过由于其非常抽象, 理解起来并不容易.当你创建一个django项目的时候 ...

  3. Goexit

    package main import ( "fmt" "runtime" ) func test() { defer fmt.Println("cc ...

  4. 移动端touch触摸事件(滑动效果和手势操作)

    一.定义 ①touch是移动端的触摸事件,而且是一组事件,主要有以下事件: touchstart 事件:当手指触摸屏幕的时候触发 touchmove 事件:当手指在屏幕来回滑动的时候触发 touche ...

  5. 控制论模型&心流模型&波模型

    1.控制论模型 这是对设定的目标,通过多次输入和输出,反馈调节,最终达成目标的方法.广泛运用于自然科学与社会科学中.反馈的周期长短决定了调节精度的大小以及达到目标的速度.反馈结果与目标背离的立即纠正, ...

  6. 洛谷 P3884 [JLOI2009]二叉树问题

    目录 题目 思路 \(Code\) 题目 P3884 [JLOI2009]二叉树问题 思路 深搜统计深度,倍增\(\text{LCA}\)求边数 \(Code\) #include<iostre ...

  7. 57、Spark Streaming: window滑动窗口以及热点搜索词滑动统计案例

    一.window滑动窗口 1.概述 Spark Streaming提供了滑动窗口操作的支持,从而让我们可以对一个滑动窗口内的数据执行计算操作.每次掉落在窗口内的RDD的数据, 会被聚合起来执行计算操作 ...

  8. CSS — BEM 命名规范

    推荐阅读: https://juejin.im/post/5b925e616fb9a05cdd2ce70d 1 什么是 BEM 命名规范 Bem 是块(block).元素(element).修饰符(m ...

  9. 开机启动类似于Tencent Upd的弹窗解决方法

    1.开机启动的程序,后台启动自动升级的exe,每次开机都弹出弹窗,一不小心就点错了,神烦. 解决方式:直接在windows系统  [ 本地安全策略>软件限制策略>其他规则 ] 里面把弹出的 ...

  10. 除法运算时的一个常见异常之java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.

    一.背景 今天在计算库存消耗百分比(消耗的库存/总库存)的时候遇到了一个错误,java.lang.ArithmeticException: Non-terminating decimal expans ...