关闭

hibernate5(9)注解映射[1]多对一单向关联

标签: hibernate
4050人阅读 评论(3) 收藏 举报
分类:

在博客网站中,我们可能需要从某一篇文章找到其所关联的作者,这就需要从文章方建立起对用户的关联,即是多对一的映射关系。
现在先看一个配置实例:我们的文章实体类

package com.zeng.model;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Lob;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;

@Table(name = "t_article")
@Entity
public class Article {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Integer id;
    @Lob//数据可能会非常长,映射为数据库支持的“大对象”
    private String content;
    /**
     * @ManyToOne 使用此标签建立多对一关联,此属性在“多”方使用注解在我们的“一”方属性上
     * @cascade 指定级联操作,以数组方式指定,如果只有一个,可以省略“{}”
     * @fetch 定义抓取策略
     * @optional 定义是否为必需属性,如果为必需(false),但在持久化时user = null,则会持久化失败
     * @targetEntity 目标关联对象,默认为被注解属性所在类
     */
    @ManyToOne(cascade ={CascadeType.ALL},fetch = FetchType.LAZY,optional = false,targetEntity = User.class)
    private User user;
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getContent() {
        return content;
    }
    public void setContent(String content) {
        this.content = content;
    }
    public User getUser() {
        return user;
    }
    public void setUser(User user) {
        this.user = user;
    }
}

因为这里是单向关联,所以我们无须在在User类中建立对文章的关联属性

接下来编写我们的测试类

package com.zeng.test;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.zeng.model.Article;
import com.zeng.model.User;

public class Test2 {
    private static ApplicationContext ac;
    private static SessionFactory sessionFactory;
    private Session session;
    private Transaction transaction;
    @BeforeClass//在测试类初始化时调用此方法,完成静态对象的初始化
    public static void before(){
        ac = new ClassPathXmlApplicationContext("spring-datasource.xml");
        sessionFactory = (SessionFactory) ac.getBean("sessionFactory");
    }
    @Before//每一个被注解Test方法在调用前都会调用此方法一次
    public void setup(){//建立针对我们当前测试方法的的会话和事务
        session = sessionFactory.openSession();
        transaction = session.beginTransaction();
    }
    //测试级联关系映射注解配置:多对一单向关联
    @Test
    public void test1(){
        User user = new User();
        user.setName("name1");
        Article article = new Article();
        article.setContent("content1");
        article.setUser(user);//建立级联关系
        session.save(article);//注意这里我们没有保存我们的user对象
    }

    @After//每一个被注解Test方法在调用后都会调用此方法一次
    public void teardown(){
        transaction.commit();
        session.clear();
        session.close();
    }
    @After//在类销毁时调用一次
    public void after(){
        sessionFactory.close();
    }

}

调用上面测试方法,我们会发现,hibernate帮我们在上篇文章已建立User类的基础上,又帮我们创建了t_article数据表:
mysql> desc t_article;
+———+————–+——+—–+———+—————-+
| Field | Type | Null | Key | Default | Extra |
+———+————–+——+—–+———+—————-+
| id | int(11) | NO | PRI | NULL | auto_increment |
| content | varchar(255) | YES | | NULL | |
| user_id | int(11) | NO | MUL | NULL | |
+———+————–+——+—–+———+—————-+
3 rows in set (0.00 sec)

然后我们查看用户表和文章表,会看到:

mysql> select * from t_user;
+—-+——-+
| id | name |
+—-+——-+
| 1 | name1 |
+—-+——-+
1 row in set (0.00 sec)

mysql> select * from t_article;
+—-+———-+———+
| id | content | user_id |
+—-+———-+———+
| 1 | content1 | 1 |
+—-+———-+———+
1 row in set (0.00 sec)
可以看到,这里我们的user_id和user表的新建记录id是对应的。

看完实例,下面我们针对配置的属性进行具体分析:

1. cascade属性

属性 说明
CascadeType.MERGE 级联更新:若user属性修改了那么article对象保存/更新时同时修改user在数据库里的属性值
CascadeType.PERSIST 级联保存:对article对象保存时也对user里的对象也会保存。
CascadeType.REFRESH 级联刷新:获取article对象里也同时也重新获取最新的user时的对象。即会重新查询数据库里的最新数据
CascadeType.REMOVE 级联删除:对article对象删除也会使对应user的象删除
CascadeType.ALL 包含PERSIST, MERGE, REMOVE, REFRESH, DETACH等;

