一对多

查询模型

用户表和订单表的关系为,一个用户有多个订单,一个订单只属于一个用户。一对多查询的需求是:查询一个用户,同时查询出该用户具有的订单。

一对多优点

  • 数据清晰,关系明确
  • 数据完整性可以通过外键约束强制维护
  • 查询灵活,通过关联表可以获取丰富的数据

一对多缺点

  • 对于复杂查询,可能涉及多次连接(JOIN),性能稍差
  • 数据模型耦合较紧,当表结构发生变更时,影响范围较大

编写代码

UserMapper

@Select("select * from wzk_user")
@Results({
        @Result(id = true, property = "id", column = "id"),
        @Result(property = "username", column = "username"),
        @Result(property = "password", column = "password"),
        @Result(property = "birthday", column = "birthday"),
        @Result(property = "roleList", column = "id", javaType = List.class,
                many = @Many(select = "icu.wzk.mapper.OrderMapper.findByUserIdWithAnnotation"))
})
List<WzkUser> findAllUserAndOderWithAnnotation();

OrderMapper

@Select("select * from wzk_orders where id = #{id}")
List<WzkOrder> findByUserIdWithAnnotation(int id);

调用代码

public class WzkIcu12 {
    public static void main(String[] args) throws IOException {
        InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder()
                .build(resourceAsStream);
        SqlSession sqlSession = sqlSessionFactory.openSession();
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        List<WzkUser> dataList = userMapper.findAllUserAndOderWithAnnotation();
        dataList.forEach(System.out::println);
        sqlSession.close();
    }
}

测试结果

WzkUser(id=1, username=wzk, password=icu, birthday=Mon Nov 11 00:00:00 CST 2024, orderList=null, roleList=[WzkOrder(id=1, ordertime=Mon Nov 11 00:00:00 CST 2024, total=100.0, user=null)])
WzkUser(id=2, username=wzk2, password=icu2, birthday=Mon Nov 11 00:00:00 CST 2024, orderList=null, roleList=[WzkOrder(id=2, ordertime=Mon Nov 11 00:00:00 CST 2024, total=200.0, user=null)])

多对多

查询模型

用户表和角色表的关系为,一个用户有多个角色,一个角色被多个用户使用。多对多的查询需求是:查询用户同时查询出该用户的所有角色。

在数据库设计中,“多对多”关系是指两张表中的记录可以互相关联,多条记录可以关联多条记录。例如,“学生”表和”课程”表之间的关系可能是多对多。

要实现多对多的关系,通常需要使用一个中间表(关联表)。这个中间表起到桥梁的作用,将两个表的记录通过其主键关联起来。

多对多关系的特点

  • 双向性:A可以关联多个B,同时B也可以关联多个A
  • 需要中间表:为了表示这种关系,通常使用一个中间表来维护关联
  • 灵活性高:多对多关系非常适合用来表示复杂的业务逻辑

多对多关系的扩展

  • 添加额外字段:中间表可以扩展更多功能,例如可以为选课添加时间戳、成绩字段等
  • 索引优化:为中间表中的外键添加索引,提高查询性能
  • ORM框架支持:现代框架支持多对多关系的自动管理

编写代码

UserMapper

@Select("select * from wzk_user")
@Results({
        @Result(id = true,property = "id",column = "id"),
        @Result(property = "username",column = "username"),
        @Result(property = "password",column = "password"),
        @Result(property = "birthday",column = "birthday"),
        @Result(property = "roleList",column = "id",
                javaType = List.class,
                many = @Many(select = "icu.wzk.mapper.RoleMapper.findByUserIdWithAnnotation"))
})
List<WzkUser> findAllUserAndRoleWithAnnotation();

RoleMapper

public interface RoleMapper {
    @Select("select * from wzk_role r, wzk_user_role ur where r.id=ur.role_id and ur.user_id=#{uid}")
    List<WzkRole> findByUserIdWithAnnotation(int uid);
}

调用代码

public class WzkIcu13 {
    public static void main(String[] args) throws IOException {
        InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder()
                .build(resourceAsStream);
        SqlSession sqlSession = sqlSessionFactory.openSession();
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        List<WzkUser> dataList = userMapper.findAllUserAndRoleWithAnnotation();
        dataList.forEach(System.out::println);
        sqlSession.close();
    }
}

测试结果

WzkUser(id=1, username=wzk, password=icu, birthday=Mon Nov 11 00:00:00 CST 2024, orderList=null, roleList=[WzkRole(id=1, rolename=ADMIN)])
WzkUser(id=2, username=wzk2, password=icu2, birthday=Mon Nov 11 00:00:00 CST 2024, orderList=null, roleList=[WzkRole(id=2, rolename=USER)])

注解模式的优缺点

优点

  • 开发简单:无需复杂的XML配置文件
  • 代码集中:SQL语句和逻辑写在一起,便于维护
  • 便捷性:适合简单的CRUD操作,代码量少

缺点

  • 可读性差:SQL语句嵌入代码,可能不易阅读
  • 复杂SQL不易维护:对于复杂SQL,注解模式不如XML清晰
  • 可扩展性有限:不易支持动态SQL和高级功能