SpringDataJpa-多表操作


多表之間的關系和操作多表的操作步驟

表關系

  • 一對多
  • 一對多      >>  一:主表     多:從表
  • 多對多     >>  中間表中最少應該由兩個字段組成,這兩個字段作為外鍵指向兩張表的主鍵,又組成了聯合主鍵

 分析步驟

  1. 明確表關系
  2. 確定表關系( 描述: 外鍵  |  中間表 )
  3. 編寫實體類,在實體類中描述表關系(包含關系)
  4. 配置映射關系

完成多表操作

一對多操作 案例:客戶和聯系人(一對多關系) 

    >> 客戶:一家公司     聯系人:這家公司的員工

 一個客戶可以具有多個聯系人,一個聯系人從屬於一家公司

分析步驟

  1. 明確表關系  >> 一對多關系

  2. 確定表關系,再從表上添加外鍵(描述: 外鍵 I 中間表)

  • 主表:客戶表   
  • 從表:聯系人表

  3. 編寫實體類,在實體類中描述表關系(包含關系)

  • 客戶:在客戶的實體類中包含一個聯系人的集合
  • 聯系人:在聯系人的實體類中包含一個客戶的對象

  4. 配置映射關系
  使用JPA注解配置一對多映射關系

 

操作步驟

1.引入依賴坐標,導入實體類和xml文件

2.  Customer   >> 配置客戶和聯系人之間的一對多關系

1   @OneToMany(targetEntity = LinkMan.class) //對方實體類的字節碼對象 2   @JoinColumn(name = "lkm_cust_id",referencedColumnName = "cust_id") //name:外鍵的名稱 referencedColumnName: 外鍵的取值來源 3   private Set<LinkMan> linkMans = new HashSet<LinkMan>();

 

  LinkMan   >> 配置客戶和聯系人之間的一對多關系

1   @ManyToOne(targetEntity = Customer.class) 2   @JoinColumn(name = "lkm_cust_id",referencedColumnName = "cust_id") 3   private Customer customer;

配置外鍵的過程中,配置到多的一方,就會在多的一方維護外鍵

 