级联属性对于一方和多方的作用效果是不一样的。经测试发现,在多对一中,多方使用CascadeType.PERSIST无法级联保存对象,必须使用CascadeType.ALL。而级联删除既可使用CascadeType.REMOVE也可使用CascadeType.ALL
对于上述方法,如果我们没有设置级联保存,在我们保存文章对象时,用户对象自然不会持久化到数据库,这时候会报错:

org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: com.zeng.model.User

在我们提交事务的时候,hibernate总会flush(清理)我们的session缓存,所谓清理,是指hibernate按照持久化对象的属性变化来同步更新数据库,当发现我们的article对象引用了临时对象user,而article.user.id = null,会判断user对象是瞬时的Transient,这个我们要持久化到数据库中的article对象发生冲突,因此会保存失败。这里我们也意在说明,关系直接的级联映射是通过用户对象标识符id来确认的。意思是说,即使article.user.其它属性全为null,但只要article.user.id在数据库中有相关记录(saved)这时就能建立两者的级联关系了。

另一方面,如果我们习惯了xxx.htm.xml的方式来配置我们的实体映射关系,那我们必然对hibernate的级联属性更加熟悉,这时我们可以通过@Cascade({org.hibernate.annotations.CascadeType.SAVE_UPDATE})来使用hibernate内置级联属性。关于hibernate的内置级联属性常见有:

属性名 说明
save-update 级联保存(load以后如果子对象发生了更新,也会级联更新)。 但它不会级联删除
delete 级联删除, 但不具备级联保存和更新
all-delete-orphan 在解除父子关系时,自动删除不属于父对象的子对象, 也支持级联删除和级联保存更新。
all 级联删除, 级联更新,但解除父子关系时不会自动删除子对象。
delete-orphan 删除所有和当前对象解除关联关系的对象

2. @JoinColumn

它的具体值可参照下表

属性 默认值 说明
columnDefinition JPA 使用最少量 SQL 创建一个数据库表列。如果需要使用更多指定选项创建列,将 columnDefinition 设置为在针对列生成 DDL 时希望 JPA 使用的 String SQL 片断。
insertable true 默认情况下,JPA 持续性提供程序假设它可以插入到所有表列中。如果该列为只读,请将 insertable 设置为 false。
name 默认值 如果使用一个连接列,则 JPA 持续性提供程序假设外键列的名称是以下名称的连接:
1. 引用关系属性的名称 +“”+ 被引用的主键列的名称。
2. 引用实体的字段名称 +“
”+ 被引用的主键列的名称。
3. 如果实体中没有这样的引用关系属性或字段(请参阅 @JoinTable),则连接列名称格式化为以下名称的连接:实体名称 +“_”+ 被引用的主键列的名称。这是外键列的名称。如果连接针对“一对一”或“多对一”实体关系,则该列位于源实体的表中。如果连接针对“多对多”实体关系,则该列位于连接表(请参阅 @JoinTable)中。
4. 如果连接列名难于处理、是一个保留字、与预先存在的数据模型不兼容或作为数据库中的列名无效,请将 name 设置为所需的 String 列名。
nullable true 默认情况下,JPA 持续性提供程序假设允许所有列包含空值。如果不允许该列包含空值,请将nullable 设置为 false。
referencedColumnName 如果使用一个连接列,则 JPA 持续性提供程序假设在实体关系中,被引用的列名是被引用的主键列的名称。如果在连接表(请参阅 @JoinTable)中使用,则被引用的键列位于拥有实体(如果连接是反向连接定义的一部分,则为反向实体)的实体表中。要指定其他列名,请将 referencedColumnName 设置为所需的 String 列名。
table JPA 持续性提供程序假设实体的所有持久字段存储到一个名称为实体类名称的数据库表中(请参阅 @Table)。如果该列与辅助表关联(请参阅 @SecondaryTable),请将 name 设置为相应辅助表名称的 String 名称
unique false 默认情况下,JPA 持续性提供程序假设允许所有列包含重复值。如果不允许该列包含重复值,请将 unique 设置为 true。
updatable true 默认情况下,JPA 持续性提供程序假设它可以更新所有表列。如果该列为只读,则将 updatable 设置为 false

