《Java从入门到放弃》入门篇:hibernate中的多表对应关系(二)
前一篇讲完了一对多的关系,通过与JDBC对比应该能发现,是不是比JDBC简单了很多?
我们只需要把对象只间的包含或对应关系理清楚,完全不用我们自己来写SQL语句。所以使用hibernate框架后,我们的关注重点是业务逻辑,所有的SQL语句都不用再操心了。
上次忘记说明,如果使用增、删、改的操作,我们还需要再引入一个Transaction对象。代码如下所示:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
public static void main(String[] args) { Session session = HibernateSessionFactory.getSession(); Transaction tx = session.beginTransaction(); try { Author author = new Author( "刘皇叔" , "sb250" ); session.save(author); tx.commit(); //提交 System.out.println( "保存成功" ); } catch (Exception e) { tx.rollback(); //回滚 } HibernateSessionFactory.closeSession(); } |
知道数据库中事务的客官应该对这个对象不陌生吧。所以执行了session对象的增、删、改后,一定要记得使用transaction对象进行提交。如果某个业务有多次数据的操作,那么一定记得使用事务。
接下来,我们继续上次未完成的任务。
二、多一对映射关系
上次我们已经生成了作者和博客表的关系,从作者的角度来看,作者对应博客是一对多,而从博客的角度来看,博客对应作者是多对一。所以博客实体类中的代码如下:
1
2
3
4
5
6
7
8
9
10
|
public class Blog implements java.io.Serializable { private Integer id; private Author author; //相当于数据库中的外键引用 private String title; private String content; private Date createTime; private String type; //封装的get和set方法略 } |
blog的映射文件中代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
< class name = "com.pxy.entity.Blog" table = "blog" catalog = "blogdb" > < id name = "id" type = "java.lang.Integer" > < column name = "id" /> < generator class = "native" /> </ id > < many-to-one name = "author" class = "com.pxy.entity.Author" fetch = "select" > < column name = "author_id" /> </ many-to-one > < property name = "title" type = "java.lang.String" > < column name = "title" length = "30" not-null = "true" /> </ property > < property name = "content" type = "java.lang.String" > < column name = "content" length = "500" /> </ property > < property name = "createTime" type = "java.util.Date" > < column name = "create_time" length = "10" /> </ property > < property name = "type" type = "java.lang.String" > < column name = "type" length = "20" /> </ property > </ class > |
里面的many-to-one就是多对一的关系。我们同样先不做任何修改,来查询一篇博客看看效果。
1
2
3
4
5
6
7
8
9
|
public static void main(String[] args) { Session session = HibernateSessionFactory.getSession(); Blog blog = (Blog)session.get(Blog. class , 6 ); System.out.println( "标题:" +blog.getTitle()); System.out.println( "内容:" +blog.getContent()); System.out.println( "作者:" +blog.getAuthor().getUsername()); HibernateSessionFactory.closeSession(); } |
结果如下:
接下来,我们来聊五毛钱的与映射关系有关的几个属性:not-null、fetch、lazy、cascade、inverse。
1)not-null
从名字就能看出来,这个表示非空,不用多说吧。
2)fetch
表示获取数据的方式,对应的值有两个:select和join。默认是select。它们的差别我们可以通过生成的SQL语句来看看。
select的结果如上图,默认只查询blog的内容,需要使用映射的author时,再次到数据库中查询。
我们将Blog的映射文件中many-to-one中的fetch的值设置为join,结果如下图:
区别是不是很明显!!!
使用join后,默认就使用多表联合的方式查询了所有的数据。
3)lazy
接下来,我们先把fetch的值还原为select。然后再把lazy的分别设置为proxy和false看效果对比。
左图为设置lazy的值为false(实时加载,实体类中包含的所有对象都一次性查询出来),
右图为设置lazy的值为proxy(延时加载,默认只查询blog的数据,当需要使用其中包含的对象时再去数据库查询)。
4)cascade
表示执行增、删、改时的级联操作。其值有:none、save-update、delete、delete-orphan、all、all-delete-orphan。
cascade属性 |
描 述 |
none |
当Session操纵当前对象时,忽略其关联对象。它是cascade属性的默认值 |
save-update |
当通过Session的save()、update()及saveOrUpdate()方法来保存或更新当前对象时,级联保存关联的临时对象,并且级联更新所有关联的游离对象 |
delete |
当通过Session的delete()方法删除当前对象时,会级联删除关联的对象 |
all |
包含save-update、delete的行为 |
delete-orphan |
删除和当前对象解除关联关系的所有对象。 即当一个节点在对象图中成为孤儿节点时,删除该节点 |
all-delete-orphan |
包含all和delete-orphan的行为 |
接下来,我们演示一下默认值和save-update,其它的值,各位客官可以自行试验哈。
4.1)不设置cascade属性
编码如下代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
public static void main(String[] args) { Session session = HibernateSessionFactory.getSession(); Transaction tx = session.beginTransaction(); //创建作者和博客对象 Author author = new Author( "刘皇叔" , "sb250" ); Blog blog = new Blog( "论持久战" ); //相互关联 author.getBlogs().add(blog); blog.setAuthor(author); //保存作者或者保存博客 session.save(author); //session.save(blog); //提交数据 tx.commit(); HibernateSessionFactory.closeSession(); } |
运行后查看结果,可以发现,只添加了作者或者博客(注意看代码,只添加作者或者只添加博客)。
4.2)把blog的映射文件和author的映射文件中的cascade属性设置为save-update
Test中的代码不做任何修改,再次运行看效果。
现在的添加操作就进行了级联,虽然我们只保存作者,或者只保存博客,但Session发现它内部还包含新的对象时就会级联更新。
5)inverse
表示是否由关联对象来主控级联关系。一般设置在一对多中的”一方“。看4.2图中的set标签中包含有inverse属性。
接下来,我们把inverse设置为false。
是不是发现多了一个update?
其实很好理解,因为把inverse设置为false后,表示没有主控方了,A执行了控制B的代码后,B也会再次执行控制A的代码,所以blog对象会发现:“哟,我还关联有author对象,那我必须要更新一下它的ID”。
今天的内容虽然简单,但大伙一定要把每个属性及每个属性的值都多练习几遍,不然很容易弄混效果。