MyBatis的注解实现复杂映射开发

xml 配置方式实现复杂映射回顾

实现复杂映射我们之前可以在映射文件中通过配置来实现,使用注解开发后,我们可以通过 @Results 注解,@Result 注解,@One 注解和 @Many 注解组合完成复杂关系的配置。

注解说明
@Results
代替的是标签 ,该注解中可以使用单个的 @Result 注解,也可以使用 @Result 集合。
使用方式: @Results({@Result(), @Result()}) 或者 @Results(@Result())
@Result
代替了 标签和 标签
@Result 中的属性介绍
column:数据库中的列名
property:要装配的属性名
one:需要使用 @One 注解( @Result(one=@One)()
many:需要使用 @Many 注解( @Result(many=@many)()
@One(一对一)代替了 标签,是多表查询的关键,在注解中用来指定子查询返回单一对象。
@One 注解属性介绍
select:指定用来多表查询的 sqlmapper
使用格式: @Result(column="", property="", one=(select=""))
@Many(多对一)代替了 标签,是多表查询的关键,在注解中用来指定子查询返回对象集合。
使用格式: @Result(property="", column="", many=@many(select=""))

一对一查询

一对一查询的模型

用户表和订单表的关系为,一个用户有多个订单,一共订单只属于一个用户

一对一查询需求:查询一个订单,与此同时查询该订单对应的用户

@startuml !include https://unpkg.com/plantuml-style-c4@latest/core.puml ' uncomment the following line and comment the first to use locally '!include core.puml left to right direction class orders { ordertime: varchar(255) total: double uid: int(11) id: int(11) } class user { username: varchar(50) password: varchar(50) birthday: varchar(50) id: int(11) } orders -[#595959,plain]-^ user : "uid:id" @enduml

一对一查询的语句

对应的 sql 语句

select * from orders;
select * from user where id=查询出订单的uid;

查询结果如下:

idordertimetotaluididusernamepasswordbirthday
12019-12-12300011lucy1232019-12-12
22019-12-12400011lucy1232019-12-12
32019-12-12500021lucy1232019-12-12
12019-12-12300012tom1232019-12-12

创建 User 和 Order 实体

/*** 订单** @name: Order* @author: terwer* @date: 2022-03-17 17:42**/
public class Order {private Integer id;private String orderTime;private Double total;// 代表当前订单属于哪一个用户private User user;public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getOrderTime() {return orderTime;}public void setOrderTime(String orderTime) {this.orderTime = orderTime;}public Double getTotal() {return total;}public void setTotal(Double total) {this.total = total;}public User getUser() {return user;}public void setUser(User user) {this.user = user;}@Overridepublic String toString() {return "Order{" +"id=" + id +", orderTime='" + orderTime + '\'' +", total=" + total +", user=" + user +'}';}
}/*** 用户** @name: User* @author: terwer* @date: 2022-05-25 13:25**/
public class User {private Integer id;private String username;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;}@Overridepublic String toString() {return "User{" +"id=" + id +", username='" + username + '\'' +'}';}
}

创建 IOrderMapper 接口

/*** 订单映射** @name: IUserMapper* @author: terwer* @date: 2022-03-17 17:54**/
public interface IOrderMapper {public List<Order> findOrderAndUser();
}

使用注解配置接口

/*** 订单映射** @name: IUserMapper* @author: terwer* @date: 2022-03-17 17:54**/
public interface IOrderMapper {/*** 查询订单同时查询订单所属用户** @return*/@Results({@Result(property = "id", column = "id"),@Result(property = "orderTime", column = "ordertime"),@Result(property = "total", column = "total"),@Result(property = "user", column = "uid", javaType = User.class, one = @One(select = "com.terwergreen.mapper.IUserMapper.findUserById"))})@Select("select * from orders")public List<Order> findOrderAndUser();
}
/** 用户映射** @name: IUserMapper* @author: terwer* @date: 2022-05-25 13:27**/
public interface IUserMapper {/*** 根据ID查询用户* @param id* @return*/@Select("select * from user where id=#{id}")User findUserById(Integer id);
}

测试结果

/*** 订单测试** @name: IOrderMapperTest* @author: terwer* @date: 2022-08-31 22:52**/
public class IOrderMapperTest {private IOrderMapper orderMapper;private SqlSession sqlSession;@Beforepublic void before() throws Exception {System.out.println("before...");InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);sqlSession = sqlSessionFactory.openSession();// 这样也是可以的,这样的话后面就不用每次都设置了// sqlSession = sqlSessionFactory.openSession(true);orderMapper = sqlSession.getMapper(IOrderMapper.class);}@Testpublic void testFindOrder() throws Exception {List<Order> orderAndUser = orderMapper.findOrderAndUser();orderAndUser.forEach(order -> {System.out.println(order);});}
}

效果

Opening JDBC Connection
Created connection 2024453272.
Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@78aab498]
==>  Preparing: select * from orders
==> Parameters: 
<==    Columns: id, ordertime, total, uid
<==        Row: 1, 2019-12-12, 3000.0, 1
====>  Preparing: select * from user where id=?
====> Parameters: 1(Integer)
<====    Columns: id, username, password, birthday
<====        Row: 1, lucy, 123, 2019-12-12
<====      Total: 1
<==        Row: 2, 2019-12-12, 4000.0, 1
<==        Row: 3, 2019-12-12, 5000.0, 2
====>  Preparing: select * from user where id=?
====> Parameters: 2(Integer)
<====    Columns: id, username, password, birthday
<====        Row: 2, tom, 123, 2019-12-12
<====      Total: 1
<==      Total: 3
Order{id=1, orderTime='2019-12-12', total=3000.0, user=User{id=1, username='lucy'}}
Order{id=2, orderTime='2019-12-12', total=4000.0, user=User{id=1, username='lucy'}}
Order{id=3, orderTime='2019-12-12', total=5000.0, user=User{id=2, username='tom'}}Process finished with exit code 0

