文章目錄
1. Spring Data JPA一對多的關聯映射案例
1.1 創建表結構
客戶表的建表語句:
CREATE TABLE `cst_customer` (
`cust_id` bigint(32) NOT NULL AUTO_INCREMENT COMMENT '客戶編號(主鍵)',
`cust_name` varchar(32) NOT NULL COMMENT '客戶名稱(公司名稱)',
`cust_user_id` bigint(32) DEFAULT NULL COMMENT '負責人id',
`cust_create_id` bigint(32) DEFAULT NULL COMMENT '創建人id',
`cust_source` varchar(32) DEFAULT NULL COMMENT '客戶信息來源',
`cust_industry` varchar(32) DEFAULT NULL COMMENT '客戶所屬行業',
`cust_level` varchar(32) DEFAULT NULL COMMENT '客戶級別',
`cust_linkman` varchar(64) DEFAULT NULL COMMENT '聯繫人',
`cust_phone` varchar(64) DEFAULT NULL COMMENT '固定電話',
`cust_mobile` varchar(16) DEFAULT NULL COMMENT '移動電話',
PRIMARY KEY (`cust_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
聯繫人表的建表語句:
CREATE TABLE `cst_linkman` (
`lkm_id` bigint(32) NOT NULL AUTO_INCREMENT COMMENT '聯繫人編號(主鍵)',
`lkm_name` varchar(16) DEFAULT NULL COMMENT '聯繫人姓名',
`lkm_cust_id` bigint(32) NOT NULL COMMENT '客戶id',
`lkm_gender` char(1) DEFAULT NULL COMMENT '聯繫人性別',
`lkm_phone` varchar(16) DEFAULT NULL COMMENT '聯繫人辦公電話',
`lkm_mobile` varchar(16) DEFAULT NULL COMMENT '聯繫人手機',
`lkm_email` varchar(64) DEFAULT NULL COMMENT '聯繫人郵箱',
`lkm_qq` varchar(16) DEFAULT NULL COMMENT '聯繫人qq',
`lkm_position` varchar(16) DEFAULT NULL COMMENT '聯繫人職位',
`lkm_memo` varchar(512) DEFAULT NULL COMMENT '聯繫人備註',
PRIMARY KEY (`lkm_id`),
KEY `FK_cst_linkman_lkm_cust_id` (`lkm_cust_id`),
CONSTRAINT `FK_cst_linkman_lkm_cust_id` FOREIGN KEY (`lkm_cust_id`) REFERENCES `cst_customer` (`cust_id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
1.2 編寫實體類
客戶的實體類如下:
@Entity
@Table(name="cst_customer")
public class Customer implements Serializable {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name="cust_id")
private Long custId;
@Column(name="cust_name")
private String custName;
@Column(name="cust_source")
private String custSource;
@Column(name="cust_industry")
private String custIndustry;
@Column(name="cust_level")
private String custLevel;
@Column(name="cust_address")
private String custAddress;
@Column(name="cust_phone")
private String custPhone;
/**
* 配置客戶和聯繫人的一對多關係
* @OneToMany:建立一對多的關係映射
* targetEntityClass:指定多的多方的類的字節碼
* mappedBy:指定從表實體類中引用主表對象的名稱
* cascade:指定要使用的級聯操作
* fetch:指定是否採用延遲加載
* orphanRemoval:是否使用孤兒刪除
* @JoinColumn:用於定義主鍵字段和外鍵字段的對應關係
* name:指定外鍵字段的名稱
* referencedColumnName:指定引用主表的主鍵字段名稱
* unique:是否唯一。默認值不唯一
* nullable:是否允許爲空。默認值允許
* insertable:是否允許插入。默認值允許
* updatable:是否允許更新。默認值允許
* columnDefinition:列的定義信息
*/
@OneToMany(targetEntity=LinkMan.class)
@JoinColumn(name="lkm_cust_id", referencedColumnName="cust_id")
private Set<LinkMan> linkmans = new HashSet<LinkMan>(0);
//省略 get和 set方法
}
聯繫人的實體類如下:
@Entity
@Table(name="cst_linkman")
public class LinkMan implements Serializable {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name="lkm_id")
private Long lkmId;
@Column(name="lkm_name")
private String lkmName;
@Column(name="lkm_gender")
private String lkmGender;
@Column(name="lkm_phone")
private String lkmPhone;
@Column(name="lkm_mobile")
private String lkmMobile;
@Column(name="lkm_email")
private String lkmEmail;
@Column(name="lkm_position")
private String lkmPosition;
@Column(name="lkm_memo")
private String lkmMemo;
/**
* 配置聯繫人和客戶的多對一關係映射
* @ManyToOne:建立多對一的關係
* targetEntityClass:指定多的多方的類的字節碼
* cascade:指定要使用的級聯操作
* fetch:指定是否採用延遲加載
* optional:關聯是否可選。如果設置爲 false,則必須始終存在非空關係
*/
@ManyToOne(targetEntity=Customer.class)
@JoinColumn(name="lkm_cust_id", referencedColumnName="cust_id")
private Customer customer;
//省略 get和 set方法
}
2.3 編寫Dao層接口
客戶的Dao層接口如下:
public interface CustomerDao extends JpaRepository<Customer, Long>, JpaSpecificationExecutor<Customer> {
}
聯繫人的Dao層接口如下:
public interface LinkManDao extends JpaRepository<LinkMan, Long>, JpaSpecificationExecutor<LinkMan> {
}
2.4 編寫測試代碼
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations="classpath:applicationContext.xml")
public class OneToManyTest {
@Autowired
private CustomerDao customerDao;
@Autowired
private LinkManDao linkManDao;
@Test
public void test1(){
Customer customer = new Customer();
customer.setCust_name("張總");
LinkMan linkMan = new LinkMan();
linkMan.setLkm_name("秦助理");
customer.getLinkMans().add(linkMan);
linkMan.setCustomer(customer);
customerDao.save(customer);
linkManDao.save(linkMan);
}
}
2. Spring Data JPA一對多的相關操作
2.1 保存
@Test
public void test1(){
Customer customer = new Customer();
customer.setCust_name("張總");
LinkMan linkMan = new LinkMan();
linkMan.setLkm_name("秦助理");
customer.getLinkMans().add(linkMan);
linkMan.setCustomer(customer);
customerDao.save(customer);
linkManDao.save(linkMan);
}
通過上面的代碼,我們可以發現當我們建立了雙向的關聯關係之後,先保存主表,再保存從表時,會產生2條insert和1條update,而實際開發中我們只需要2條insert。
原因是在客戶實體類上(一的一方)添加了外鍵了配置,所以對於客戶而言,也具備了維護外鍵的作用。那我們的解決是思路很簡單,就是一的一方放棄維護權。放棄外鍵維護權需要將客戶實體類的一對多配置改爲:
@Entity
@Table(name="cst_customer")
public class Customer implements Serializable {
//mappedBy:放棄外鍵維護權,值爲對方配置關係的屬性名稱
@OneToMany(mappedBy="customer")
private Set<LinkMan> linkmans = new HashSet<LinkMan>(0);
}
2.2 刪除
@Test
public void test2(){
customerDao.delete(1l);
}
刪除操作的說明如下:
- 刪除從表數據:可以隨時任意刪除。
- 刪除主表數據:
- 有從表數據:
1、在默認情況下,它會把外鍵字段置爲null,然後刪除主表數據。如果在數據庫的表結構上,外鍵字段有非空約束,默認情況就會報錯了。
2、如果配置了放棄維護關聯關係的權利,則不能刪除(與外鍵字段是否允許爲null沒有關係)。因爲在刪除時,它需要把外鍵字段置爲null,而放棄外鍵維護權,它根本不會去更新從表的外鍵字段了,所以刪除時會報錯。
3、如果還想刪除,使用級聯刪除引用。 - 沒有從表數據引用:隨便刪。
- 有從表數據:
2.3 級聯操作和延遲加載
級聯操作:指操作一個對象同時操作它的關聯對象。使用方法:只需要在操作主體的註解上配置cascade。
延遲加載:就是當在真正需要數據的時候,才真正執行數據加載操作。使用方法:只需要在操作主體的註解上配置fetch。
/**
* cascade:配置級聯操作
* CascadeType.MERGE:級聯更新
* CascadeType.PERSIST:級聯保存
* CascadeType.REFRESH:級聯刷新
* CascadeType.REMOVE:級聯刪除
* CascadeType.ALL:包含所有
* fetch:配置關聯對象的加載方式
* FetchType.EAGER:立即加載
* FetchType.LAZY:延遲加載
*/
@OneToMany(mappedBy="customer", cascade=CascadeType.ALL, fetch=FetchType.LAZY)