3. 保存一個客戶,保存一個聯系人

 1 @RunWith(SpringJUnit4ClassRunner.class)
 2 @ContextConfiguration(locations = "classpath:applicationContext.xml")
 3 public class OneToManyTest {
 4  @Autowired 5 private CustomerDao customerDao; 6 @Autowired 7 private LinkManDao linkManDao;  8     /**
 9      * 保存一個客戶,保存一個聯系人 10      *  效果:客戶和聯系人作為獨立的數據保存到數據庫中
11      *      聯系人的外鍵為空 12      *  原因? >> 實體類中沒有配置關系!! 14      */
15     @Test
16     @Transactional //配置事務
17     @Rollback(false) //不自動回滾
18     public void testAdd() {
19         //創建一個客戶,創建一個聯系人
20         Customer customer = new Customer();
21         customer.setCustname("百度");
22 
23         LinkMan linkMan = new LinkMan();
24         linkMan.setLkmName("小李");
25         /**
26  * 配置了客戶到聯系人的關系 27  * 從客戶的角度上:發送兩條insert語句,發送一條更新語句更新數據庫(更新外鍵) 28  * 由於我們配置了客戶到聯系人的關系:客戶可以對外鍵進行維護 29 */
30 customer.getLinkMans().add(linkMan); 31 
32         customerDao.save(customer);
33         linkManDao.save(linkMan);
34     }

 

進行改進

1 /**
2  * 配置聯系人到客戶的關系(多對一) 3  * 只發送了兩條insert語句 4  * 由於配置了聯系人到客戶的映射關系(多對一),聯系人就能在保存的時候維護外鍵5 */
6         linkMan.setCustomer(customer);

 

再次進行改進

1 linkMan.setCustomer(customer);//由於配置了多的一方到一的一方的關聯關系(當保存的時候,就已經對外鍵賦值)
2         customer.getLinkMans().add(linkMan);//由於配置了一的一方到多的一方的關聯關系(發送一條update語句)

 

結果:會有一條多余的update語句 ,是由於一的一方會維護外鍵,發送update語句

解決的辦法:只需要在一的一方放棄外鍵維護權即可

1 @OneToMany(mappedBy = "customer")// mappedBy:對方配置關系的屬性名稱,如下橙色條 2 private Set<LinkMan> linkMans = new HashSet<LinkMan>();對方配置關系的屬性名稱
@ManyToOne(targetEntity = Customer.class)
@JoinColumn(name = "lkm_cust_id",referencedColumnName = "cust_id")
private Customer customer;
 

 刪除說明:當在主表中設置了放棄外鍵維護權,導致從表中的外鍵無法修改,刪除時就會提示主鍵正在被占用不能刪除。    >> 真的想刪除,則使用級聯刪除 (實際開發中,慎用!!  >> 一對多情況下)

級聯操作    >> 操作一個對象的同時操作他的關聯對象

  1.  需要區分操作主體
  2.  需要在操作主體的實體類上,添加級聯屬性(需要添加到多表映射關系的注解上)
  3.  cascade(配置級聯)

 

 

級聯添加

 

 案例:當我保存一個客戶的同時保存聯系人

 Customer

1 @OneToMany(mappedBy = "customer",cascade = CascadeType.ALL)  //
  • CascadeType.ALL:所有
  • MERGE:更新
  • PERSIST:保存
  • REMOVE:刪除
2     private Set<LinkMan> linkMans = new HashSet<LinkMan>();

 

 1 @Test
 2 @Transactional //配置事務
 3 @Rollback(false) //不自動回滾
 4     public void testCascadeAdd() {
 5         //創建一個客戶,創建一個聯系人
 6         Customer customer = new Customer();
 7         customer.setCustname("百度級聯添加");
 8 
 9         LinkMan linkMan = new LinkMan();
10         linkMan.setLkmName("小李級聯添加");
11         
12         linkMan.setCustomer(customer);//由於配置了多的一方到一的一方的關聯關系(當保存的時候,就已經對外鍵賦值)
13         customer.getLinkMans().add(linkMan);//由於配置了一的一方到多的一方的關聯關系(發送一條update語句)
14 
15  customerDao.save(customer); 16     }

 

級聯刪除

 案例:當我刪除一個客戶的同時刪除此客戶的所有聯系人

1 @Test
2 @Transactional //配置事務
3 @Rollback(false) //不自動回滾
4     public void testRemove() {
5         customerDao.delete(33l);
6     }

 

   改進:根據客戶名查詢出id,再進行刪除操作

 1 @Test
 2     @Transactional //配置事務
 3     @Rollback(false) //不自動回滾
 4     public void testRemove1() {
 5         Specification<Customer> spec=new Specification<Customer>() {
 6             public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
 7                 Path<Object> custname = root.get("custname");
 8                 Predicate predicate = criteriaBuilder.equal(custname, "百度級聯添加");
 9                 return predicate;
10             }};
11         Customer customerDaoOne = customerDao.findOne(spec);
12         Long custid = customerDaoOne.getCustid();
13         customerDao.delete(custid);
14     }

 

多對多操作  案例:用戶和角色

1.  引入依賴坐標,導入實體類和xml文件,創建dao接口

2.  User >> 配置用戶和聯系人之間的一對多關系

 

 1 package cn.itcast.domain;
 2 
 3 import lombok.Data;
 4 
 5 import javax.persistence.*;
 6 import java.util.HashSet;
 7 import java.util.Set;
 8 @Data
 9 @Entity
10 @Table(name = "sys_user")
11 public class User {
12     @Id
13     @GeneratedValue(strategy = GenerationType.IDENTITY)
14     @Column(name="user_id")
15     private Long userId;
16     @Column(name="user_name")
17     private String userName;
18     @Column(name="age")
19     private Integer age;
20     /**
21  * 配置用戶到角色的多對多關系 22  * 配置多對多的映射關系 23  * 1.聲明表關系的配置 24  * @ManyToMany(targetEntity = Role.class) //多對多 25  * targetEntity:代表對方的實體類字節碼 26  * 2.配置中間表(包含兩個外鍵) 27  * @JoinTable 28  *  name : 中間表的名稱 29  * joinColumns:配置當前對象在中間表的外鍵 30  * @JoinColumn的數組 31  * name:外鍵名 32  *  referencedColumnName:參照的主表的主鍵名 33  *       inverseJoinColumns:配置對方對象在中間表的外鍵 34      */
35     @ManyToMany(targetEntity = Role.class,cascade = CascadeType.ALL) 36     @JoinTable(name = "sys_user_role", 37             //joinColumns,當前對象在中間表中的外鍵
38             joinColumns = {@JoinColumn(name = "sys_user_id",referencedColumnName = "user_id")}, name:外鍵名 referencedColumnName:參照的主表里的主鍵名 39             //inverseJoinColumns,對方對象在中間表的外鍵
40             inverseJoinColumns = {@JoinColumn(name = "sys_role_id",referencedColumnName = "role_id")} name:外鍵名  referencedColumnName:參照的主表里的主鍵名
41  ) 42 private Set<Role> roles = new HashSet<Role>(); 43 }

 

 3.  Role >> 配置用戶和聯系人之間的一對多關系

 1 package cn.itcast.domain;
 2 
 3 import lombok.Data;
 4 
 5 import javax.persistence.*;
 6 import java.util.HashSet;
 7 import java.util.Set;
 8 
 9 //@Data
