本次实验环境:spring boot + spring data jpa + hibernate
本次实验用例:
人:
id
name
漂流瓶:
id
content
man
一个人可以抛多个漂流瓶,且抛出去之后通过人无法得到漂流瓶。一个漂流瓶只能由一个人抛,假设瓶中包含抛的人的信息,则可以通过漂流瓶得到人。
实际生活中,人和漂流瓶没有共生的关系,一方是否存在对另一方无任何影响,代码中可以通过字段冗余来模拟,但是本次试验的对象是一对多关系,漂流瓶表中包含指向人的字段man_id,如果对应的man的数据被删除了,则漂流瓶数据会发生异常,在本次试验中会碰到此问题,具体请看下文。
#Man类:
@Entity
@Table(name="t_12n_man")
public class Man {
@Id
@GeneratedValue
private Long id;
private String name;
//getter与setter省略
}
#Bottle类:
@Entity
@Table(name="t_12n_bottle")
public class Bottle {
@Id
@GeneratedValue
private Long id;
private String content;
@ManyToOne
@JoinColumn(name="man_id")
private Man man;
//getter与setter省略
}
#生成表
CRUD:
- 添加man,直接添加即可。
Man man = new Man();
man.setName("张三");
manDao.saveAndFlush(man); - 更新man,因为Man类中没有bottle相关的成员属性,直接更新时自动的生成的sql语句不包含bottle相关内容,不会对bottle表产生影响。
当然,如果man中包含其余字段,比如年龄,那么我们只把名字从“张三”改成“李四”,就该保证年龄与数据库中的原数据是一致的。所以先查询后更新。
Man man = manDao.findOne(1L);
man.setName("李四");
manDao.saveAndFlush(man); - 查询man,直接通过id或其他过滤条件查询即可,因为man中无bottle的成员变量,查询出来的数据只是man本身,在本例中查询返回结果就只有id和name。
- 删除man,若这个人没有抛任何漂流瓶,即bottle表中没有一条数据是和当前待删除的man有关连,则可直接删除。否则无法删除。
打断这种关联有两种方式,一:把bottle表中的man_id字段设置为null或其他人,二:就是干脆先删除这条bottle记录。 添加bottle,我们并没有设置cascde,所以可直接添加。
Bottle bottle = new Bottle();
bottle.setContent("拉拉拉拉拉拉啦阿拉啦啦");
Man man = manDao.findOne(2L);
bottle.setMan(man);
bottleDao.saveAndFlush(bottle);
如果设置了cascade,那么只能设置CascadeType.MERGE,但是设置MERGE的效果与不设置一致。
如果cascade中包括CascadeType.PERSIST,则每添加一个bottle必须添加一个新的man,才能保证不报错,即
Bottle bottle = new Bottle();
bottle.setContent("拉拉拉拉拉拉啦阿拉啦啦");
Man man = new Man();
bottle.setMan(man);
bottleDao.saveAndFlush(bottle);更新bottle,老生常谈,除了要变更的字段,其余字段的值必须与数据库中的原数据一致,如果不传数据库中的字段会被更新为null,包括man_id。
- 查询bottle,@ManyToOne默认为急加载,所以查询结果包括bottle自身的属性,也有相关联的man的属性。
- 删除bottle,没有设置cascade直接删除即可。同样设置CascadeType.REMOVE会导致删除bottle时级联删除man,如果此时该man在bottle表中其他某些记录仍有关系,就会报错。即使没有关连了,但是你删掉漂流瓶就连抛这个瓶子的人都删除了,逻辑上也说不过去。