亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Spring?Boot?整合JPA?數(shù)據(jù)模型關(guān)聯(lián)使用操作(一對一、一對多、多對多)

 更新時(shí)間:2022年07月19日 11:38:39   作者:大·風(fēng)  
這篇文章主要介紹了Spring?Boot?整合JPA?數(shù)據(jù)模型關(guān)聯(lián)操作(一對一、一對多、多對多),本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下

表關(guān)聯(lián)

上一篇介紹了JPA的簡單使用,這一篇介紹JPA在表關(guān)聯(lián)上的使用

一對一

配置參數(shù)
JPA對于數(shù)據(jù)實(shí)體一對一映射使用的是@OneToOne注解。

代碼

User用戶表

/**
 * 用戶信息
 * @author daify
 **/
@Data
@Entity
@Table(name = "cascade_user")
public class User {

    @Id
    @GeneratedValue
    private Long id;
    
    private String name;
    
    private Integer age;
    
    private Double point;
    /**
     * CascadeType包含的類別  級聯(lián):給當(dāng)前設(shè)置的實(shí)體操作另一個(gè)實(shí)體的權(quán)限
     *      CascadeType.ALL 級聯(lián)所有操作
     *      CascadeType.PERSIST 級聯(lián)持久化(保存)操作
     *      CascadeType.MERGE   級聯(lián)更新(合并)操作
     *      CascadeType.REMOVE  級聯(lián)刪除操作
     *      CascadeType.REFRESH 級聯(lián)刷新操作
     *      CascadeType.DETACH 級聯(lián)分離操作,如果你要?jiǎng)h除一個(gè)實(shí)體,但是它有外鍵無法刪除,這個(gè)級聯(lián)權(quán)限會撤銷所有相關(guān)的外鍵關(guān)聯(lián)。
     */
    @OneToOne(targetEntity = UserCart.class,
            cascade = CascadeType.ALL,
            mappedBy = "user")
    private UserCart userCart;

    @OneToOne(targetEntity = UserInfo.class,
            cascade = CascadeType.ALL)
    @JoinTable(name = "user_info_table",
            joinColumns = @JoinColumn(name="user_id"),
            inverseJoinColumns = @JoinColumn(name = "info_id"))
    private UserInfo userInfo;

}

UserCart用戶購物車表

@Data
@Entity
@Table(name = "cascade_user_cart")
public class UserCart {

    @Id
    @GeneratedValue
    private Long id;
    
    private Integer count;
    
    private Double totalMoney;
    
    private Date updateTime;

    /**
     * CascadeType包含的類別  級聯(lián):給當(dāng)前設(shè)置的實(shí)體操作另一個(gè)實(shí)體的權(quán)限
     *      CascadeType.ALL 級聯(lián)所有操作
     *      CascadeType.PERSIST 級聯(lián)持久化(保存)操作
     *      CascadeType.MERGE   級聯(lián)更新(合并)操作
     *      CascadeType.REMOVE  級聯(lián)刪除操作
     *      CascadeType.REFRESH 級聯(lián)刷新操作
     *      CascadeType.DETACH 級聯(lián)分離操作,如果你要?jiǎng)h除一個(gè)實(shí)體,但是它有外鍵無法刪除,這個(gè)級聯(lián)權(quán)限會撤銷所有相關(guān)的外鍵關(guān)聯(lián)。
     */
    @OneToOne(targetEntity = User.class,
            cascade = {},
            fetch = FetchType.LAZY)
    private User user;
}

用戶信息

@Data
@Entity
@Table(name = "cascade_user_info")
public class UserInfo {

    @Id
    @GeneratedValue
    private Long id;
    
    private String userInfo;
    
    private String config;
}

上面例子中嘗試使用了兩種方式來維護(hù)一對一的關(guān)系,首先在User實(shí)體中同樣標(biāo)注了@OneToOne但是配置了mappedBy,
這樣生成的表數(shù)據(jù)中,User和UserCart的關(guān)系將由UserCart負(fù)責(zé)維護(hù)。User表中并不會維護(hù)UserCart的信息。
而在User和UserInfo的關(guān)系中使用了中間表user_info_table來維護(hù)雙方的關(guān)系,UserInfo實(shí)體中并沒有保存任何User的信息。

權(quán)限

