0
点赞
收藏
分享

微信扫一扫

hibernate关联对象的增删改查------增


本文可作为,北京尚学堂马士兵hibernate课程的学习笔记。
这一节,我们看看hibernate关联关系的增删改查
就关联关系而已,咱们在上一节已经提了很多了,一对多,多对一,单向,双向...

其实咱们可以简单的说就是A与B,有关系。

hibernate关联对象的增删改查------增_数据库

至于他们到底是一对多,多对一,暂且不论。

咱们要讨论的是,如果我存储A,那么数据库里是否会有B;如果我删除A,那么与之相关的B是否也会删除;如果我更新了A,那么B是否会被更新;如果我查询出A,那么B是否也会被查询出来。


首先,咱们看一对多,多对一双向的例子。


还是我们上一节的例子,dream与person。


一个person有多个dream,而每一个dream只能属于一个person。


我们在配置xml时,让hibernate自动生成建表语句,并且每次都新生数据库。


<property name="hbm2ddl.auto">create</property>

实体类情况


@Entity
public class Person {
private int id;
private String name;
private Set<Dream> dreams=new HashSet<>();


@Id
@GeneratedValue
public int getId() {
return id;
}
@Column(name ="myname")
public String getName() {
return name;
}

@OneToMany(mappedBy="person")
public Set<Dream> getDreams() {
return dreams;
}//省略部分代码
}

@Entity
public class Dream {
private int id;
private String description;

private Person person;

@Id
@GeneratedValue
public int getId() {
return id;
}

@ManyToOne
@JoinColumn(name="personId")
public Person getPerson() {
return person;
} //省略部分代码
}


OK,两个类的关系已经很清楚了,双向多对一/一对多。


如果我们的测试代码如下:


//代码片1


public static void main(String[] args) {
Person p=new Person();
p.setName("dlf");

Dream d=new Dream();
d.setDescription("marry glt");
d.setPerson(p);

SessionFactory sessionFactory = new AnnotationConfiguration().configure().buildSessionFactory();
Session session = sessionFactory.getCurrentSession();
session.beginTransaction();

session.save(p);
session.save(d);

session.getTransaction().commit();
}



上面的代码是没有问题的,而且即使先save dream也OK。


那么现在问题来了


d.setPerson(p);


这句代码,已经说明了dream里有一个引用指向了person。


那么我可以在代码层次不save person么?


即只有一个


session.save(d);


答案是否定的,报下面的错误。


object references an unsaved transient instance - save the transient instance before flushing: com.bjsxt.hibernate.Person


因为在数据库保存dream的时候,person还没有保存,所以出错了。


上面的例子告诉我们,默认情况下:hibernate不会替我们存储"一"的那一方。


当我写到这块的时候,我忽然脑子一抽,又写下了下面的测试代码:


//代码片2
public static void main(String[] args) {
Dream d=new Dream();
d.setDescription("marry glt");

Person p=new Person();
p.setName("dlf");
p.getDreams().add(d);

SessionFactory sessionFactory = new AnnotationConfiguration().configure().buildSessionFactory();
Session session = sessionFactory.getCurrentSession();
session.beginTransaction();

session.save(p);

session.getTransaction().commit();

}

如果,我以"一"的那一方为主,上面的代码会是个什么情况?


答案是,

不报错,代码能正常执行,但是数据库里只有p的信息而没有d的信息。


上面的代码确实有点奇葩了,在上一节的时候,我们就已经达成了共识,

在处理关联关系时,数据库层面总是在多的那一方维护关系。


所以上面的代码,并不能保存dream。



上面也说了,是在默认情况下,那特殊情况呢?


我们看api文档

hibernate关联对象的增删改查------增_hibernate_02

hibernate关联对象的增删改查------增_级联_03



上面是manytoone这个元标签可以带的属性,cascade翻译成中文就是级联。他是caschdetype型的


而Caschdetype是enum型的。可以取六个值


我们最经常用的就是,all,persist与remove。


all的意思是,对这个对象的增删改四中操作都会影响到与之关联的那个对象。(关于查询的级联,由另一个属性管理)

persist的意思是,对这个对象的增加(save操作)会连带把与之关联的那个对象也sava了。

remove的意思就是,如果删除这个对象也会删除与之关联的那个对象。


OK看下面的改动


@ManyToOne(cascade={CascadeType.ALL})
@JoinColumn(name="personId")
public Person getPerson() {
return person;
}

此时,我们下面的代码,就能正常运行了,而且数据库里,两个对象都存储了,且外键关联也是OK的。


//代码片3
Person p=new Person();
p.setName("dlf");

Dream d=new Dream();
d.setDescription("marry glt");
d.setPerson(p);

session.save(d);



写到这,我的脑子又抽了,如果我给onetomany的那一方加上cascade会如何?


@OneToMany(mappedBy="person",cascade={CascadeType.ALL})
public Set<Dream> getDreams() {
return dreams;
}
测试代码:
Dream d=new Dream();
d.setDescription("marry glt");

Person p=new Person();
p.setName("dlf");
p.getDreams().add(d);

session.save(p);


cascade确实有用,此时数据库里已经有了dream,但是dream的外键是null。

为什么?因为dream里并没有关联person。


其实

,cascade这个东西也不是绝对的,如果关联关系比较麻烦,我们发现数据库里总是少存了一个对象,那就按照代码1的办法,直接存两次对象不就OK了。


谈点规律:


1 我们发现如果存储对象的时候,我们从多的一方操作是比较简单的。所以以后,尽量在多的一方操作。

2 为了符合逻辑,同时也不出错,一点两个对象之间的关系是双向的,那么在代码层次,就把两个的引用都设好,这样就不会出问题了。

3 之前说的,如果是双向的,设定mappedby。

举报

相关推荐

0 条评论