CRUD

C:Create

  Cascade(Cascade不影响读取,即get和load)。

  数据库中进行的操作,无非就是CRUD,在hibernate中也提供了进行CRUD的操作。

  在many-to-one时,明显已经设置了关系,可以使用hibernate的save()进行数据的保存,但是因为存在关系,所以必须先在对象中把对应的引用或者数据传递进去。也就是说如果存在user和group两个对象,user中存在一个group对象,那么必须通过setter方法把实例化后的group对象的引用传递到user对象中。在把数据保存到数据库的时候,也要先把引用对象的数据插入到数据库,在插入另一个对象。在这里的话就是先把save(g),在save(u)。

  在默认情况下,如果不保存引用的对象,而直接保存另一个对象,即不将group的数据保存到数据库中,就直接执行save(u),那么是会报错的,因为在执行save(g)的时候,g处于瞬态,也就是在数据库中并没有存储,那么user对象中的group引用的数据就无法插入到数据库中,那么就会报错。

  那如果想在把user的数据插入到数据库的时候,同时把group对象的数据也插入到数据库的时候,就要用到级联(cascade)操作了。级联操作是在使用注解的时候使用的。不管是one2one、one2many、many2one还是many2many,通过查看对应的api文档,都会发现有cascade这么一个元素,这个元素就是来进行级联操作的。cascade是一个CascadeType数组,CascadeType有如下几个参数:

All

对一个对象进行任意持久化操作的时候,都会在关联的对象中进行级联操作。也就是说,对user对象进行CRUD时,group也会进行对应的操作。

Meger

调用meger方法的时候进行级联操作。

Persist

调用persist方法的时候进行级联操作。

Refresh

调用refresh方法的时候进行级联操作。

Remove

调用delete方法的时候进行级联操作。

  具体的实际操作请看api文档。

  要注意的是,Cascade并不是非用不可。只是使用cascade时候会给我们带来一些方便,如果当业务逻辑比较复杂的时候,别执意一定要使用cascade,别忘了还可以先save(g),在save(u),这样逻辑是很清晰的。

  因为每个关系映射的注解都存在cascade这个属性,那么在进行操作的时候,一定要注意对应的关系映射的注解中是否设置好了cascade。如想通过添加user的时候直接把group的数据添加到数据库时,要在user类中的关系映射中指定cascade属性;想通过添加group的时候直接添加user,就必须在group类中的关系映射中设置好cascade属性,还要注意,在设置完关系映射的关系,还要注意在user中通过setGroup把user与group的关系设置进行,不然在数据库是无法插入数据的。

规律:双向关系在程序中要设定双向关联。

R:Read

  在进行数据的读取时,cascade设置的级联关系对get和load是不会有影响的,在many-to-one中,不管是否设置cascade,在进行get或者load的时候,都会把关联字段给取出来。One-to-many中,进行get或者load的时候,不会把关联字段去出来。按我们的逻辑想,当我们要取出多的一方的数据时,当然会顺带把数据少的一方给取出来。就好像我们在取出user对象的信息的时候,一般也会把user所在的group查询出来。而我们在提取少的一方的数据的时候,是不会把数据多的一方取出来的。比如我们只是想知道group的信息时,是不需要把user中一大堆的数据提取出来的。

  当然这也不是一定的,那么如果想修改这种默认的设置,就可以使用feath来进行设置。在每个关系映射中,也会存在feach这么一个元素,里面存放一个FeachType数组,数组里有两个参数:EAGER、LAZY。

  EAGER是指设置为当进行get或者load操作的时候,进行级联操作。

  LAZY则表示进行get或者load操作时,不进行级联操作。

  many-to-one中,feach默认设置为EAGER,one-to-many中则设置为LAZY。在把fetch设置为LAZY后,进行的get或者load操作是不会进行级联操作的,而当我们需要使用到关联到的属性的信息的时候,在调用具体的getter方法时,会往数据库中再发一条请求,此时就会进行级联操作,把两者的信息都取出来,但要记住具体的操作要在session关闭之前执行,即在session.getTransaction().commit()之前执行。否则当session关闭时,就读取不出数据库的数据了。

注意,在多对多中不要两边都把fetch设置为EAGER。

  EAGER、LAZY的区别:

  用load加载user,执行user.getGroup().getName()。设置为LAZY时,先不管关联的部分,把user先取出来,等到调用了user.getGroup().getName()时再把关联的取出来。设置为EVGER时,会先把关联的取出来,又因为user和group中都把fetch设置成EAGER,所以这个时候会再取出单独的user。

U:Update

要进行更新时,有两种方式:

第一种是直接将load或者get出来的数据通过setter方法进行重新设置,那么在调用session.getTransaction().commit()的时候就会到数据库中去执行更新的操作,只是调用了几个setter方法,就会发出几条update语句。
第二种是将获得的数据在处于托管的状态下进行修改,然后再另一个session中调用session.update(u)去执行。

D:Delete

进行删除的时候,因为在cascade里设置了CascadeType.ALL,所以当删除某张表的某一行数据记录时,会把级联的另一张表的数据删除,而另一张表级联的数据又会删除了其他级联的数据,这样会导致删除了很多不想删除的数据。那么有如下的解决方法:

修改cascade的数值,改为除了ALL和REMOVE的即可。
(经过测试优点问题)在不方便修改级联操作的时候;可以选择先打破级联关系。如存在user和group两个表,那么像删除user表的某一行记录时,可以先设置user.setGroup(null),这样就打破了级联关系,再删除数据的时候就不会误删了。
使用HQL,即调用session.createQuery(“String sql”).

一般one-to-many中,把one一方删除之后,many中对应的数据也该删除掉,不然就变为垃圾数据了。

Published by

风君子

独自遨游何稽首 揭天掀地慰生平

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注