Jpa 注解详解 映射详解 一对多 多对一

Jpa映射详解

该博客例子均用 SpringBoot + Spring Data Jpa 实现

一、常用注解

这里主要介绍了最常用注解,实现POJO和数据库的隐射。

@Entity

对类注释。任何Hibernate映射对象都要有这个注释
持久层将对象映射到数据库,JPA是一种规范,Hibernate是一种实现,可以将POJO映射到数据库。这种类就叫Entity Bean

@Table

对类注释。通过它可以为实体指定表(talbe),目录(Catalog)和schema的名字

@ID

声明该属性为主键,指定类的主键

@GeneratedValue

指定主建的声明策略,自动生成主键

  • TABLE:数据库产生主键
  • IDENTITY:数据库自增长
  • SEQUENCR :通过数据库的序列产生主键
  • AUTO:默认选项

    @Column

    声明该属性与数据库字段的映射关系,Hibernate会自动匹配属性和字段名字相同的,@Column可以修改隐射值

    @Transitent

    若属性非数据库字段,则可以声明该属性与数据库字段的不产生映射关系

参考用例
# 配置 Hibernate 自动生成表
spring.jpa.properties.hibernate.hbm2ddl.auto=update

定义两个实体表,Author和Poetry,就将刚才所有的注解配置上,启动服务springboot 扫描注解@Entity后,会自动生成数据库表,最后我们查看下数据库表中的结构就知道答案了

Author

@Entity
@Table(name = "authorCN")
public class Author implements Serializable {

    private static final long serialVersionUID = 4074367019988114836L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    @Column(name = "p_name")
    private String name;

    @Column(name = "p_age")
    private Integer age;

    @Transient
    private String error;
 
    // getter and setter   
}

Poetry

@Entity
@Table
public class Poetry implements Serializable {

    private static final long serialVersionUID = -2743230230981482358L;

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    private Integer id;
    private String title;
    private String summary;
    private String content;

     // getter and setter 
}

image

查看数据库表,可以看到Poetry的字段,表明都是和属性一样的,而Author里面加了@Column注解的属性后,生成的字段名发生的改变,并且表名也有改变,@Transient下的属性并没有生成数据库表中的字段。

通过测试启动服务插入数据,我们可以查看主键的生成策略

    @Test
    public void testSavaData() {
        authorRepository.save(new Author("杜甫", 56));
        authorRepository.save(new Author("李白", 42));
        poetryRepository.save(new Poetry("八阵图", "咏怀诗", "功盖三分国,名高八阵图。江流石不转,遗恨失吞吴。"));
        poetryRepository.save(new Poetry("春望", "爱国诗", "国破山河在,城春草木深。感时花溅泪,恨别鸟惊心。烽火连三月,家书抵万金。白头搔更短,浑欲不胜簪。"));
        poetryRepository.save(new Poetry("静夜思", "思乡诗", "床前明月光,疑是地上霜。举头望明月,低头思故乡"));
    }

我们查看日志可以得知,因为在Poetry里面设置的生成策略是SEQUENCE,所以,在每次插入数据的时候,都有hibernate_sequence的更新。

Hibernate: insert into authorcn (p_age, p_name) values (?, ?)
Hibernate: insert into authorcn (p_age, p_name) values (?, ?)
Hibernate: select next_val as id_val from hibernate_sequence for update
Hibernate: update hibernate_sequence set next_val= ? where next_val=?
Hibernate: insert into poetry (content, summary, title, id) values (?, ?, ?, ?)
Hibernate: select next_val as id_val from hibernate_sequence for update
Hibernate: update hibernate_sequence set next_val= ? where next_val=?
Hibernate: insert into poetry (content, summary, title, id) values (?, ?, ?, ?)
Hibernate: select next_val as id_val from hibernate_sequence for update
Hibernate: update hibernate_sequence set next_val= ? where next_val=?
Hibernate: insert into poetry (content, summary, title, id) values (?, ?, ?, ?)

二、POJO之间的关系

(1)一对一关系

因为之前古诗和作者是多对一关系,所以呢,这里我要将一对一,我就创建了妻子的表,夫妻关系一对一,哈哈,古代我们也是一夫一妻制