10 @Entity
11 @Table(name = "sys_role")
12 public class Role {
13 
14     @Id
15     @GeneratedValue(strategy = GenerationType.IDENTITY)
16     @Column(name = "role_id")
17     private Long roleId;
18     @Column(name = "role_name")
19     private String roleName;
20 
21     /*@ManyToMany(targetEntity = User.class)
22     @JoinTable(name = "sys_user_role",
23             //joinColumns,當前對象在中間表中的外鍵
24             joinColumns = {@JoinColumn(name = "sys_role_id", referencedColumnName = "role_id")},
25             //inverseJoinColumns,對方對象在中間表的外鍵
26             inverseJoinColumns = {@JoinColumn(name = "sys_user_id", referencedColumnName = "user_id")}
27     )*/
28 
29     @ManyToMany(mappedBy = "roles")  //配置多表關系,被選擇的一方放棄
30     private Set<User> users = new HashSet<User>();
31 
32     public Long getRoleId() { return roleId; }
33     public void setRoleId(Long roleId) { this.roleId = roleId; }
34     public String getRoleName() { return roleName; }
35     public void setRoleName(String roleName) { this.roleName = roleName; }
36     public Set<User> getUsers() { return users; }
37     public void setUsers(Set<User> users) { this.users = users; }
38 }

 

保存一個用戶,保存一個角色

  Role

1  @ManyToMany(mappedBy = "roles")  //配置多表關系,放棄維護權,被選擇的一方放棄(因為角色被用戶所選擇)
2  private Set<User> users = new HashSet<User>();

 

 1 @Test
 2 @Transactional
 3 @Rollback(false)
 4     
 5     public void testAdd() {
 6         User user = new User();
 7         user.setUserName("小馬");
 8         user.setAge(21);
 9 
10         Role role = new Role();
11         role.setRoleName("tx程序員");
12 
13         //配置用戶到角色關系,可以對中間表中的數據進行維護
14         user.getRoles().add(role);
15         //配置角色到用戶關系
16         role.getUsers().add(user);
17 
18         userDao.save(user);
19         roleDao.save(role);
20     }

 

 級聯添加 / 級聯刪除(與一對多案例類似)

 

1 這里只給出 級聯刪除案例
2 @Transactional
3     @Rollback(false)
4     @Test
5     public void testCaseCadeRemove() {
6 User user = userDao.findOne(1l); 7 userDao.delete(user); 8 }

 

多表的查詢

對象導航查詢  :查詢一個對象的同時,通過此對象查詢他的關聯對象

 使用 jpa-day03-onetomany 項目來演示

 1 @Test  2  @Transactional  no Session錯誤! >>  因為所有操作並沒有在一個事務中進行,所以需要添加事務注解
3 public void testQuery1(){ 4 //查詢id為6的客戶 5 Customer customer = customerDao.getOne(6l); 6 //對象導航查詢,此客戶下的所有聯系人 7 Set<LinkMan> linkMans = customer.getLinkMans(); 8 for (LinkMan linkMan : linkMans) { 9 System.out.println(linkMan); 10 } }

 默認使用的是延遲加載的形式查詢的
  調用get方法並不會立即發送查詢,而是在使用關聯對象的時候才會差和訊延遲加載!
  修改配置,將延遲加載改為立即加載(GAGER)
    fetch (延遲加載),需要配置到多表映射關系的注解上

LinkMan

 

1 @ManyToOne(targetEntity = Customer.class,fetch = FetchType.LAZY)
2     @JoinColumn(name = "lkm_cust_id",referencedColumnName = "cust_id")
3     private Customer customer;

 

 

 

 

1 @Test
2     @Transactional
3     public void testQuery2(){
4         LinkMan linkMan = linkManDao.findOne(1l);
5         //對象導航查詢所屬的語句
6         Customer customer = linkMan.getCustomer(); 7         System.out.println(customer);
8     }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM