JPA级联查询
客户 :指一家公司,可以有多个联系人 与联系人是一对多关系
联系人: 只属于一家公司 与客户是多对一关系
客户表
public class Customer { /** * @Id:声明主键的配置 * @GeneratedValue:配置主键的生成策略 * strategy * GenerationType.IDENTITY :自增,mysql * * 底层数据库必须支持自动增长(底层数据库支持的自动增长方式,对id自增) * GenerationType.SEQUENCE : 序列,oracle * * 底层数据库必须支持序列 * GenerationType.TABLE : jpa提供的一种机制,通过一张数据库表的形式帮助我们完成主键自增 * GenerationType.AUTO : 由程序自动的帮助我们选择主键生成策略 * @Column:配置属性和字段的映射关系 * name:数据库表中字段的名称 */ @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_level") private String custLevel;//客户级别 @Column(name="cust_industry") private String custIndustry;//客户所属行业 @Column(name="cust_phone") private String custPhone;//客户的联系方式 @Column(name="cust_address") private String custAddress;//客户地址 /** * 配置一对多关系 * 使用注解方式 * 1.声明关系 @OneToMany 表示一对多关系 * 2. 配置外键(中间表) * @JoinColumn: 配置外键 * name: 外键字段名称 * referencedColumnName:参照主表的主键字段名称 * 在客户实体类上 添加了外键配置,所以对于客户而言,也具备了维护外键的作用 */ @OneToMany(targetEntity = LinkMan.class) @JoinColumn(name = "lkm_cust_id",referencedColumnName = "cust_id") private Set<LinkMan> linkMans = new HashSet<LinkMan>(); }
联系人表
public class LinkMan { @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;//联系人备注 /** * 配置联系人到客户的多对一关系 * 使用注解的形式配置多对一关系 * 1.配置表关系 * @ManyToOne : 配置多对一关系 * targetEntity:对方的实体类字节码 * 2.配置外键(中间表) * * * 配置外键的过程,配置到了多的一方,就会在多的一方维护外键 * */ @ManyToOne(targetEntity = Customer.class) @JoinColumn(name = "lkm_cust_id",referencedColumnName = "cust_id") private Customer customer;
测试代码
@Test @Transactional @Rollback(false) public void testAff(){ //创建一个客户 Customer customer = new Customer(); customer.setCustName("百度"); LinkMan linkMan = new LinkMan(); linkMan.setLkmName("小李"); /*LinkMan linkMan2 = new LinkMan(); linkMan.setLkmName("小李2");*/ customer.getLinkMans().add(linkMan); customerDao.save(customer); linkManDao.save(linkMan); }
运行之后可以在表中看到link _man 表中lkm_cust_id 会有外键
说明实体之间已经建立联系,也就是外键维护
如果没有这一行
customer.getLinkMans().add(linkMan);
是不会生成外键
实际上看控制台会知道 执行了两条insert语句 以及一条update 更新外键的语句
这里是通过客户维护到联系人 同样联系人也可以维护到客户 却只有两条insert语句
@Test @Transactional @Rollback(false) public void testAff01(){ //创建一个客户 Customer customer = new Customer(); customer.setCustName("百度"); LinkMan linkMan = new LinkMan(); linkMan.setLkmName("小李"); linkMan.setCustomer(customer); customerDao.save(customer); linkManDao.save(linkMan); }
同样都能到达效果,但 多对一中 一的一方会维护外键 多了update语句
所以一般情况下 会放弃一的一方放弃维护权
题外:实体上我用的@Data 但是测试时会报错,就换成了@Setter @Getter ???
删除主表数据
1. 默认情况下从表数据会把外键设置为null,然后删除主表数据,如果有非空约束,则报错
2. 如果放弃了维护关联关系,则不能删除(于外键是否为空,没有关系),因为在删除时根本不会去更新从表的外键字段
3. 如果非要删除,使用级联删除引用
级联 :
操作一个对象的同时操作他的关联对象
1.需要区分操作的主体
2.需要在主体上添加级联属性(注解) -------cascade
@Test @Transactional @Rollback(false) public void testAff02(){ //创建一个客户 Customer customer = new Customer(); customer.setCustName("百度"); LinkMan linkMan = new LinkMan(); linkMan.setLkmName("小李"); linkMan.setCustomer(customer); customer.getLinkMans().add(linkMan); customerDao.save(customer); }
去掉了
linkManDao.save(linkMan);
删除
cascada
CascadeType {
all 所以
MERGE 更新
persist 保存
remove 删除
}
需要之前的create 改为 update
@Test @Transactional @Rollback(false) public void testAff03(){ Customer customer = customerDao.getOne((long) 1); customerDao.delete(customer); }