Jpa-多表关联-OneToOne
- 准备
- JoinColumn
- OneToOne属性
- targetEntity
- cascade*
- PERSIST
- MERGE
- REMOVE
- REFRESH
- orphanRemoval
- fetch
- optional
- MappedBy*
OneToOne
在
hibernate
中用于对表与表之间进行维护关联
准备
import com.alibaba.fastjson.JSON;
import jakarta.persistence.*;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@Entity
@Table(name = "t_user_account", schema = "test")
public class TUserAccount {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id", nullable = false)
private Long id;
@Column(name = "msg", length = 50)
private String msg;
@JoinColumn(name = "user_account", referencedColumnName = "id")
@OneToOne
private TUser user;
public String toString() {
return JSON.toJSONString(this);
}
}
@Entity
@Table(name = "t_user", schema = "test")
@Data
public class TUser {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id", nullable = false)
private Long id;
@Column(name = "real_name", length = 50)
private String realName;
//......
@OneToOne(mappedBy = "user")
private TUserAccount userAccount;
}
-- auto-generated definition
create table t_user
(
id bigint auto_increment
primary key,
real_name varchar(50) null comment '实际名称',
age bigint null,
sex varchar(255) null,
create_time datetime default CURRENT_TIMESTAMP not null comment '创建时间',
update_time datetime default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment '更新时间',
is_delete tinyint default 0 not null comment '是否删除'
)
comment '用户表';
-- auto-generated definition
create table t_user_account
(
id bigint auto_increment
primary key,
user_account bigint null,
msg varchar(50) null
);
JoinColumn
与OneToOne
一起使用的情况下。
JoinColumn
用于定义外键关系。
name
:用当前表那个字段作为目标表的外键,默认是实体名_字段名
referencedColumnName
:与源表用那个字段进行,默认为当前表的主键
OneToOne属性
targetEntity
关联的目标实体类。默认为存储关联的字段的类型。
cascade*
表明那些操作需要级联操作。默认为空。但是查询的时候是会进行级联查询的。
PERSIST
只有插入(INSERT
)操作时进行级联操作 插入主表的同时会插入子表。
当插入操作时,如果没有标注当前PERSIST
方法时则会报错。
// 修改TUserAccount.java中的 @OneToOne(cascade = {CascadeType.PERSIST})
@Test
public void testOneToOneInsert(){
TUserAccount entity = new TUserAccount();
entity.setMsg("INSERT");
TUser user = new TUser();
user.setRealName("INSERT");
entity.setUser(user);
// 对主表进行INSERT操作
userAccountRepository.save(entity);
}
MERGE
只有更新(UPDATE
)操作时进行级联操作,更新时如果将关联属性修改为null
会把当前表的关联的字段改为null
。默认是不会删除关联表的行数据( 注意这里不会将关联表的行数据给删除,需要删除的话则需要开启orphanRemoval
)。
// 修改TUserAccount.java中的 @OneToOne(cascade = {CascadeType.MERGE})
@Test
public void testOneToOneUpdate(){
TUserAccount newEntity = new TUserAccount();
newEntity.setId(11L);
newEntity.setMsg("MERGE");
newEntity.setUser(null);
userAccountRepository.save(newEntity);
}
进行级联查询后,只对当前表进行
update
操作,将user_account
字段置为null
REMOVE
只有删除(DELETE)操作时进行级联操作,删除主表的同时会把子表也删除
// 修改TUserAccount.java中的 @OneToOne(cascade = {CascadeType.REMOVE})
@Test
public void testOneToOneDelete(){
userAccountRepository.deleteById(15L);
}
级联查询后,对主表进行删除,再后关联表进行删除。
REFRESH
EntityManager.refresh()
方法用于重新加载实体的状态,从数据库中获取最新的数据,并覆盖当前持久化上下文中的实体状态
orphanRemoval
当进行更新操作时,将关联属性修改为null
,会删除关联的子表数据。默认为false
。
// 修改TUserAccount.java中的 @OneToOne(cascade = {CascadeType.MERGE},orphanRemoval=true)
@Test
public void testOneToOneOrphanRemoval(){
TUserAccount newEntity = new TUserAccount();
newEntity.setId(11L);
newEntity.setMsg("MERGE");
newEntity.setUser(null);
userAccountRepository.save(newEntity);
}
级联查询后,对主表进行更新,将
user_account
改为null
,并删除t_user
的记录。
fetch
EAGER
:立即获取数据(默认)与主表一起查出LAZY
:如果是LAZY
则是当我们使用关联表对象的时候才会去进行查询。注意使用LAZY
时需要@Transactional
中进行使用,因为如果查询完session
关闭了就不能从里面获取数据了。
// 修改TUserAccount.java中的 @OneToOne(cascade = {CascadeType.ALL},orphanRemoval=true,fetch = FetchType.LAZY)
@Test
@Transactional
public void testOneToOneFetchLazy(){
TUserAccount tUserAccount = userAccountRepository.findById(6L).get();
System.out.println("================wait================");
System.out.println(tUserAccount.getUser());
}
先只查主表,如果我们没有使用则不会对关联表进行查询,而到我们获取关联表信息的时候再去对关联表进行查询,
optional
是否允许为空,默认是true
。为false
时不能将关联字段设置为null
。表示为非空的关联关系。
MappedBy*
表示关联关系为当前字段类型的的实体
来进行维护,指定的值为目标类型
中的外键字段。这里删除,更新,不会对关联进行操作。
@Test
public void testQueryMappedBy(){
TUser tUser = userRepository.findById(7017L).get();
System.out.println(tUser);
tUser.setUserAccount(null);
userRepository.save(tUser);
}
当查询
t_user
的时候也可以把t_user_account
查询出来。对t_user的uesrAccount
的进行操作的时候不会对数据库中的字段进行影响。