在User、UserCart、UserInfo三者中User為數(shù)據(jù)存在的主體,其他兩個(gè)實(shí)體都是依托于User數(shù)據(jù)的存在而存在。
所以在權(quán)限中給User實(shí)體提供了全部全部權(quán)限。

注解

@OneToOne主要提供了下面的參數(shù)內(nèi)容

注解參數(shù)描述
@OneToOne 描述一個(gè) 一對一的關(guān)聯(lián)
 targetEntity目標(biāo)類的實(shí)體
 cascade關(guān)聯(lián)到目標(biāo)的操作
 fetch是否使用延遲加載
 mappedBy反向關(guān)聯(lián)

測試
因?yàn)樯厦嬉粚σ坏睦又袡?quán)限被賦予給User表中,UserCart并沒有賦予任何權(quán)限,所以保存用戶的時(shí)候可以關(guān)聯(lián)保存用戶購物車,刪除購物車的時(shí)候并不會刪除用戶,但是刪除用戶的時(shí)候會刪除購物車

通過保存用戶關(guān)聯(lián)保存購物車

    @Test
    public void testUserSave() {
        User defUser1 = UserMock.getDefUser1();
        UserCart defUserCart1 = UserCartMock.getDefUserCart1();
        defUser1.setUserCart(defUserCart1);
        defUserCart1.setUser(defUser1);
        // 此時(shí)保存用戶,用戶購物車應(yīng)該也被保存
        userRepository.save(defUser1);
        List <UserCart> all = userCartRepository.findAll();
        Assert.assertNotNull(all);
        Assert.assertTrue(all.size() == 1);
    }

刪除用戶購物車的時(shí)候,用戶不會被刪除

    @Test
    public void testUserCartDelete() {
        User defUser1 = UserMock.getDefUser1();
        UserCart defUserCart1 = UserCartMock.getDefUserCart1();
        defUser1.setUserCart(defUserCart1);
        // 此時(shí)保存用戶,用戶購物車應(yīng)該也被保存
        userRepository.save(defUser1);
        // 此時(shí)刪除用戶購物車并不會刪除用戶
        userCartRepository.deleteAll();
        List <User> all1 = userRepository.findAll();
        Assert.assertNotNull(all1);
        Assert.assertTrue(all1.size() == 1);
    }

刪除用戶的時(shí)候,購物車會被刪除

    @Test
    public void testUserDelete() {
        User defUser1 = UserMock.getDefUser1();
        UserCart defUserCart1 = UserCartMock.getDefUserCart1();
        defUser1.setUserCart(defUserCart1);
        // 此時(shí)保存用戶,用戶購物車應(yīng)該也被保存
        userRepository.save(defUser1);
        // 此時(shí)刪除用戶購物車并不會刪除用戶
        userRepository.delete(defUser1);
        List <UserCart> all = userCartRepository.findAll();
        Assert.assertTrue(all.size() == 0);
    }

一對多和多對一

通過@OneToMany和@ManyToOne的組合我們可以實(shí)現(xiàn)雙向關(guān)聯(lián)。根據(jù)JPA規(guī)范,我們使用多方來維護(hù)關(guān)系。
通過在多方維護(hù)@JoinColumn來注釋屬性。

代碼

訂單表

@Data
@Entity
@Table(name = "cascade_order")
public class Order {

    @Id
    @GeneratedValue
    private Long id;
    
    private String orderNo;
    
    private Integer count;
    
    private Double money;

    @OneToMany(mappedBy = "order",
            cascade = CascadeType.ALL,
            fetch = FetchType.EAGER)
    private List<OrderItem> orderItems;
    
    /**
    * 重寫toString防止死循環(huán)
    * @return 
    */
    @Override 
    public String toString() {
        return "OrderItem{" + "id=" + id + ", productId='" + productId + '\'' + ", money=" + money
               + ", count=" + count + ", productName='" + productName + '\'' + ", order=" + order
               + '}';
    }
    
}

訂單子項(xiàng)

@Data
@Entity
@Table(name = "cascade_order_item")
public class OrderItem {

    @Id
    @GeneratedValue
    private Long id;

    private String productId;

    private Double money;
    
    private Integer count;
    
    private String productName;
    
