多表关联:一对一关联(重点)

association标签的作用:一对一关联映射

property 指定另一方对象的属性名字 resultMap 指定另一方的映射

image.png

  1. // 这个一个MyBatis工具类,简化MyBatis开发
  2. public class MyBatisUtils {
  3. // SqlSessionFactory: 理解为连接池
  4. private static SqlSessionFactory sqlSessionFactory;
  5. static {
  6. try {
  7. // 核心配置文件的名字
  8. String resource = "mybatis-config.xml";
  9. // 把核心配置文件变成流(相当于创建了一个输入流)
  10. InputStream inputStream = Resources.getResourceAsStream(resource);
  11. // new SqlSessionFactoryBuilder().build(inputStream): 解析mybatis-config.xml文件和UserMapper.xml文件
  12. sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
  13. } catch (IOException e) {
  14. System.out.println("MyBatis初始化失败: " + e.toString());
  15. }
  16. }
  17. // SqlSession: 相当于数据库连接池中的连接 (SqlSession有操作事务的功能每个功能都要拿到一个新的SqlSession,保证事务准确)
  18. public static SqlSession openSession() {
  19. SqlSession sqlSession = sqlSessionFactory.openSession();
  20. return sqlSession;
  21. }
  22. // 可以自动提交事务
  23. public static SqlSession openSession(boolean autoCommit) {
  24. SqlSession sqlSession = sqlSessionFactory.openSession(autoCommit);
  25. return sqlSession;
  26. }
  27. }
  1. //user表实现类
  2. public class User {
  3. private int id;
  4. private String username;
  5. private Date birthday;
  6. private String sex;
  7. private String address;
  8. //一对一,一个用户号包含一个扩展信息
  9. private UserInfo userInfo;
  10. //构造方法setgettoString方法
  11. }
  12. //user_into表实现类
  13. public class UserInfo {
  14. private int id;
  15. private double height;
  16. private double weight;
  17. private boolean married;
  18. }
  1. public class TestMybatis {
  2. public static SqlSession sqlSession;
  3. @Test
  4. public void test01() {
  5. SqlSession sqlSession = MyBatisUtils.openSession();
  6. UserMapper mapper = sqlSession.getMapper(UserMapper.class);
  7. User user = mapper.findUserAndInfo(1);
  8. System.out.println(user);
  9. sqlSession.close();
  10. }
  11. }
  12. public interface UserMapper {
  13. User findUserAndInfo(int uid);
  14. }
  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. <!--MyBatis默认多表查询,表中字段名和类中变量名相同的也要配置
  6. autoMapping="true": 字段名和变量名相同的就不用指定-->
  7. <mapper namespace="com.gdkm.mapper.UserMapper">
  8. <resultMap id="InfoMap" type="UserInfo" autoMapping="true">
  9. <id column="id" property="id"/>
  10. </resultMap>
  11. <resultMap id="UserMap" type="user" autoMapping="true">
  12. <id column="id" property="id"/>
  13. <!--配置一对一-->
  14. <association property="userInfo" resultMap="InfoMap"/>
  15. </resultMap>
  16. <!--根据用户id查询用户基本信息和扩展信息-->
  17. <select id="findUserAndInfo" resultMap="UserMap">
  18. SELECT
  19. *
  20. FROM
  21. USER INNER JOIN user_info ON user.id = user_info.id
  22. WHERE
  23. user.id = #{uid};
  24. </select>
  25. </mapper>

