hibernate mysql arraylist_Hibernate学习笔记(四) --- 映射基本数据类型的List集合

集合按其内元素的数据类型分为两种:基本数据类型集合及复杂对象类型集合,Hibernate对于两类集合提供不同的映射方式。(在类上以@Embeddable注解的复杂对象数据类型处理方式同基本数据类型集合一致,此处只讨论以@Entity注解的对象)

对于基本数据类型集合,直接在属性上添加@ElementCollection即可,Hibernate在存储数据时会自动为该集合单独创建一张表,这个表包含一个指向该属性所在类ID的外键

看一个例子,假如之前的Movie数据类要新增加一个actors属性,标识该电影的演员表(只保存姓名),更改后的Movie.java代码如下:

1 packagestudy.hibernate.model;2

3 importjava.util.ArrayList;4 importjava.util.List;5

6 importjavax.persistence.Column;7 importjavax.persistence.Convert;8 importjavax.persistence.ElementCollection;9 importjavax.persistence.Embeddable;10 importjavax.persistence.Entity;11 importjavax.persistence.EnumType;12 importjavax.persistence.Enumerated;13 importjavax.persistence.Id;14 importjavax.persistence.Table;15

16 importorg.hibernate.annotations.Type;17

18 /**

19 * 电影数据类20 *@authoryaoyao21 *22 */

23 @Entity24 @Table(name="MOVIE")25 public classMovie {26 @Id27 @Column(name="MOVIE_ID")28 private intid;29

30 @Column(name="NAME")31 @Type(type="string")32 privateString name;33

34 @Column(name="DESCRIPTION")35 @Type(type="text")36 privateString description;37

38 @Column(name="TYPE")39 @Convert(converter=MovieTypeConvertor.class)40 privateMovieType type;41

42 @Column(name="ACTORS")43 @ElementCollection44 private List actors = new ArrayList();45

46 public intgetId() {47 returnid;48 }49

50 public void setId(intid) {51 this.id =id;52 }53

54 publicString getName() {55 returnname;56 }57

58 public voidsetName(String name) {59 this.name =name;60 }61

62 publicString getDescription() {63 returndescription;64 }65

66 public voidsetDescription(String description) {67 this.description =description;68 }69

70 publicMovieType getType() {71 returntype;72 }73

74 public voidsetType(MovieType type) {75 this.type =type;76 }77

78 public ListgetActors() {79 returnactors;80 }81

82 public void setActors(Listactors) {83 this.actors =actors;84 }85

86 }

可以看到,新增了一个List的属性,并对该属性添加了@ElementCollection的注解。

在启动程序中对该属性赋值并保存数据到数据库:

1 Movie movie = newMovie();2 movie.setId(1);3 movie.setName("速度与激情8");4 movie.setDescription("多米尼克(范·迪塞尔 Vin Diesel 饰)与莱蒂(米歇尔·罗德里格兹 Michelle Rodriguez 饰)共度蜜月,布莱恩与米娅退出了赛车界,这支曾环游世界的顶级飞车家族队伍的生活正渐趋平淡。然而,一位神秘女子Cipher(查理兹·塞隆 Charlize T heron 饰)的出现,令整个队伍卷入信任与背叛的危机,面临前所未有的考验。");5 movie.setType(MovieType.CARTOON);6

7 List actors = new ArrayList();8 actors.add("范·迪塞尔");9 actors.add("米歇尔·罗德里格兹");10 movie.setActors(actors);11

12 session.beginTransaction();13 session.save(movie);14 session.getTransaction().commit();

从Hibernate日志中可以看出,在启动时创建了两张表:一张是Movie,这是我们显式指定要创建的表,另一张是Movie_actors,这一张是Hibernate自己创建的,我们并没有在哪里配置要创建这个表

1 Hibernate: drop table if existsMOVIE2 Hibernate: drop table if existsMovie_actors3

4 Hibernate: create table MOVIE (MOVIE_ID integer not null, DESCRIPTION longtext, NAME varchar(255), TYPE varchar(255), primary key (MOVIE_ID)) engine=MyISAM5

6 Hibernate: create table Movie_actors (Movie_MOVIE_ID integer not null, ACTORS varchar(255)) engine=MyISAM7