    @ManyToOne(targetEntity = Order.class,
            cascade = {},
            fetch = FetchType.EAGER)
    @JoinColumn(
            // 設(shè)置在OrderItem表中的關(guān)聯(lián)字段(外鍵)
            name="order_id"
    )
    // 防止json序列化死循環(huán)問題解決
    @JsonBackReference
    private Order order;
}

上門的例子中,訂單方為一端,訂單子項(xiàng)為多端,在多端除了使用了@ManyToOne
還使用了@JoinColumn注解來標(biāo)識Order主鍵創(chuàng)建到OrderItem表的列的名稱,
當(dāng)然沒有此注解的時(shí)候JPA會根據(jù)默認(rèn)規(guī)則生成一個(gè)列名稱。

權(quán)限
根據(jù)JPA規(guī)范一對多時(shí)候,關(guān)系的維護(hù)交給了多方來進(jìn)行,但是很多時(shí)候多方的存在是依靠一方的。
比如(訂單、訂單子項(xiàng))所以更新刪除的權(quán)限需要授權(quán)給一方(Order)。

@ManyToOne,@OneToMany

注解參數(shù)描述
@ManyToOne 一個(gè)多對一的映射,該注解標(biāo)注的屬性通常是數(shù)據(jù)庫表的外鍵.
 targetEntity目標(biāo)類的實(shí)體
 cascade關(guān)聯(lián)到目標(biāo)的操作
 fetch是否使用延遲加載
@OneToMany 一個(gè) 一對多的關(guān)聯(lián),該屬性應(yīng)該為集體類型,在數(shù)據(jù)庫中并沒有實(shí)際字段
 targetEntity目標(biāo)類的實(shí)體
 cascade關(guān)聯(lián)到目標(biāo)的操作
 fetch是否使用延遲加載
 mappedBy反向關(guān)聯(lián)
 orphanRemoval講移除操作級聯(lián)到關(guān)聯(lián)的實(shí)體中

測試

一對多的時(shí)候雖然多方維持了兩者關(guān)系,但是我們把權(quán)限賦予了一方所以,刪除多方并不會級聯(lián)操作,刪除一方可以移除多方數(shù)據(jù)。所以下的測試可以通過

    @Test
    public void testOrder() {
        Order defOrder1 = OrderMock.getDefOrder1();
        List <OrderItem> allDefOrder = OrderItemMock.getAllDefOrder();
        // order 維持orderItem關(guān)系
        defOrder1.setOrderItems(allDefOrder);
        // orderItem維持order關(guān)系
        allDefOrder.forEach(o -> o.setOrder(defOrder1));
        Order save = orderRepository.save(defOrder1);
        List <OrderItem> all = orderItemRepository.findAll();
        Assert.assertTrue(all.size() == allDefOrder.size());

        orderItemRepository.delete(all.get(0));
        Order order = orderRepository.findById(save.getId()).get();
        Assert.assertNotNull(order);

        orderRepository.deleteById(order.getId());
        List <OrderItem> all1 = orderItemRepository.findAll();
        Assert.assertTrue(all1.size() == 0);

    }

多對多

配置方法
和一對多、一對一不同,多對多沒法只使用兩個(gè)數(shù)據(jù)實(shí)體完成相互之間的關(guān)系維護(hù),這個(gè)時(shí)候需要一個(gè)關(guān)聯(lián)的中間表來維護(hù)他們之間的關(guān)系。
對于中間表的配置,你大可不去進(jìn)行額外的配置讓JPA自動生成,當(dāng)然你也可以使用之前介紹的@JoinTable注解進(jìn)行配置。

權(quán)限

和一對多、一對一不同,多對多一般是沒有辦法設(shè)置級聯(lián)操作的。因?yàn)殡p方對應(yīng)的都是集合對象,
而雙方某一條數(shù)據(jù)都可能被對方多條數(shù)據(jù)關(guān)聯(lián)。

代碼

用戶表

@Data
@Entity
@Table(name = "cascade_user")
public class User {

    @Id
    @GeneratedValue
    private Long id;
    
    private String name;
    
    private Integer age;
    
    private Double point;

