以博客实体类和用户实体类为例,他们之间是多对多的关系,即一个博客可以被多个用户收藏,一个用户也可以收藏多个博客,现在考虑三个问题:
1.双方是否持有对方集合的引用
2.当双方均持有对方集合的引用时,哪一方拥有对于联系的维护权限
3.当双方均持有对方集合的引用时,如何设置级联关系
首先第一个问题,双方是否持有对方的引用。我认为这取决于在传递数据(一方的pojo对象)时是否可能需要同时传递另一方的pojo对象集合。例如,若在传递用户时同时需要传递其收藏的博客列表,则用户类需要持有博客集合的引用,反之亦然。
当双方均持有对方集合的引用时,设有下面用户类和博客类(省略setter和getter方法)
@Entity
@Table(name="user_inf")
public class User
{
//新闻编号,设置为自动增长
@Id@Column(name="user_id")
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer userId;
//新闻的标签
@ManyToMany(targetEntity = Blog.class,cascade=CascadeType.ALL)
@JoinTable(name = "user_blog", joinColumns = { @JoinColumn(name = "user_id") }, inverseJoinColumns = { @JoinColumn(name = "blog_id") })
private Set<Blog> blogs = new HashSet<Blog>();
@Entity
@Table(name="blog_inf")
public class Blog {
//新闻编号,设置为自动增长
@Id@Column(name="blog_id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer blogId;
//mappedBy后面的属性为User类中相应的集合字段名
@ManyToMany(mappedBy="blogs")
private Set<User> user = new HashSet<User>();
现在看第二个问题,当双方均持有对方集合的引用时,哪一方拥有对于联系的维护权限。一方拥有对于联系的维护权限=可以通过对该方对象的修改来修改中间表(多对多关系会产生一个中间表)。例如,若想通过修改用户对象的博客集合这一属性来对中间表进行修改,如下列语句
//数据库中已存在主键为1的博客记录
Blog blog = new Blog();
blog.setBlogId(1);
//数据库中已存在主键为1的用户记录
User user = new User();
user.setUserId(1);
//为id为1的用户添加收藏id为1的博客
user.getBlogs().add(blog);
sess.update(user);
//执行后中间表user_blog多了一行记录
则应让用户类持有对于联系的维护权限,此时应在博客的用户集合属性的manyToMany注解中添加mappedBy属性,表示博客这一端放弃对联系的维护权限。关于这个问题可以参考一下我的另一篇博客Hibernate注解之@ManyToMany
最后第三个问题,当双方均持有对方集合的引用时,如何设计级联关系。例如,若想在添加用户对象时,同时添加该用户对象持有的博客对象,,如下列语句
//新的用户对象
User user = new User();
//该用户对象持有两个新的博客对象
user.getBlogs().add(new Blog());
user.getBlogs().add(new Blog());
//同时保存用户对象以及其关联的博客对象
sess.save(user);
//执行后user_inf表多了一行记录
//执行后blog_inf表多了二行记录
//执行后中间表user_blog多了二行记录
此时应在用户的博客集合属性的ManyToMany注解中添加cascade=CascadeType.ALL属性,表示对用户表增加,更新等操作会级联到博客表。
另外在级联操作中有两点需要注意:
1.在级联删除时,若需要在删除用户记录的同时级联删除与其关联的博客记录,则在调用sess.delete(user)方法进行删除时,user对象中必须持有相应博客对象的引用,若user对象中仅有userId属性而blogs属性为空,那么此时只能删除用户记录和中间表内的相关记录,无法级联删除相应的博客记录。
2.在级联操作时,不要通过对放弃维护关联关系的那一方进行级联操作,因为该方不具备修改中间表的权限,而在级联操作中,必然会对中间表进行修改,这样做通常会产生一个由外键约束而导致的异常 。