8 Hibernate: alter table Movie_actors add constraint FKcx4l8fplo42ncmh0hpoc6oyvl foreign key (Movie_MOVIE_ID) references MOVIE (MOVIE_ID)

查看数据库,发现确认多了一张Movie_actors的表,而且该表中有两条数据,存储代码中添加的两个演员的名称

1 mysql>show tables;2 +--------------------+

3 | Tables_in_movie_db |

4 +--------------------+

5 | movie |

6 | movie_actors |

7 +--------------------+

8 2 rows in set (0.00sec)9

10 mysql> select * frommovie_actors;11 +----------------+----------------------------+

12 | Movie_MOVIE_ID | ACTORS |

13 +----------------+----------------------------+

14 | 1 | 范·迪塞尔 |

15 | 1 | 米歇尔·罗德里格兹 |

16 +----------------+----------------------------+

17 2 rows in set (0.00 sec)

通过@ElementCollection注解映射的集合,在对该集合进行数据更新时效率比较低,因为Hibernate会将关联表(Movie_actors)中相关的数据全部删除然后依次重新添加,这样在集合中数据比较多的时候,执行的SQL语句会变的非常多

假如现在要向演员列表中新增一个名字并保存到数据库:

1 session.beginTransaction();2 movie.getActors().add("查理兹·塞隆");3 session.update(movie);4 session.getTransaction().commit();

查看Hibernate日志,发现它是将Movie_actors表中所有电影ID为1的数据全删除,然后再依次添加该电影所有的演员信息(三个插入语句)

1 Hibernate: delete from Movie_actors where Movie_MOVIE_ID=?2

3 Hibernate: insert into Movie_actors (Movie_MOVIE_ID, ACTORS) values(?, ?)4 Hibernate: insert into Movie_actors (Movie_MOVIE_ID, ACTORS) values(?, ?)5 Hibernate: insert into Movie_actors (Movie_MOVIE_ID, ACTORS) values (?, ?)

对于@ElementCollection注解效率低的问题,有一个不算太好的解决方案是同时引入@OrderColumn属性,该属性在关联表(Movie_actors)中会新增一列用于标识元素在集合中的位置,列名由该注解的name属性指定:

1 @Column(name="ACTORS")2 @ElementCollection3 @OrderColumn(name="position")4 private List actors = new ArrayList();

运行程序并查看数据库,发现Movie_actors表中多了一列position,其值即是对应元素在List集合中的位置:

1 mysql> select * frommovie_actors;2 +----------------+----------------------------+----------+

3 | Movie_MOVIE_ID | ACTORS | position |

4 +----------------+----------------------------+----------+

5 | 1 | 范·迪塞尔 | 0 |

6 | 1 | 米歇尔·罗德里格兹 | 1 |

7 | 1 | 查理兹·塞隆 | 2|

8 +----------------+----------------------------+----------+

9 3 rows in set (0.00 sec)

使用了@OrderColumn注解后,在对集合数据做更改时,并不会将所有相关数据都删除然后重新添加,而是会只删除、添加有变更的数据,对该数据之后位置的数据做更新操作:

1 session.beginTransaction();2 movie.getActors().remove(2);3 session.update(movie);4 session.getTransaction().commit();

1 Hibernate: delete from Movie_actors where Movie_MOVIE_ID=? and position=?

因此@OrderColumn并不能完全解决对集合元素更改操作效率低的问题,因为该方案只能在变更元素位于集合末尾的时候效率才比较高,如果操作的是集合头部的元素,则效率同没有使用该标注是差不多的

1 session.beginTransaction();2 movie.getActors().remove(0);3 session.update(movie);4 session.getTransaction().commit();

1 Hibernate: delete from Movie_actors where Movie_MOVIE_ID=? and position=?2 Hibernate: update Movie_actors set ACTORS=? where Movie_MOVIE_ID=? and position=?3 Hibernate: update Movie_actors set ACTORS=? where Movie_MOVIE_ID=? and position=?

综上,在映射集合元素时,可以添加@ElementCollection及@OrderColumn注解来完成映射工作,但需考虑不同场景下数据操作效率快慢的问题。个人建议,基本数据类型的集合使用@Convert注解来实现,这样不存在多个表的数据更新问题了

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值