    @ManyToMany(targetEntity = UserTag.class,
            cascade = {},
            fetch = FetchType.LAZY)
    // 假如不定義,jpa會生成“表名1”+“_”+“表名2”的中間表
    @JoinTable(
            // 定義中間表的名稱
            name = "cascade_user_tag_table",
            // 定義中間表中關(guān)聯(lián)User表的外鍵名
            joinColumns = {
                    @JoinColumn(name = "user_id",
                            referencedColumnName = "id")
            },
            // 定義中間表中關(guān)聯(lián)UserTag表的外鍵名
            inverseJoinColumns = {
                    @JoinColumn(name = "tags_id",
                            referencedColumnName = "id")
            }
    )
    private Set<UserTag> tags;

}

用戶標(biāo)簽表

@Data
@Entity
@Table(name = "cascade_user_tag")
public class UserTag {

    @Id
    @GeneratedValue
    private Long id;
    
    private String tagName;

    @ManyToMany(mappedBy = "tags",
            cascade = {},
            fetch = FetchType.LAZY)
    private List<User> userList;
}

@ManyToMany

下面是@OneToOne以及與其配合的@JoinTable提供的注解參數(shù)

注解參數(shù)描述
@ManyToMany 描述一個(gè)多對多的關(guān)聯(lián).多對多關(guān)聯(lián)上是兩個(gè)一對多關(guān)聯(lián),但是在ManyToMany描述中,中間表是由ORM框架自動處理
 targetEntity目標(biāo)類的實(shí)體
 cascade關(guān)聯(lián)到目標(biāo)的操作
 fetch是否使用延遲加載
 mappedBy反向關(guān)聯(lián)
@JoinTable JoinTable在many-to-many關(guān)系的所有者一邊定義。如果沒有定義JoinTable,使用JoinTable的默認(rèn)值。
 catalog表的目錄
 foreignKey外鍵約束,創(chuàng)建表的時(shí)候使用
 indexes表的索引,在生成表的時(shí)候使用
@JoinColumns 關(guān)系存在多個(gè)JoinColumn,用JoinColumns定義多個(gè)JoinColumn的屬性。
 foreignKey此列的外鍵約束
 valueJoinColumn的集合
 inverseJoinColumns聯(lián)接表的外鍵列,該列引用不擁有關(guān)聯(lián)的實(shí)體的主表
 joinColumns聯(lián)接表的外鍵列,該列引用擁有關(guān)聯(lián)的實(shí)體的主表
 name進(jìn)行連接的表名稱
 schema表的命名空間

測試

多對多的情況下,我們使用雖然User和UserTag的關(guān)系由中間表維護(hù),但是我們在User中配置了中間表的關(guān)系維護(hù),所以此時(shí)刪除用戶的時(shí)候可以成功刪除,且可以成功移除中間表數(shù)據(jù),但是這個(gè)時(shí)候移除UserTag數(shù)據(jù)的時(shí)候,卻會拋出DataIntegrityViolationException異常。只能通過User移除中間關(guān)系。

    @Test
    public void testUserTag() {
        User defUser1 = UserMock.getDefUser1();
        UserTag defTag1 = UserTagMock.getDefTag1();
        UserTag defTag2 = UserTagMock.getDefTag2();
        defUser1 = userRepository.save(defUser1);
        defTag1 = userTagRepository.save(defTag1);
        defTag2 = userTagRepository.save(defTag2);

        defUser1.getTags().add(defTag1);
        defUser1.getTags().add(defTag2);

        defUser1 = userRepository.save(defUser1);
        // 此時(shí)會報(bào)錯(cuò),因?yàn)橹虚g表關(guān)系為User維護(hù)
        try {
            userTagRepository.delete(defTag2);
        } catch (Exception e) {
            log.info(e.getCause().getMessage());
            Assert.assertTrue(e instanceof DataIntegrityViolationException);
        }
        // 修改User表中關(guān)系
        defUser1.setTags(new HashSet <>());
        defUser1.getTags().add(defTag1);
        defUser1 = userRepository.save(defUser1);
        // 此時(shí)可以刪除
        userTagRepository.delete(defTag2);
        // 直接刪除用戶沒問題
        userRepository.delete(defUser1);
    }

本篇文章涉及的源碼下載地址:https://gitee.com/daifyutils/springboot-samples

到此這篇關(guān)于Spring Boot 整合JPA 數(shù)據(jù)模型關(guān)聯(lián)操作(一對一、一對多、多對多)的文章就介紹到這了,更多相關(guān)Spring Boot 整合JPA 數(shù)據(jù)模型關(guān)聯(lián)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論