在这之前,我偷偷的在数据库加了些测试数据,这个就不列出来了

@Entity
@Table
public class Wife implements Serializable {


    private static final long serialVersionUID = 381807136517697285L;
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    
    private String wname;

    private Integer wage;
    
    // getter and setter

在Author声明属性wife,指定对应关系

@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "wife_id")
private Wife wife;
@OneToOne

顾名思义,就是一对一关系,cascade是级联操作,CascadeType有多种配置

  • ALL 所有
  • PERSIST 级联持久化(保存)操作
  • MERGE 级联更新(合并)操作
  • REMOVE 移除
  • REFRESH 刷新
  • DETACH 脱管/游离操作
@JoinColumn

保存表与表之间关系的字段,同@Column,name只指定数据库字段,wife_id,但是默认指向该表的主键,如何要让wife表其他字段做外建,就需要使用referencedColumnName指明对应表的字段。我这里没有明确举例,其他小伙伴可以自己去尝试。

@JoinColumn(name = "wife_id",referencedColumnName="name")

测试:
建立Controller类,启动服务访问

@RestController
@RequestMapping("/jpa")
public class IndexController {

    @Autowired
    AuthorRepository authorRepository;
    
    @Autowired
    PoetryRepository poetryRepository;
    
    @Autowired
    WifeRepository wifeRepository;

    @GetMapping("/author/{id}")
    public Author findAuthorById(@PathVariable(value = "id") Integer id){
        return authorRepository.findById(id).get();
    }
}

这里@Controller
效果如图:

image

当然这里只是一对一的单向关联,主导权全在author那边,而wife这边没有任何可以修改的权限,对于这种也是可以有解决的办法的,我们建立双向关联,

在wife类里添加

@OneToOne(mappedBy="wife")
@JsonBackReference
private Author author;

mappedBy指的被映射,如何要双向关联,必须要指定mappedBy,
而@JsonBackReference注解是因为双向关联后,你中有我,我中有你,就会无限循环下去,所以在任何一方添加 @JsonBackReference可以解决这个问题,通过debug我们可以看到如果不加 @JsonBackReference的后果

image

(2)一对多关系

这里一对多关系,我们就用之前的作者表(author)和古诗(Poetry),李白一个人就有一千多首诗呢

好了,还是先单向关联,主动权肯定在author 作者这边。

在Author加入

@OneToMany
private List<Poetry> poetryList;

这里就有点不同了,一对一中外键关系wife_id主动权在author手中,那么数据表这边就会添加一个字段wife_id,
但是一对多就不同了,主键但是对应多个,不可能生成外键,
所以外键是放在多那边,就是古诗表(poetry);

Poetry

多对一里面是主动的,@JoinColumn指定外键authorCN_id

@ManyToOne
@JoinColumn(name = "authorCN_id")
@JsonBackReference
private Author author;

Author

一对多里面是被动的,mappedBy指向Poetry里面的author

@OneToMany(mappedBy = "author")
private List<Poetry> poetryList;

建立后,查询结果如下,可以看到关联到杜甫的诗就都出来了

image

(3)多对多关系

多对多的话,就拿读者和古诗举例吧,读者可以读很多古诗,古诗也可以有不同的读者

@Entity
@Table
public class Reader implements Serializable {
    private static final long serialVersionUID = 4074367019988114836L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    private String name;

    private Integer age;

    @ManyToMany
    @JoinTable(name = "PoetryAndReader", joinColumns ={@JoinColumn(name = "reader_id")},
            inverseJoinColumns = {@JoinColumn(name = "poetry_id")})
    private List<Poetry> poetryList;
}
@ManyToMany

多对多的注解

@JoinTable

因为多对多不存在直接外键外键,所以建立第三方表里面存储双方法的主键作为外键,name就是第三方表的名字,joinColumns就是配置连接表中外键列的信息,该属性值可接受多个@JoinColumn,用于配置连接表中外键列的信息

image

结束

里面的代码只粘贴了重要部分的,如果哪个小伙伴要跑一下看下具体效果,我把代码贴到了GitHub里面,有兴趣的可以去copy.

https://github.com/AugusDuan/jpaTest

转载于:https://www.cnblogs.com/augusduan/p/9397202.html

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值