java ee 博客园_Java EE学习笔记(九)

MyBatis的关联映射

1、关联关系概述

1)、实际的开发中,对数据库的操作常常会涉及到多张表,这在面向对象中就涉及到了对象与对象之间的关联关系。针对多表之间的操作,MyBatis提供了关联映射,通过关联映射就可以很好的处理对象与对象之间的关联关系。

2)、在关系型数据库中,多表之间存在着三种关联关系,分别为一对一、一对多和多对多,如下图所示:

b7aaec77f68896de74ba6d6cf9861a9c.png

a)、一对一:在任意一方引入对方主键作为外键;

b)、一对多:在“多”的一方,添加“一”的一方的主键作为外键;

c)、多对多:产生中间关系表,引入两张表的主键作为外键,两个主键成为联合主键或使用新的字段作为主键。

3)、在Java中,通过对象也可以进行关联关系描述,如图下图所示:

555a35c5431023231e73d44d116c0075.png

a)、一对一:在本类中定义对方类型的对象,如A类中定义B类类型的属性b,B类中定义A类类型的属性a;

b)、一对多:一个A类类型对应多个B类类型的情况,需要在A类中以集合的方式引入B类类型的对象,在B类中定义A类类型的属性a;

c)、多对多:在A类中定义B类类型的集合,在B类中定义A类类型的集合。

2、一对一

1)、元素中,包含了一个子元素,MyBatis就是通过该元素来处理一对一关联关系的。

2)、在元素中,通常可以配置以下属性:

a)、property:指定映射到的实体类对象中的属性,与表字段一一对应。

b)、column:指定数据库表中对应的字段。

c)、javaType:指定映射到实体对象属性的类型。

d)、select:指定引入嵌套查询的子SQL语句,该属性用于关联映射中的嵌套查询。

e)、fetchType:指定在关联查询时是否启用延迟加载。该属性有lazy和eager两个属性值,默认值为lazy(即默认关联映射延迟加载)。

3)、MyBatis加载关联关系对象主要通过两种方式:嵌套查询和嵌套结果。

57c322d62fe3c731ff8984db879bdc41.png

4)、疑惑:虽然使用嵌套查询的方式比较简单,但是嵌套查询的方式要执行多条SQL语句,这对于大型数据集合和列表展示不是很好,因为这样可能会导致成百上千条关联的SQL语句被执行,从而极大的消耗数据库性能并且会降低查询效率。

5)、解决办法:MyBatis延迟加载的配置。使用MyBatis的延迟加载在一定程度上可以降低运行消耗并提高查询效率。MyBatis默认没有开启延迟加载,需要在核心配置文件中的元素内进行配置,具体配置方式如下:

6)、在映射文件中,元素和元素中都已默认配置了延迟加载属性,即默认属性fetchType="lazy"(属性fetchType="eager"表示立即加载),所以在配置文件中开启延迟加载后,无需在映射文件中再做配置。

7)、使用元素进行一对一关联映射非常简单,只需要参考如下两种示例配置即可。

839b1abbc54e219dd9088c769356ecf7.png

8)、创建数据库表---tb_idcard和tb_person。

1 CREATE TABLEtb_idcard(2 id INT PRIMARY KEYAUTO_INCREMENT,3 CODE VARCHAR(18)4 );5

6 INSERT INTO tb_idcard(CODE) VALUES('13341631331213');7 INSERT INTO tb_idcard(CODE) VALUES('21311211321111');8

9 CREATE TABLEtb_person(10 id INT PRIMARY KEYAUTO_INCREMENT,11 NAME VARCHAR(32),12 age INT,13 sex VARCHAR(8),14 card_id INT UNIQUE,15 FOREIGN KEY(card_id) REFERENCEStb_idcard(id)16 );17

18 INSERT INTO tb_person(NAME, age, sex, card_id) VALUES('Rose', 29, '女', 1);19 INSERT INTO tb_person(NAME, age, sex, card_id) VALUES('tom', 27, '男', 2);

执行SQL查询语句如图所示:

8a3d08198ac82c8611ccb4a1c0e232b5.png

9)、本章文件结构如下:

b7e878ddb7ed0f1814946b72baa5c100.png

635f25fd3a382d5059c04bb23bc406f1.png

①证件持久化类:src/com/itheima/po/IdCard.java

1 packagecom.itheima.po;2 /**

3 * 证件持久化类4 */

5 public classIdCard {6 privateInteger id;7 privateString code;8

9 publicInteger getId() {10 returnid;11 }12

13 public voidsetId(Integer id) {14 this.id =id;15 }16

17 publicString getCode() {18 returncode;19 }20

21 public voidsetCode(String code) {22 this.code =code;23 }24

25 @Override26 publicString toString() {27 return "IdCard [id=" + id + ", code=" + code + "]";28 }29 }

