Spring Data JPA-单向一对一关联映射

Spring Data JPA-单向一对一关联映射

假如有一张客户表和一张银行账户表,如果想在客户表中关联该客户的银行账户信息,那么这就是一个单向一对一的映射关系。

配置映射关系

  1. 在客户domain中的银行账户domain对象的属性上添加@OneToOne注解,表示这是一个一对一关联关系,然后配置cascade属性,该属性的作用是设置关联关系在哪种持久化操作下有效,属性如下:
    • ALL:所有持久化操作都执行关联操作,也就是说,如果执行的是删除操作,会把所有关联的数据都删除。我个人觉得尽可能不要设置为ALL,因为通常关联的数据都会被很多表关联,这样难免会造成数据错误。
    • PERSIST:只有插入才会执行关联操作
    • MERGE:只有修改才会执行关联操作
    • REMOVE:只有删除才会执行关联操作
  2. 在客户domain中的银行账户domain对象的属性上添加@JoinColumn注解,name属性用来设置外键的字段名。

完成以上两步,一个单向一对一的关联关系就设置好了。

代码示例

示例客户domain:

@Entity
@Table(name = "tb_customer")
@Data
public class Customer {

    @Id
    @GeneratedValue
    private Long id; //客户的主键

    private String customerName;//客户名称

    private String customerAddress;//客户地址

    @OneToOne(cascade = CascadeType.PERSIST)
    @JoinColumn(name = "account_id")
    private Account account;
}

示例银行账户domain

@Entity
@Table(name = "tb_account")
@Data
public class Account {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String username;
    private String password;
}

示例repository

public interface CustomerRepository extends JpaRepository<Customer, Long> {
    
}

测试

Insert

    @Test
    public void testInsert() {
        // 初始化数据
        Account account = new Account();
        account.setUsername("ZMQ");
        account.setPassword("123456");

        Customer customer = new Customer();
        customer.setCustomerName("朱茂强");
        customer.setCustomerAddress("山东 - 青岛");

        // 在客户表中存储客户对应账户的ID
        customer.setAccount(account);

        repository.save(customer);
    }

程序运行日志

Hibernate: insert into tb_account (password, username) values (?, ?)
Hibernate: insert into tb_customer (account_id, address, name) values (?, ?, ?)

可以看到程序自动完成了关联插入,在客户表中插入了 @JoinColumn中name属性指定的外键字段。

Query

    @Test
    public void testQuery() {
        Optional<Customer> customer = repository.findById(1L);
        System.out.println(customer);
    }

程序运行日志

Hibernate: select customer0_.id as id1_1_0_, customer0_.account_id as account_4_1_0_, customer0_.address as address2_1_0_, customer0_.name as name3_1_0_, account1_.id as id1_0_1_, account1_.password as password2_0_1_, account1_.username as username3_0_1_ from tb_customer customer0_ left outer join tb_account account1_ on customer0_.account_id=account1_.id where customer0_.id=?
Optional[Customer(id=1, customerName=朱茂强, customerAddress=山东 - 青岛, account=Account(id=1, username=ZMQ, password=123456))]

可以看到程序默认使用左外连接的方式将关联信息也查了出来,可以通过配置懒加载,默认不进行连表查询,等用到关联信息的时候再执行连表查询,有关懒加载我会在后面讲。

update

    @Test
    public void testUpdate() {
        Optional<Customer> customerOptional = repository.findById(1L);

        Customer customer = customerOptional.get();
        customer.setCustomerName("zmq");

        Account account = customer.getAccount();
        account.setUsername("ZhuMaoqiang");
        account.setPassword("123");

        customer.setAccount(account);
        repository.save(customer);
    }

程序运行日志

Hibernate: select customer0_.id as id1_1_0_, customer0_.account_id as account_4_1_0_, customer0_.address as address2_1_0_, customer0_.name as name3_1_0_, account1_.id as id1_0_1_, account1_.password as password2_0_1_, account1_.username as username3_0_1_ from tb_customer customer0_ left outer join tb_account account1_ on customer0_.account_id=account1_.id where customer0_.id=?
Hibernate: select customer0_.id as id1_1_0_, customer0_.account_id as account_4_1_0_, customer0_.address as address2_1_0_, customer0_.name as name3_1_0_ from tb_customer customer0_ where customer0_.id=?
Hibernate: select account0_.id as id1_0_0_, account0_.password as password2_0_0_, account0_.username as username3_0_0_ from tb_account account0_ where account0_.id=?
Hibernate: update tb_customer set account_id=?, address=?, name=? where id=?

可以看到用户关联的银行账户信息并没有执行更新操作,原因是我们设置了持久化操作的关联操作只对插入有效。如果我们不改变

@OneToOne(cascade = CascadeType.PERSIST)并且还想当关联的数据设置为null或者修改为其他的关联数据时自动删除关联数据,可以通过@OneToOne中的属性orphanRemoval = true来完成。

delete

    @Test
    public void Customerdelete() {
        repository.deleteById(1L);
    }

程序运行日志

Hibernate: select customer0_.id as id1_1_0_, customer0_.account_id as account_4_1_0_, customer0_.address as address2_1_0_, customer0_.name as name3_1_0_, account1_.id as id1_0_1_, account1_.password as password2_0_1_, account1_.username as username3_0_1_ from tb_customer customer0_ left outer join tb_account account1_ on customer0_.account_id=account1_.id where customer0_.id=?
Hibernate: delete from tb_customer where id=?

可以看到用户关联的银行账户信息并没有执行删除操作,原因是我们设置了持久化操作的关联操作只对插入有效。

懒加载

上面提起:默认情况下,若获取维护关联关系的一方(客户信息),则会通过左外连接获取其关联的对象。加假如每个用户都有关联的角色信息,很多时候我们可能只是用到用户信息,那么就没必要每次都连接查询关联信息。可以通过添加 @OntToOne 的 fetch 属性来修改加载策略,如添加 fetch = FetchType.LAZY,默认就不会左外连查询。如果session没有关闭之前,用到了关联信息就会自动连表查询。

示例:

假设你已经配置了fetch = FetchType.LAZY

    @Test
    /**
     * 为什么懒加载要配置事务 :
     * 当通过repository调用完查询方法,session就会立即关闭, 一旦session关闭就不能再执行查询操作,这个
     * 时候如果你没有用到关系的对象,那么就还没进行查询。加了事务后, 就能让session直到事务方法执行完
     * 毕后才会关闭。
     */
    @Transactional(readOnly = true)
    public void testQueryByLazy() {
        Optional<Customer> customer = repository.findById(2L);
        /*
         * 由于设置了懒加载,程序执行到这一行并没有连表查询关联对象,当执行到下一行,get()会调用customer的
         * toString方法,而toString 方法中有Account的信息,这时由于加了事务,session并没有关闭,程序会继续
         * 执行关联查询。
         */
        System.out.println(customer.get());  // toString
    }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

朱茂强

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值