调用过程分析

image-20220901002006366

一对多查询

一对多查询的模型

用户表和订单表的关系为,一个用户有多个订单,一个订单只从属于一个用户。

一对多查询需求:查询一个用户,与此同时查出该用户具有的订单。

@startuml !include https://unpkg.com/plantuml-style-c4@latest/core.puml ' uncomment the following line and comment the first to use locally '!include core.puml left to right direction class orders { ordertime: varchar(255) total: double uid: int(11) id: int(11) } class user { username: varchar(50) password: varchar(50) birthday: varchar(50) id: int(11) } orders -[#595959,plain]-^ user : "uid:id" @enduml

一对多查询语句

对应查询语句:

对应的 sql 语句

select * from user;
select * from orders where uid=查询出用户的id;

查询结果如下:

idordertimetotaluididusernamepasswordbirthday
12019-12-12300011lucy1232019-12-12
22019-12-12400011lucy1232019-12-12
32019-12-12500021lucy1232019-12-12
12019-12-12300012tom1232019-12-12

修改 User 实体

/*** 订单** @name: Order* @author: terwer* @date: 2022-03-17 17:42**/
public class Order {private Integer id;private String orderTime;private Double total;// 代表当前订单属于哪一个用户private User user;public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getOrderTime() {return orderTime;}public void setOrderTime(String orderTime) {this.orderTime = orderTime;}public Double getTotal() {return total;}public void setTotal(Double total) {this.total = total;}public User getUser() {return user;}public void setUser(User user) {this.user = user;}@Overridepublic String toString() {return "Order{" +"id=" + id +", orderTime='" + orderTime + '\'' +", total=" + total +", user=" + user +'}';}
}
/*** 用户** @name: User* @author: terwer* @date: 2022-05-25 13:25**/
public class User {private Integer id;private String username;// 代表当前用户具备那些订单private List<Order> orderList;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 List<Order> getOrderList() {return orderList;}public void setOrderList(List<Order> orderList) {this.orderList = orderList;}@Overridepublic String toString() {return "User{" +"id=" + id +", username='" + username + '\'' +", orderList=" + orderList +'}';}
}

创建 IUserMapper 接口

/*** 用户映射** @name: IUserMapper* @author: terwer* @date: 2022-05-25 13:27**/
public interface IUserMapper {/*** 查询用户和订单** @return*/List<User> findUserAndOrder();
}

使用注解配置 Mapper