参考:http://blog.sina.com.cn/s/blog_4bc179a80100kd0k.html

1
0
查看评论

hibernate5(10)注解映射[2]一对多单向关联

一对多单向关联映射在实际的博客网站中,用户肯定需要获取自己所写的文章,这时可以建立用户(一)对文章(多)的单向关联映射。 先来看我们的一方配置实例package com.zeng.model;import java.util.Set;import javax.persistence.Cascade...
  • qwe6112071
  • qwe6112071
  • 2016-04-07 09:26
  • 5972

使用Hibernate注解来配置多对一单向的三种方法

多对一单向(数据库设计,多在在多方设计外键)          数据库设计:主键列不可分,联合主键不可有部分依赖,不能存在传递依赖      ...
  • gy1055277934
  • gy1055277934
  • 2015-10-09 14:56
  • 2521

hibernate的注解方式如何实现级联删除

我们都知道hibernate是面向对象的持久化技术。说到删除肯定是这个方法了session.delete(Obj);但是注解是怎么配置才能实现删除呢?本人在学习途中,由此遇到难处,总是无法实现,不知道问题出在哪里。后就找度娘了。找到解决之法了。就此分享一下。废话不多说。上干货。@OneToMany(...
  • u013410747
  • u013410747
  • 2015-09-25 05:08
  • 4502

Hibernate的关联关系注解映射(一对一、一对多、多对一、多对多、自连接)

1. 一对多关系: 在一的一方添加注解@OneToMany(targetEntity=Goods.class,cascade=CascadeType.ALL),指定cascade为all,即交由多的一方控制;在多的一方添加注解@ManyToOne(targetEntity=GoodsClass.cl...
  • baidu_28283827
  • baidu_28283827
  • 2016-10-11 16:28
  • 4164

Hibernate级联操作 注解

Hibernate级联操作 注解。如果设在many一端的<many-to-one>标签里,就是在删除many一端的数据时,会试图删除one一端的数据,如果仍然有many外键引用one,就会报“存在子记录”的错误;如果在one的一端同时也设置了cascade=“delete”属性,就会发生...
  • a442180673
  • a442180673
  • 2013-10-14 11:04
  • 9619

Hibernate----@Annotation----一对多----级联

一对多,双向,"一"的一方   Java代码   package com.pegasus.domain;      import java.util.Has...
  • z69183787
  • z69183787
  • 2012-11-18 19:39
  • 8000

Hibernate4 注解配置实现一对多级联删除

用了hibernate有一段时间了,不过总是写很简单的功能,今天看了一下hibernate的级联删除,发现网上有很多代码已经过时了,即使没有过时的也有许多坑没有说明,在踩了n个坑后终于实现了hibernate的级联删除。 我们以产品类型ProductType类和产品Product类为例,一个产品类型...
  • W895972478
  • W895972478
  • 2015-08-03 20:53
  • 8041

hibernate双向多对多关联映射(注解版)

  • 2017-05-07 17:41
  • 16KB
  • 下载

Hibernate4注解详解之多对多对象映射

3.多对多(在多对多的使用上,建议使用表间关联方式,使用外键关联冗余数据较为严重)        1.1多对多外键关联          Test和SubTes...
  • beadle233
  • beadle233
  • 2015-04-01 14:13
  • 915

Hibernate中使用多对多映射注解

hibernateannotation注解方式来处理映射关系 在hibernate中,通常配置对象关系映射关系有两种,一种是基于xml的方式,另一种是基于annotation的注解方式,熟话说,萝卜青菜,可有所爱,每个人都有自己喜欢的配置方式,我在试了这两种方式以后,发现使用annotation的方...
  • JikAK1153
  • JikAK1153
  • 2015-02-17 11:18
  • 4668
    个人资料
    • 访问:334008次
    • 积分:4653
    • 等级:
    • 排名:第7455名
    • 原创:132篇
    • 转载:9篇
    • 译文:0篇
    • 评论:64条
    博客专栏
    最新评论