②个人持久化类:src/com/itheima/po/Person.java

1 packagecom.itheima.po;2 /**

3 * 个人持久化类4 */

5 public classPerson {6 privateInteger id;7 privateString name;8 privateInteger age;9 privateString sex;10 private IdCard card; //个人关联的证件

11

12 publicInteger getId() {13 returnid;14 }15

16 public voidsetId(Integer id) {17 this.id =id;18 }19

20 publicString getName() {21 returnname;22 }23

24 public voidsetName(String name) {25 this.name =name;26 }27

28 publicInteger getAge() {29 returnage;30 }31

32 public voidsetAge(Integer age) {33 this.age =age;34 }35

36 publicString getSex() {37 returnsex;38 }39

40 public voidsetSex(String sex) {41 this.sex =sex;42 }43

44 publicIdCard getCard() {45 returncard;46 }47

48 public voidsetCard(IdCard card) {49 this.card =card;50 }51

52 @Override53 publicString toString() {54 return "Person [id=" + id + ", name=" + name + ", age=" + age + ", sex=" + sex + ", card=" + card + "]";55 }56 }

③创建证件映射文件:src/com/itheima/mapper/IdCardMapper.xml

1 <?xml version="1.0" encoding="UTF-8"?>

2 "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

4

5

6

7

8

9 SELECT * from tb_idcard where id=#{id}10

11

④个人配置文件:src/com/itheima/mapper/PersonMapper.xml

1 <?xml version="1.0" encoding="UTF-8"?>

2 "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

4

5

6

7

10

11 resultMap="IdCardWithPersonResultID">

12 SELECT * from tb_person where id=#{id}13

14

15

16

17

18

19

20

21

22

29

30 select="com.itheima.mapper.IdCardMapper.findCodeById" />

31

32

33

34

35 resultMap="IdCardWithPersonResult2ID">

36

37 SELECT p.*,idcard.code38 from tb_person p,tb_idcard idcard39 where p.card_id=idcard.id40 and p.id= #{id}41

42

43

44

45

46

47

48

49

50

53

54

55

56

57

58

59

⑤编写MyBatis的配置文件:src/mybatis-config.xml

1 <?xml version="1.0" encoding="UTF-8"?>

2 "http://mybatis.org/dtd/mybatis-3-config.dtd">

4

5

6

7

8

9

10

11

13

14

15

16

17

18

19

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

⑥一对一映射查询测试:src/com/itheima/test/MybatisAssociatedTest.java

1 packagecom.itheima.test;2 importorg.apache.ibatis.session.SqlSession;3 importorg.junit.Test;4

5 importcom.itheima.po.Orders;6 importcom.itheima.po.Person;7 importcom.itheima.po.User;8 importcom.itheima.utils.MybatisUtils;9 /**

10 * Mybatis关联查询映射测试类11 */

12 public classMybatisAssociatedTest {13 /**

14 * 嵌套查询15 */

16 @Test17 public voidfindPersonByIdTest() {18

19 //1、通过工具类生成SqlSession对象

20 SqlSession session =MybatisUtils.getSession();21

22 //2.使用MyBatis嵌套查询的方式查询id为1的人的信息

23 Person person = session.selectOne("com.itheima.mapper.PersonMapper.findPersonById", 1);24

25 //3、输出查询结果信息

26 System.out.println(person);27

28 //4、关闭SqlSession

29 session.close();30 }31

32 /**

33 * 嵌套结果34 */

35 @Test36 public voidfindPersonByIdTest2() {37

38 //1、通过工具类生成SqlSession对象

39 SqlSession session =MybatisUtils.getSession();40

41 //2.使用MyBatis嵌套结果的方法查询id为1的人的信息

42 Person person = session.selectOne("com.itheima.mapper.PersonMapper.findPersonById2", 1);43

44 //3、输出查询结果信息

45 System.out.println(person);46

47 //4、关闭SqlSession

48 session.close();49 }50 }

⑦嵌套查询如图所示:

59f661975ccfcf54a313b34ae607dd22.png

⑧嵌套结果如图所示:

e92fd278d6bfc80cd9cf4231f6e72d67.png

3、一对多

1)、开发人员接触更多的关联关系是一对多(或多对一)。例如,一个用户可以有多个订单,同时多个订单归一个用户所有。元素中,包含了一个子元素,MyBatis就是通过该元素来处理一对多关联关系的。

2)、子元素的属性大部分与元素相同,但其还包含一个特殊属性--ofType 。