/*** 用户映射** @name: IUserMapper* @author: terwer* @date: 2022-05-25 13:27**/
public interface IUserMapper {/*** 查询用户和订单** @return*/@Results({@Result(property = "id", column = "id"),@Result(property = "username", column = "username"),@Result(property = "orderList", column = "id", many = @Many(select = "com.terwergreen.mapper.IOrderMapper.findOrderByUid"), javaType = List.class)})@Select("select * from user")List<User> findUserAndOrder();
}
/*** 订单映射** @name: IUserMapper* @author: terwer* @date: 2022-03-17 17:54**/
public interface IOrderMapper {@Select("select * from orders where uid=#{uid}")public List<Order> findOrderByUid(Integer uid);
}

测试结果

public class IUserMapperTest {private IUserMapper userMapper;private SqlSession sqlSession;@Beforepublic void before() throws Exception {System.out.println("before...");InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);sqlSession = sqlSessionFactory.openSession();// 这样也是可以的,这样的话后面就不用每次都设置了// sqlSession = sqlSessionFactory.openSession(true);userMapper = sqlSession.getMapper(IUserMapper.class);}@Testpublic void testGetUserOrders() {List<User> userAndOrder = userMapper.findUserAndOrder();userAndOrder.forEach(user -> {System.out.println(user);});}
}

结果如下:

Opening JDBC Connection
Created connection 98394724.
Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@5dd6264]
==>  Preparing: select * from user
==> Parameters: 
<==    Columns: id, username, password, birthday
<==        Row: 1, lucy, 123, 2019-12-12
====>  Preparing: select * from orders where uid=?
====> Parameters: 1(Integer)
<====    Columns: id, ordertime, total, uid
<====        Row: 1, 2019-12-12, 3000.0, 1
<====        Row: 2, 2019-12-12, 4000.0, 1
<====      Total: 2
<==        Row: 2, tom, 123, 2019-12-12
====>  Preparing: select * from orders where uid=?
====> Parameters: 2(Integer)
<====    Columns: id, ordertime, total, uid
<====        Row: 3, 2019-12-12, 5000.0, 2
<====      Total: 1
<==        Row: 8, 测试2, null, null
====>  Preparing: select * from orders where uid=?
====> Parameters: 8(Integer)
<====      Total: 0
<==        Row: 9, 测试3, null, null
====>  Preparing: select * from orders where uid=?
====> Parameters: 9(Integer)
<====      Total: 0
<==      Total: 4
User{id=1, username='lucy', orderList=[Order{id=1, orderTime='2019-12-12', total=3000.0, user=null}, Order{id=2, orderTime='2019-12-12', total=4000.0, user=null}]}
User{id=2, username='tom', orderList=[Order{id=3, orderTime='2019-12-12', total=5000.0, user=null}]}
User{id=8, username='测试2', orderList=[]}
User{id=9, username='测试3', orderList=[]}Process finished with exit code 0

多对多查询

多对多查询的模型

用户表和角色表的关系为,一个用户有多个角色,一个角色被多个用户使用。

@startuml !include https://unpkg.com/plantuml-style-c4@latest/core.puml ' uncomment the following line and comment the first to use locally '!include core.puml left to right direction class sys_role { rolename: varchar(255) roleDesc: varchar(255) id: int(11) } class sys_user_role { userid: int(11) roleid: int(11) } class user { username: varchar(50) password: varchar(50) birthday: varchar(50) id: int(11) } sys_user_role -[#595959,plain]-^ sys_role : "roleid:id" sys_user_role -[#595959,plain]-^ user : "userid:id" @enduml

多对多查询需求

查询用户的同时查询该用户对应的角色。

多对多查询的语句

select * from user;
select * from sys_role r,sys_user_role ur where r.id=ur.roleid and ur.userid=用户的id

查询结果如下:

idrolenameroleDescuseridroleid
1CTOCTO11
2CEOCEO12