多表关联:一对多关联(重点)

  1. //user表实现类
  2. public class User {
  3. private int id;
  4. private String username;
  5. private Date birthday;
  6. private String sex;
  7. private String address;
  8. //一对多,一个用户包含多个订单
  9. private List<Order> order;
  10. }
  11. //order表实现类
  12. public class Order {
  13. private int oid;
  14. private int userId;
  15. private String number;
  16. private Timestamp createTime;
  17. private String note;
  18. }
  1. public class TestMybatis {
  2. public static SqlSession sqlSession;
  3. @Test
  4. public void test02() {
  5. SqlSession sqlSession = MyBatisUtils.openSession();
  6. UserMapper mapper = sqlSession.getMapper(UserMapper.class);
  7. User user = mapper.findUserAndOrders(1);
  8. System.out.println(user);
  9. user.getOrder().forEach(System.out::println);
  10. sqlSession.close();
  11. }
  12. }
  13. public interface UserMapper {
  14. User findUserAndOrders(int uid);
  15. }
  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. <!--MyBatis默认多表查询,表中字段名和类中变量名相同的也要配置
  6. autoMapping="true": 字段名和变量名相同的就不用指定-->
  7. <mapper namespace="com.gdkm.mapper.UserMapper">
  8. <resultMap id="OrderMap" type="Order" autoMapping="true">
  9. <id column="oid" property="oid"/>
  10. </resultMap>
  11. <resultMap id="UserMap" type="user" autoMapping="true">
  12. <id column="id" property="id"/>
  13. <!--配置一对多-->
  14. <collection property="order" resultMap="OrderMap"/>
  15. </resultMap>
  16. <!--根据用户id查询用户基本信息和所有订单-->
  17. <select id="findUserAndOrders" resultMap="UserMap">
  18. SELECT
  19. *
  20. FROM
  21. USER INNER JOIN `order` ON user.id = `order`.user_id
  22. WHERE
  23. user.id = #{uid};
  24. </select>
  25. </mapper>

多表关联: 多对多(两个一对多)

collection的作用:一对多的关联映射

property 多方属性的名字 javaType 属性的类型 ofType 元素的类型 image.png

根据用户id查询用户基本信息和所有角色

  1. //user表实现类
  2. public class User {
  3. private int id;
  4. private String username;
  5. private Date birthday;
  6. private String sex;
  7. private String address;
  8. // 一对多(一个用户包含多个角色)
  9. private List<Role> roles;
  10. }
  11. //role表实现类
  12. public class Role {
  13. private int roleId;
  14. private String roleName;
  15. private String roleDetail;
  16. }
  1. public class TestMybatis {
  2. public static SqlSession sqlSession;
  3. @Test
  4. public void test03() {
  5. SqlSession sqlSession = MyBatisUtils.openSession();
  6. UserMapper mapper = sqlSession.getMapper(UserMapper.class);
  7. User user = mapper.findUserAndRoles(1);
  8. System.out.println(user);
  9. user.getRoles().forEach(System.out::println);
  10. sqlSession.close();
  11. }
  12. }
  13. public interface UserMapper {
  14. User findUserAndRoles(int uid);
  15. }
  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. <!--MyBatis默认多表查询,表中字段名和类中变量名相同的也要配置
  6. autoMapping="true": 字段名和变量名相同的就不用指定-->
  7. <mapper namespace="com.gdkm.mapper.UserMapper">
  8. <resultMap id="UserMap" type="user" autoMapping="true">
  9. <id column="id" property="id"/>
  10. <!--配置一对多 简化写法-->
  11. <collection property="roles" javaType="List" ofType="Role" autoMapping="true">
  12. <id column="role_id" property="roleId"/>
  13. </collection>
  14. </resultMap>
  15. <!--根据用户id查询用户基本信息和所有角色-->
  16. <select id="findUserAndRoles" resultMap="UserMap">
  17. SELECT
  18. *
  19. FROM
  20. USER INNER JOIN user_role ON user.`id`= user_role.`user_id`
  21. INNER JOIN role ON user_role.`role_id`=role.`role_id`
  22. WHERE
  23. user.`id` = #{uid};
  24. </select>
  25. </mapper>

