public class OneToManyTest {
@Autowired
private CustomerDao customerDao;
@Autowired
private LinkManDao linkManDao;
}
1. 测试添加数据
执行保存操作,保存一个客户和一个联系人,同时建立客户和联系人之间关联关系(双向一对多的关联关系)
@Test
@Transactional //配置事务
@Rollback(false) //设置不自动回滚
public void testAdd(){
//创建一个客户,创建一个联系人
Customer customer = new Customer();
customer.setCustName(“客户1”);
customer.setCustLevel(“VIP客户”);
customer.setCustSource(“网络”);
customer.setCustIndustry(“商业办公”);
customer.setCustAddress(“北京”);
customer.setCustPhone(“111-11111111”);
LinkMan linkMan=new LinkMan();
linkMan.setLkmName(“联系人1”);
linkMan.setLkmGender(“male”);
linkMan.setLkmMobile(“11111111111”);
linkMan.setLkmPhone(“111-11111111”);
linkMan.setLkmEmail(“abc@qq.com”);
linkMan.setLkmPosition(“IT讲师”);
linkMan.setLkmMemo(“很厉害老师”);
/**
-
配置了联系人到客户的关系(多对一关系)
-
只发送了两条保存语句insert
-
因为我们配置了联系人对客户的映射关系(多对一)
*/
linkMan.setCustomer(customer);
/**
-
配置了客户到联系人的关系(一对多关系)
-
从客户角度:发送两条insert语句,发送一条更新语句更新数据库(更新外键)
-
由于我们配置了客户到联系人的关系,客户可以对外键进行维护
*/
customer.getLinkMans().add(linkMan);
/**
-
会有一条多余的update语句
-
由于一的一方可以维护外键,会发送update语句
-
解决此问题:只需要在一的一方放弃维护权即可
*/
//由于配置了多的一方到一的一方的关联关系(当保存时就已经对外键赋值)
linkMan.setCustomer(customer);
//由于配置了一的一方到多的一方的关联关系(发送一条update语句)
customer.getLinkMans().add(linkMan);
customerDao.save(customer);
linkManDao.save(linkMan);
}
运行结果分析:
1.当我们只配置了多的一方到一的一方的关联关系时 linkMan.setCustomer(customer);执行了两条insert语句
2.当我们只配置了配置了一的一方到多的一方的关联关系时customer.getLinkMans().add(linkMan);执行了两条insert语句之后,还执行了update语句
3.当我们建立了双向的关联关系之后,先保存主表,再保存从表时:执行了两条insert语句之后,还执行了update语句
可以看出,在设置了双向关系之后,update语句语句是多余的,想要解决这个问题,我们可以让主表的一方放弃维护权,即修改Customer中的如下字段:
//@OneToMany(targetEntity=LinkMan.class)
//@JoinColumn(name=“lkm_cust_id”,referencedColumnName=“cust_id”)
//设置为
@OneToMany(mappedBy=“customer”)
2. 测试删除数据
@Test
@Transactional
@Rollback(false)//设置为不回滚
public void testDelete() {
customerDao.delete(1l);
}
在执行删除操作时,对于从表数据可以随时任意删除,当我们要删除主表数据数据时:
- 1. 有从表数据
在默认情况下,它会把外键字段置为null,然后删除主表数据。如果在数据库的表结构上,外键字段有非空约束,默认情况就会报错了。
如果配置了放弃维护关联关系的权利,则不能删除(与外键字段是否允许为null, 没有关系)因为在删除时,它根本不会去更新从表的外键字段,这时如果还想删除,可以使用级联删除引用,在实际开发中,级联删除请慎用!(在一对多的情况下)
- 2. 没有从表数据引用:随便删
级联操作: 指操作一个对象同时操作它的关联对象,只需要在操作主体的注解上配置cascade,就可以设置级联操作
/**
-
放弃了外键的维护权
-
mappedBy:对方配置的属性名称(可以配置到设置多表的映射关系的注解上)
-
cascade :配置级联
-
CascadeType.ALL 所有
-
CascadeType.MERGE 更新
-
CascadeType.PERSIST 保存
-
CascadeType.REMOVE 删除
*/
@OneToMany(mappedBy = “customer”,cascade = CascadeType.ALL)
确定两张表之间的关系,对于用户和角色之间的关系,用户可以表示某一个人,它可以有很多中身份,在学校可以是学生,做兼职时可以被称作是临时工,在家里又有了子女的身份。同时对于某一个角色,也可以被多个用户拥有,每个人都可以是子女,都可以是学生,都可以是临时工。
表关系建立:
多对多的表关系建立靠的是中间表,其中用户表和中间表的关系是一对多,角色表和中间表的关系也是一对多,如下图所示:
实体类关系建立以及映射配置:
在实体类中描述出两个实体的关系,一个用户可以具有多个角色,所以在用户实体类中应该包含多个角色的信息,代码如下:
/**
-
@Author: Ly
-
@Date: 2020-12-01 16:57
*/
@Entity
@Table(name = “sys_user”)
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = “user_id”)
private Long userId;
@Column(name = “user_name”)
private String username;
@Column(name = “user_age”)
private Integer age;
/**
-
配置用户到角色的多对多关系
-
配置多对多关系
-
1.声明表关系的配置
-
@ManyToMany(targetEntity = Role.class)//多对多
-
targetEntity:代表对方的实体类字节码
-
2.配置中间表(包含两个外键)
-
@JoinTable
-
name:中间表的名称
-
joinColumns: 配置当前对象在中间表的外键
-
{@JoinColumn的数组 name:外键名,referencedColumnName 参照主表的主键名}
-
inverseJoinColumns:配置对方对象在中间表的外键
*/
@ManyToMany(targetEntity = Role.class,cascade = CascadeType.ALL)
@JoinTable(name = “sys_user_role”,
//joinColumns,当前对象在中间表中的外键
joinColumns = {@JoinColumn(name = “sys_user_id”,referencedColumnName = “user_id”)},
//inverseJoinColumns ,对方对象在中间表中的外键
inverseJoinColumns = {@JoinColumn(name = “sys_role_id”,referencedColumnName = “role_id”)}
)
private Set roles=new HashSet();
/**
- Get、Set、toString
*/
}
一个角色可以赋予多个用户,所以在角色实体类中应该包含多个用户的信息,代码如下:
/**
-
@Author: Ly
-
@Date: 2020-12-01 16:58
*/
@Entity
@Table(name = “sys_role”)
public class Role {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = “role_id”)
private Long roleId;
@Column(name = “role_name”)
private String roleName;
/**
-
配置角色到用户的多对多关系
-
配置多对多关系
-
1.声明表关系的配置
-
2.配置中间表
*/
// @ManyToMany(targetEntity = User.class)
// @JoinTable(name = “sys_user_role”,
// //joinColumns,当前对象在中间表中的外键
// joinColumns = {@JoinColumn(name = “sys_role_id”,referencedColumnName = “role_id”)},
// //inverseJoinColumns ,对方对象在中间表中的外键
// inverseJoinColumns = {@JoinColumn(name = “sys_user_id”,referencedColumnName = “user_id”)}
// )
@ManyToMany(mappedBy = “roles”)
private Set users =new HashSet();
/**
- Get、Set、toString
*/
}
多对多的操作:
新建测试类:
/**
-
@Author: Ly
-
@Date: 2020-12-01 09:06
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = “classpath:applicationContext.xml”)
public class ManyToManyTest {
@Autowired
private UserDao userDao;
@Autowired
private RoleDao roleDao;
}
1. 测试保存操作
保存用户和角色,用户与角色之间满足多对多关系
/**
- 保存一个用户,保存一个角色
*/
@Test
@Transactional
@Rollback(false)
public void testAdd(){
User user=new User();
user.setUsername(“张三”);
user.setAge(20);
Role role=new Role();
role.setRoleName(“程序员”);
//配置用户到角色的关系,可以对中间表中的数据进行维护
user.getRoles().add(role);
//配置角色到用户的关系,可以对中间表中的数据进行维护
role.getUsers().add(user);
userDao.save(user);
roleDao.save(role);
}
出现的问题: 在多对多(保存)中,如果双向都设置关系,意味着双方都维护中间表,都会往中间表插入数据,中间表的2个字段又作为联合主键,所以报错,主键重复,
解决保存失败的问题: 只需要在任意一方放弃对中间表的维护权即可,推荐在被动的一方放弃,配置如下:
//放弃对中间表的维护权,解决保存中主键冲突的问题
@ManyToMany(mappedBy=“roles”)
private Set users = new HashSet();
级联操作:
/**
-
放弃了外键的维护权
-
mappedBy:对方配置的属性名称(可以配置到设置多表的映射关系的注解上)
-
cascade :配置级联
-
CascadeType.ALL 所有
-
CascadeType.MERGE 更新
-
CascadeType.PERSIST 保存
-
CascadeType.REMOVE 删除
*/
@ManyToMany(mappedBy = “customer”,cascade = CascadeType.ALL)
测试级联操作:
/**
- 测试级联添加(保存一个用户的同时保存关联的角色)
*/
@Test
@Transactional
@Rollback(false)
public void testCascadeAdd(){
User user=new User();
user.setUsername(“张三”);
user.setAge(20);
Role role=new Role();
role.setRoleName(“程序员”);
//配置用户到角色的关系,可以对中间表中的数据进行维护
user.getRoles().add(role);
//配置角色到用户的关系,可以对中间表中的数据进行维护
role.getUsers().add(user);
userDao.save(user);
}
/**
-
测试级联删除(禁用)
-
在多对多的删除时,双向级联删除根本不能配置
-
如果配了的话,如果数据之间有相互引用关系,可能会清空所有数据
*/
@Test
@Transactional
@Rollback(false)
public void testCascadeRemove(){
testCascadeAdd();
//查询1号用户
User user=userDao.findOne(1l);
//删除1号用户
userDao.delete(user);
}
1. 对象导航查询:
小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级Java工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年最新Java开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Java)
结语
小编也是很有感触,如果一直都是在中小公司,没有接触过大型的互联网架构设计的话,只靠自己看书去提升可能一辈子都很难达到高级架构师的技术和认知高度。向厉害的人去学习是最有效减少时间摸索、精力浪费的方式。
我们选择的这个行业就一直要持续的学习,又很吃青春饭。
虽然大家可能经常见到说程序员年薪几十万,但这样的人毕竟不是大部份,要么是有名校光环,要么是在阿里华为这样的大企业。年龄一大,更有可能被裁。
送给每一位想学习Java小伙伴,用来提升自己。
本文到这里就结束了,喜欢的朋友可以帮忙点赞和评论一下,感谢支持!
索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!**
因此收集整理了一份《2024年最新Java开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
[外链图片转存中…(img-kDq8Aiou-1711154480405)]
[外链图片转存中…(img-d6exg3QH-1711154480406)]
[外链图片转存中…(img-GJAeLrdK-1711154480407)]
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Java)
[外链图片转存中…(img-Z3I7d8pD-1711154480407)]
结语
小编也是很有感触,如果一直都是在中小公司,没有接触过大型的互联网架构设计的话,只靠自己看书去提升可能一辈子都很难达到高级架构师的技术和认知高度。向厉害的人去学习是最有效减少时间摸索、精力浪费的方式。
我们选择的这个行业就一直要持续的学习,又很吃青春饭。
虽然大家可能经常见到说程序员年薪几十万,但这样的人毕竟不是大部份,要么是有名校光环,要么是在阿里华为这样的大企业。年龄一大,更有可能被裁。
送给每一位想学习Java小伙伴,用来提升自己。
[外链图片转存中…(img-e9rP2V6e-1711154480408)]
本文到这里就结束了,喜欢的朋友可以帮忙点赞和评论一下,感谢支持!