代码实现

  • 创建 User 实体和 Role 实体

    /*** 用户** @name: User* @author: terwer* @date: 2022-05-25 13:25**/
    public class User {private Integer id;private String username;// 代表当前用户具备那些订单private List<Order> orderList;// 代表当前用户具备的那些角色private List<Role> roleList;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 List<Order> getOrderList() {return orderList;}public void setOrderList(List<Order> orderList) {this.orderList = orderList;}public List<Role> getRoleList() {return roleList;}public void setRoleList(List<Role> roleList) {this.roleList = roleList;}@Overridepublic String toString() {return "User{" +"id=" + id +", username='" + username + '\'' +", orderList=" + orderList +", roleList=" + roleList +'}';}
    }
    
  • 创建 IRoleMapper

    /*** 角色映射** @name: IRoleMapper* @author: terwer* @date: 2022-09-06 00:04**/
    public interface  IRoleMapper {@Select("select * from sys_role r,sys_user_role ur where r.id=ur.roleid and ur.userid=#{userId}")List<Role> findRolesByUserId(Integer userId);
    }
    
    /*** 角色** @name: Role* @author: terwer* @date: 2022-05-12 14:14**/
    public class Role {private Integer id;private String rolename;@Overridepublic String toString() {return "Role{" +"id=" + id +", rolename='" + rolename + '\'' +'}';}
    }
    
  • 修改 IUserMapper

    /*** 用户映射** @name: IUserMapper* @author: terwer* @date: 2022-05-25 13:27**/
    public interface IUserMapper {@Results({@Result(property = "id", column = "id"),@Result(property = "username", column = "username"),@Result(property = "roleList", column = "id", javaType = List.class,many = @Many(select = "com.terwergreen.mapper.IRoleMapper.findRolesByUserId"))})@Select("select * from user")List<User> findUserAndRole();
    }
    
  • 添加测试方法

    public class IUserMapperTest {private IUserMapper userMapper;private SqlSession sqlSession;@Beforepublic void before() throws Exception {System.out.println("before...");InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);sqlSession = sqlSessionFactory.openSession();// 这样也是可以的,这样的话后面就不用每次都设置了// sqlSession = sqlSessionFactory.openSession(true);userMapper = sqlSession.getMapper(IUserMapper.class);}@Testpublic void testFindUserAndRole() {userMapper.findUserAndRole().forEach(user -> {System.out.println(user);});}
    }
    
  • 效果如下

    Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@51e5fc98]
    ==>  Preparing: select * from user
    ==> Parameters: 
    <==    Columns: id, username, password, birthday
    <==        Row: 1, lucy, 123, 2019-12-12
    ====>  Preparing: select * from sys_role r,sys_user_role ur where r.id=ur.roleid and ur.userid=?
    ====> Parameters: 1(Integer)
    <====    Columns: id, rolename, roleDesc, userid, roleid
    <====        Row: 1, CTO, CTO, 1, 1
    <====        Row: 2, CEO, CEO, 1, 2
    <====      Total: 2
    <==        Row: 2, tom, 123, 2019-12-12
    ====>  Preparing: select * from sys_role r,sys_user_role ur where r.id=ur.roleid and ur.userid=?
    ====> Parameters: 2(Integer)
    <====    Columns: id, rolename, roleDesc, userid, roleid
    <====        Row: 1, CTO, CTO, 2, 1
    <====        Row: 2, CEO, CEO, 2, 2
    <====      Total: 2
    <==        Row: 8, 测试2, null, null
    ====>  Preparing: select * from sys_role r,sys_user_role ur where r.id=ur.roleid and ur.userid=?
    ====> Parameters: 8(Integer)
    <====      Total: 0
    <==        Row: 9, 测试3, null, null
    ====>  Preparing: select * from sys_role r,sys_user_role ur where r.id=ur.roleid and ur.userid=?
    ====> Parameters: 9(Integer)
    <====      Total: 0
    <==      Total: 4
    User{id=1, username='lucy', orderList=null, roleList=[Role{id=1, rolename='CTO'}, Role{id=2, rolename='CEO'}]}
    User{id=2, username='tom', orderList=null, roleList=[Role{id=1, rolename='CTO'}, Role{id=2, rolename='CEO'}]}
    User{id=8, username='测试2', orderList=null, roleList=[]}
    User{id=9, username='测试3', orderList=null, roleList=[]}Process finished with exit code 0
    

文章更新历史

2024/05/13 同步文章到其他平台

2022-08-30 feat:初稿

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/701389.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

举个栗子!Tableau 技巧(273):用葡萄干布丁图(Plum Pudding Chart)查看数据

葡萄干布丁图 / Plum Pudding Chart 葡萄干布丁图&#xff08;Plum Pudding Chart&#xff09;源自英国传统的葡萄干布丁&#xff0c;它由多种原料混合而成&#xff0c;每种原料的比例不同&#xff0c;葡萄干布丁图用于展示多种不同类型的数据。 葡萄干布丁图由一系列同心圆环…

mysql的隔离性——MVCC