根据角色id查询角色所有信息和所有用户

  1. //user表实现类
  2. public class User {
  3. private int id;
  4. private String username;
  5. private Date birthday;
  6. private String sex;
  7. private String address;
  8. }
  9. //role表实现类
  10. public class Role {
  11. private int roleId;
  12. private String roleName;
  13. private String roleDetail;
  14. // 一对多(一个角色包含多个用户)
  15. private List<User> users;
  16. }
  1. public class TestMybatis {
  2. public static SqlSession sqlSession;
  3. @Test
  4. public void test04() {
  5. SqlSession sqlSession = MyBatisUtils.openSession();
  6. UserMapper mapper = sqlSession.getMapper(UserMapper.class);
  7. Role role = mapper.findRoleAndUsers(1);
  8. System.out.println(role);
  9. role.getUsers().forEach(System.out::println);
  10. sqlSession.close();
  11. }
  12. }
  13. public interface UserMapper {
  14. Role findRoleAndUsers(int uid);
  15. }
  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. <!--MyBatis默认多表查询,表中字段名和类中变量名相同的也要配置
  6. autoMapping="true": 字段名和变量名相同的就不用指定-->
  7. <mapper namespace="com.gdkm.mapper.UserMapper">
  8. <resultMap id="RoleMap" type="Role" autoMapping="true">
  9. <id column="role_id" property="roleId"/>
  10. <!--配置一对多-->
  11. <collection property="users" javaType="List" ofType="User" autoMapping="true">
  12. <id column="id" property="id"/>
  13. </collection>
  14. </resultMap>
  15. <!--根据角色id查询角色和所有用户-->
  16. <select id="findRoleAndUsers" resultMap="RoleMap">
  17. SELECT
  18. *
  19. FROM
  20. USER INNER JOIN user_role ON user.`id`=user_role.`user_id`
  21. INNER JOIN role ON user_role.`role_id`=role.`role_id`
  22. WHERE
  23. role.`role_id`=#{rid};
  24. </select>
  25. </mapper>

涉及数据表

user

image.png

user_info

image.png

order

image.png

user_role

image.png

role

image.png

MyBatis缓存

概述

  • MyBatis框架提供了缓存策略,通过缓存策略可以减少查询数据库的次数,提升系统性能
  • MyBatis框架中缓存分为一级缓存和二级缓存

image.png

一级缓存

  • 一级缓存是sqlSession范围的缓存,只能在同一个sqlSession内部有效。它本身已经存在,一级缓存不需要手动处理,可以直接使用
  • 第一次查询数据时,会将查询的数据放入一级缓存中。后面的相同查询直接从缓存中获取
  • 一级缓存是 SqlSession 范围缓存。当调用 SqlSession 的修改、添加、删除、提交、关闭等方法时,一级缓存会被清空
  1. // 测试一级缓存
  2. public void test03() {
  3. SqlSession sqlSession = MyBatisUtils.getSqlSession();
  4. UserMapper mapper = sqlSession.getMapper(UserMapper.class);
  5. // 第一次查询
  6. User user = mapper.findUserById(1);
  7. System.out.println(user.getUsername());
  8. // 清除缓存
  9. // sqlSession.clearCache();
  10. // 第二次查询
  11. User user2 = mapper.findUserById(1);
  12. System.out.println(user2.getUsername());
  13. sqlSession.close();
  14. }

二级缓存

概述

  • 二级缓存是mapper映射级别缓存,作用范围跨越SqlSession,即可以在多个SqlSession之间共享二级缓存数据

    实现步骤

  • 修改实体类实现Serializable接口
    • public class 实现类名 implements Serializable{ }
  • 在 mybatis-config.xml 配置开启二级缓存
    • image.png
  • 在 UserMapper.xml 开启二级缓存
    • image.png
    • image.png
  • 使用准备2个SqlSession进行测试
  1. public void test04() {
  2. // 第一个sqlSession
  3. SqlSession sqlSession1 = MyBatisUtils.getSqlSession();
  4. UserMapper mapper1 = sqlSession1.getMapper(UserMapper.class);
  5. User user1 = mapper1.findUserById(1);
  6. System.out.println("第一次" + user1.getUsername());
  7. sqlSession1.close(); // 要关闭数据才会保存二级缓存中
  8. // 第二个sqlSession
  9. SqlSession sqlSession2 = MyBatisUtils.getSqlSession();
  10. UserMapper mapper2 = sqlSession2.getMapper(UserMapper.class);
  11. User user2 = mapper2.findUserById(1);
  12. System.out.println("第二次" + user2.getUsername());
  13. sqlSession2.close();
  14. }