Spring Hibernate 5 快速入门(二) 连表操作 OneToOne

1 概述

所有的代码都保证是可运行的完整project, 代码分享在github.com, 平时工作中也可以作为模板代码ctrl+c用.
https://github.com/ZhongjunTian/spring-hibernate-examples
本章内容在 intermediate-hibernate-1 文件夹下, 执行App.java即可运行例子.

最基本连表关系:OneToOne关系

一对一的关系是最基本的表与表之间的关系。
下面假设我们有3个表,分别为Person, Account, Address.
因为我们定义了他们之间的关系为一对一的关系,所以每个Person只有一个Account和一个Address.

2. Table定义

create table person_table (
        id bigint generated by default as identity,
        name varchar(255),
        account_id bigint
        );
create table account_table (
        id bigint generated by default as identity,
        balance decimal(19,2)
        );
create table address_table (
        id bigint generated by default as identity,
        city varchar(255),
        person_id bigint
        );

这里Person和Account之间的OneToOne关系, 由Person拥有account的id,也就是account_id,
而Person和Address之间的关系, 我们让address拥有person的id, 也就是person_id (这样做是为了展示两种情况的代码)

2.1 Person类

首先我们会创建三个@Entity类 Person.java Account.java Address.java
Person有如下内容

@Entity(name="PersonTable")
public class Person {
    @Id
    @GeneratedValue
    public Long id;

    public String name;
    
    //Person表拥有account_id,而Account表则没有person_id,这里与Address相反
    @OneToOne(cascade = CascadeType.ALL)
    public Account account;

    //Address表拥有person_id
    @OneToOne(mappedBy = "owner")
    @JoinColumn
    public Address address;
    ...
 }
@Entity.name

这里为了避免读者在下文中混淆java的Person类和Person表, 我特地让类和表的名字不一样. name标明这个Entity对应 Person_table表

@Id

主键

@OneToOne

表面Account是一个Entity, 并且Person和Account是一一对应的关系, 任何一个Person最多有一个Account.

cascade (可选)

级联(串联)操作, 默认是不执行任何级联操作.
什么是级联操作? 这里用伪代码更好解释,

    //假设我们从repository读取到了person   
    person = personRepository.find(1L);
    person.name = "李四"
    person.account.balance += 100;
    
    personRepository.save(person);
    personRepository.delete(person);

当你 更新/删除 person的时候, Hibernate并不能确定你是要操作person还是person和account两个一起操作. 有点类似于古代的连坐制度, 当person被xx的时候account也要被xx.
我们这里为了做个示范, 就直接级联所有操作了. 具体还有很多种, 常用的是Persist, Merge, Remove 和 All

而Address就没有设置cascade, 因此在使用的时候Person和address要分开保存, 详见最后面的public void oneToOneNoCascading1()

mappedBy

Mapped标明Person是无辜群众, 没有address的任何信息, 另一个Address表拥有外键(或者更专业的说法是 关系的拥有者为Address ).
并且由java的类Address.owner这个成员变量维护他们之间的关系.

隐式的Long accountId

这里有个小细节, 虽然PersonTable表里面有外键account_id但是Entity里面却没有,
实际上Hibernate会默认 public Account account; 的外键在PersonTable表里面为account_id.
如果这里是 public Account xx; 那么hibernate会认为PersonTable表里面有外键xx_id;

2.2 Account类

@Entity(name = "AccountTable")
public class Account {
    @Id
    @GeneratedValue
    public Long id;

    public BigDecimal balance;//余额
    ...
    }

因为Person是关系的拥有者, 所以这个类就很简单了.
并且, 我们没有在Account类里面定义Person成员, Hibernate官方文档里面称这种关系为 unidirectional,
另一种关系为bi-directional双向关系, Person和Address的关系就是双向的.

2.3 Address类

@Entity(name = "AddressTable")
public class Address {
    @Id
    @GeneratedValue
    public Long id;

    public String city;

    @OneToOne
    @JoinColumn(name = "person_id") //如果没有这个就会认为外键为 PersonTable 表的 owner_id列
    public Person owner;
    ...
}
@JoinColumn

标明外键的名字, 如果没有这个就会默认外键为AddressTable表的owner_id

3. 示范代码


@Service
public class Demo {
    @Autowired
    PersonRepository personRepository;
    @Autowired
    AccountRepository accountRepository;

    @Transactional  //one to one relationship
    public void oneToOneCascading1() {
        System.out.println("*******************开始");
        //先创建account
        Account account = Account.createAccount();

        //再把person绑定address
        Person person = Person.createPerson();
        person.account = account;

        person = personRepository.save(person);
        System.out.println("直接同时创建 person 和 account: "+person);//
    }

    @Transactional
    public void oneToOneCascading2() {
        System.out.println("*******************开始");
        //创建account
        Account account = Account.createAccount();
        account = accountRepository.save(account);

        System.out.println("先创建account: "+account);//
        //把person绑定address
        Person person = Person.createPerson();
        person.account = account;

        person = personRepository.save(person);
        System.out.println("再创建person, 同时绑定了前面的address: "+person);//
    }

    @Transactional
    public void oneToOneNocascading1() {
        System.out.println("*******************开始");
        //把person绑定address
        Person person = Person.createPerson();
        person = personRepository.save(person);
        System.out.println("先创建person: "+person);//

        //创建account
        Account account = Account.createAccount();
        account = accountRepository.save(account);
        System.out.println("再创建account: "+account);//

        person.account = account;
        person = personRepository.save(person);
        System.out.println("再更新person: "+person);//

    }

}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,047评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,807评论 3 386
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,501评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,839评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,951评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,117评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,188评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,929评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,372评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,679评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,837评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,536评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,168评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,886评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,129评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,665评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,739评论 2 351

推荐阅读更多精彩内容