MVCC通过undolog版本链和readview来实现 更新和删除时会写入undolog中。 读已提交&#xff1a;在事务任意读时创建readview&#xff0c;读最新提交的事务 可重复读&#xff1a;在事务第一次读时创建readview

电力物联网-(2)系统设计

电力物联网系统设计 前言 在此之前写过《电力物联网系统设计》开篇文章&#xff0c;上一篇文章主要的概述性的内容&#xff0c;发表之后总觉得对电力物联网系统设计这一方面还只是开了一个头&#xff0c;没有把相关的内容讲解清楚&#xff0c;于是经过一段时间的构思终于产出了…

千层烤馍,五彩斑斓的甘肃特色美食

甘肃玫瑰千层烤馍是一道具有浓郁地方特色的传统面点&#xff0c;以其独特的口感和精美的外观而闻名。食家巷的千层烤馍更是其中的佼佼者&#xff0c;它采用了优质的原料和传统的制作工艺&#xff0c;让你品尝到最正宗的甘肃味道。 食家巷千层烤馍的制作过程非常讲究&#xff0c…

蓝桥杯-线性动态规划问题背包问题进阶策略详解-奇怪的段

0奇怪的段【算法赛】 - 蓝桥云课 (lanqiao.cn) 基础dp&#xff1a; #include<iostream> #include<cstring> #include<algorithm>using namespace std;const int N1e56;typedef long long ll;ll f[N][206]; ll a[N]; ll sum[N]; ll p[206]; int n,k;int main…

Python 和Java 哪个更适合做自动化测试?

Python和Java都是常用于自动化测试的编程语言&#xff0c;它们各有优势和适用场景。本文将从零到一地详细描述Python和Java在自动化测试中的特点和应用。 首先&#xff0c;我们来介绍Python在自动化测试中的优势。 Python是一种简洁、易读且功能强大的编程语言&#xff0c;它…

链表----带环链表快慢指针进阶版

1.带环链表及其拓展 &#xff08;1&#xff09;这个题目组要就是进行判断这个链表是否带环&#xff0c;使用的是布尔类型作为返回值&#xff1b; &#xff08;2&#xff09;我们这里的思路是使用的快慢指针&#xff0c;快指针一次走2步&#xff0c;慢指针一次走1步&#xff0c…

C++:编程领域的全能王者

在编程语言的海洋中&#xff0c;C以其全面而强大的功能&#xff0c;犹如一位全能王者&#xff0c;屹立不倒。它不仅在科技领域有着广泛的应用&#xff0c;更在推动社会进步、促进人类创新方面发挥着至关重要的作用。 一、C&#xff1a;编程界的璀璨明星 C自诞生以来&#xff…

【数据结构】红黑树(定义性质、插入、查找、删除)解析+完整代码

3.3 红黑树 3.3.1 定义和性质 为什么发明红黑树&#xff1f; 平衡二叉树和红黑树的时间复杂度相同&#xff0c;但是平衡二叉树的平衡特性容易被破坏&#xff0c;需要频繁调整树的形态。 红黑树RBT&#xff1a;插入/删除很多时候不会破坏红黑特性&#xff0c;无需频繁调整树的形…

浅谈Windows 上的线程亲和性(Thread affinity)

​ 前言 线程属性包括是否分离、亲和性、调度策略和优先级等。Linux默认的调度策略是CFS(完全公平调度算法),而 Windows 是基于优先级抢占式的策略。 在这些方面,Windows 和 Linux 差异巨大。本文仅针对 Windows 系统的线程亲和性进行探讨。 线程亲和性(Thread affinity) 什…

ESP32如何使用PSRAM

ESP32的内部RAM的设计做了内存扩展。您可以通过寻址高达4MB的外部SPI RAM内存来进一步扩展它。在本文中&#xff0c;探讨如何在项目中使用PSRAM&#xff0c;针对ESP32-WROVER模块进行特别的讨论。 关键问题&#xff1a; 如何确保PSRAM在应用程序代码中可用&#xff1f;如何分…

HOOPS Visualize:工业级3D可视化SDK,打造移动端和PC端工程应用程序

HOOPS Visualize是一种高性能的软件开发工具包&#xff08;SDK&#xff09;&#xff0c;旨在帮助开发人员轻松构建和集成高质量的3D可视化功能。这是一种全功能的&#xff0c;以工程为重点的场景图技术&#xff0c;我们称为Core Graphics。Core Graphics可集成到一个框架中&…