3)、ofType属性与javaType属性对应,它用于指定实体对象中集合类属性所包含的元素类型。元素的使用也非常简单,同样可以参考如下两种示例进行配置,具体代码如下:

633afebd5eff08d0c8a860fcecbd5047.png

4)、创建数据库表tb_user和tb_orders:

1 CREATE TABLEtb_user(2 id INT(32) PRIMARY KEYAUTO_INCREMENT,3 username VARCHAR(32),4 address VARCHAR(256)5 );6 INSERT INTO tb_user VALUES('1', '张三', '深圳');7 INSERT INTO tb_user VALUES('2', '李四', '东莞');8

9 CREATE TABLEtb_orders(10 id INT(32) PRIMARY KEYAUTO_INCREMENT,11 number VARCHAR(32) NOT NULL, #订单号12 user_id INT(32) NOT NULL, #外键,该订单上客户id13 FOREIGN KEY(user_id) REFERENCEStb_user(id) # 定义外键引用14 );15 INSERT INTO tb_orders VALUES('2', '100111', '1');16 INSERT INTO tb_orders VALUES('3', '100112', '2');

执行SQL查询语句后如图所示:

6fb2f30028e8023ed68a0b2a78008828.png

①创建订单持久化类:src/com/itheima/po/Orders.java

1 packagecom.itheima.po;2

3 importjava.util.List;4

5 /**

6 * 订单持久化类7 */

8 public classOrders {9 private Integer id; //订单id

10 private String number; //订单编号

11

12

13 publicInteger getId() {14 returnid;15 }16

17 public voidsetId(Integer id) {18 this.id =id;19 }20

21 publicString getNumber() {22 returnnumber;23 }24

25 public voidsetNumber(String number) {26 this.number =number;27 }28

29 @Override30 publicString toString() {31 return "Orders [id=" + id + ", number=" + number + "]";32 }33

34 }

②创建用户持久化类:src/com/itheima/po/User.java

1 packagecom.itheima.po;2 importjava.util.List;3 /**

4 * 用户持久化类5 */

6 public classUser {7 private Integer id; //用户编号

8 private String username; //用户姓名

9 private String address; //用户地址

10 private List ordersList; //用户关联的订单,一对多:即一个用户可以有多个订单

11

12 publicInteger getId() {13 returnid;14 }15

16 public voidsetId(Integer id) {17 this.id =id;18 }19

20 publicString getUsername() {21 returnusername;22 }23

24 public voidsetUsername(String username) {25 this.username =username;26 }27

28 publicString getAddress() {29 returnaddress;30 }31

32 public voidsetAddress(String address) {33 this.address =address;34 }35

36 public ListgetOrdersList() {37 returnordersList;38 }39

40 public void setOrdersList(ListordersList) {41 this.ordersList =ordersList;42 }43

44 @Override45 publicString toString() {46 return "User [id=" + id + ", username=" + username + ", address=" + address + ", ordersList=" + ordersList + "]";47 }48 }

③创建用户实体映射文件:src/com/itheima/mapper/UserMapper.xml

1 <?xml version="1.0" encoding="UTF-8"?>

2 "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

4

5

6

7

8

13

14 resultMap="UserWithOrdersResultID">

15 SELECT u.*, o.id as orders_id, o.number16 from tb_user u,tb_orders o17 WHERE u.id=o.user_id and u.id=#{id}18

19

20

21

22

23

24

25

26

32

33

36

37

38

39

40

④单元测试:

1 /**

2 * 一对多3 */

4 @Test5 public voidfindUserTest() {6

7 //1、通过工具类生成SqlSession对象

8 SqlSession session =MybatisUtils.getSession();9

10 //2、查询id为1的用户信息

11 User user = session.selectOne("com.itheima.mapper.UserMapper.findUserWithOrders", 1);12

13 //3、输出查询结果信息

14 System.out.println(user);15

16 //4、关闭SqlSession

17 session.close();18 }

⑤执行结果:

1fcefc4301d8a6a0267d097a14e322fc.png

4、多对多

1)、在实际项目开发中,多对多的关联关系也是非常常见的。以订单和商品为例,一个订单可以包含多种商品,而一种商品又可以属于多个订单。

2)、在数据库中,多对多的关联关系通常使用一个中间表来维护,中间表中的订单id作为外键参照订单表的id,商品id作为外键参照商品表的id。

d4c683cbb3a7c4279658dfda52711e49.png

3)、在MyBatis中,多对多的关联关系查询,同样可以使用前面介绍的元素进行处理(其用法和一对多关联关系查询语句用法基本相同)。

4)、创建数据库表tb_product和tb_ordersitem:

1 CREATE TABLEtb_product(2 id INT(32) PRIMARY KEYAUTO_INCREMENT,3 NAME VARCHAR(32),4 price DOUBLE

5 );6 INSERT INTO tb_product VALUES('1', 'JAVA入门基础', '96');7 INSERT INTO tb_product VALUES('2', 'JAVAWEB程序开发入门', '90');8 INSERT INTO tb_product VALUES('3', 'SSM框架整合实战', '90');9

10 CREATE TABLEtb_ordersitem( #创建中间表11 id INT(32) PRIMARY KEYAUTO_INCREMENT,12 orders_id INT(32),13 product_id INT(32),14 FOREIGN KEY(orders_id) REFERENCEStb_orders(id),15 FOREIGN KEY(product_id) REFERENCEStb_product(id)16 );17

18 INSERT INTO tb_ordersitem VALUES('1', '2', '1');19 INSERT INTO tb_ordersitem VALUES('2', '2', '3');20 INSERT INTO tb_ordersitem VALUES('3', '3', '3'); #注意引用值的存在

①创建商品持久化类:src/com/itheima/po/Product.java

1 packagecom.itheima.po;2 importjava.util.List;3 /**

4 * 商品持久化类5 */

6 public classProduct {7 private Integer id; //商品id

8 private String name; //商品名称

9 private Double price;//商品单价

10 private List orders; //与订单的关联属性

11

12 publicInteger getId() {13 returnid;14 }15

16 public voidsetId(Integer id) {17 this.id =id;18 }19

20 publicString getName() {21 returnname;22 }23

24 public voidsetName(String name) {25 this.name =name;26 }27

28 publicDouble getPrice() {29 returnprice;30 }31

32 public voidsetPrice(Double price) {33 this.price =price;34 }35

36 public ListgetOrders() {37 returnorders;38 }39

40 public void setOrders(Listorders) {41 this.orders =orders;42 }43

44 @Override45 publicString toString() {46 return "Product [id=" + id + ", name=" + name + ", price=" + price + "]";47 }48 }

②创建订单持久化类:src/com/itheima/po/Orders.java

1 packagecom.itheima.po;2

3 importjava.util.List;4

5 /**

6 * 订单持久化类7 */

8 public classOrders {9 private Integer id; //订单id

10 private String number; //订单编号11

12 //关联商品集合信息

13 private List productList; //一个订单可以包含多个商品,即一对多

14

15

16 publicInteger getId() {17 returnid;18 }19

20 public voidsetId(Integer id) {21 this.id =id;22 }23

24 publicString getNumber() {25 returnnumber;26 }27

28 public voidsetNumber(String number) {29 this.number =number;30 }31

32

33 public ListgetProductList() {34 returnproductList;35 }36

37 public void setProductList(ListproductList) {38 this.productList =productList;39 }40

41 @Override42 publicString toString() {43 return "Orders [id=" + id + ", number=" + number + ", productList=" + productList + "]";44 }45 }

③创建订单实体映射文件:src/com/itheima/mapper/OrdersMapper.xml

1 <?xml version="1.0" encoding="UTF-8"?>

2 "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

4

5

6

7

8

9 resultMap="OrdersWithProductResultID">

10 select * from tb_orders WHERE id=#{id}11

12

13

14

15

16

17

18

23

24 select="com.itheima.mapper.ProductMapper.findProductById">

25

26

27

28

29

30 resultMap="OrdersWithPorductResult2ID">

31 select o.*,p.id as pid,p.name,p.price32 from tb_orders o,tb_product p,tb_ordersitem oi33 WHERE oi.orders_id=o.id34 and oi.product_id=p.id35 and o.id=#{id}36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

④创建商品映射文件:src/com/itheima/mapper/ProductMapper.xml

1 <?xml version="1.0" encoding="UTF-8"?>

2 "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

4

5

6

7

8 resultType="Product">

9 SELECT * from tb_product where id IN (10 SELECT product_id FROM tb_ordersitem WHERE orders_id = #{id}11

14 )15

16

⑤多对多关联查询测试:

1 /**

2 * 多对多3 */

4 @Test5 public voidfindOrdersTest(){6

7 //1、通过工具类生成SqlSession对象

8 SqlSession session =MybatisUtils.getSession();9

10 //2、查询id为1的订单中的商品信息

11 Orders orders = session.selectOne("com.itheima.mapper.OrdersMapper.findOrdersWithPorduct", 1);12

13 //3、输出查询结果信息

14 System.out.println(orders);15

16 //4、关闭SqlSession

17 session.close();18 }

⑥执行结果:

b6fe3b9c100e024a646d99955120dc39.png

个人总结:

Mybatis的关联映射很好地模拟了数据库多表查询,感觉很方便,初学还不太熟悉,应该多操作,多理解!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值