Java Hibernate Spring双向多对多删除不工作
我在尝试在多对多关系中进行删除时遇到问题。首先我想提一下这个故事。我有两个实体类,分别称为Post和Category,这里的Post与Category相关联,反之亦然。我可以创建类别和帖子,在创建或编辑帖子时,我可以关联类别,这没有问题。当我从帖子中删除一个类别时,问题就出现了。没有抛出异常或错误,但不会将其删除 通常,正如您在代码下面看到的,在一个post集中,当我删除一个category对象并保存该对象时,hibernate将负责删除共享表中的相关关系,但这并不是偶然发生的 除此之外,我尝试了多种解决方案,但它们也没有完全奏效Java Hibernate Spring双向多对多删除不工作,java,mysql,spring,hibernate,jakarta-ee,Java,Mysql,Spring,Hibernate,Jakarta Ee,我在尝试在多对多关系中进行删除时遇到问题。首先我想提一下这个故事。我有两个实体类,分别称为Post和Category,这里的Post与Category相关联,反之亦然。我可以创建类别和帖子,在创建或编辑帖子时,我可以关联类别,这没有问题。当我从帖子中删除一个类别时,问题就出现了。没有抛出异常或错误,但不会将其删除 通常,正如您在代码下面看到的,在一个post集中,当我删除一个category对象并保存该对象时,hibernate将负责删除共享表中的相关关系,但这并不是偶然发生的 除此之外,我尝试
@Entity
@Table(name = "posts")
public class Post {
@Id
@Column(name = "postid")
@GeneratedValue(strategy = GenerationType.AUTO)
private long postId;
@Column(name = "postTitle")
private String postTitle;
@Column(name = "postContext")
@Type(type = "text")
private String postContext;
@Column(name = "postedDate")
private Date postedDate;
@Column(name = "visitCount")
private long visitCount;
@Column(name = "publishable")
private boolean publishable;
@ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE}, targetEntity = Category.class, fetch = FetchType.EAGER)
//@ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE}, fetch = FetchType.EAGER,mappedBy = "posts")
@JoinTable(name = "post_category", joinColumns = {@JoinColumn(name = "postid")}, inverseJoinColumns = {@JoinColumn(name = "categoryid")})
private Set<Category> categories = new HashSet<>();
@OneToOne(cascade = CascadeType.ALL)
private User user;
public Post() {
}
public Post(String postTitle, String postContext, Date postedDate, boolean publishable, Set<Category> categories, User user) {
this.postTitle = postTitle;
this.postContext = postContext;
this.postedDate = postedDate;
this.publishable = publishable;
this.categories = categories;
this.user = user;
}
public long getPostId() {
return postId;
}
public void setPostId(long postId) {
this.postId = postId;
}
public String getPostTitle() {
return postTitle;
}
public void setPostTitle(String postTitle) {
this.postTitle = postTitle;
}
public String getPostContext() {
return postContext;
}
public void setPostContext(String postContext) {
this.postContext = postContext;
}
public Date getPostedDate() {
return postedDate;
}
public long getVisitCount() {
return visitCount;
}
public void setVisitCount(long visitCount) {
this.visitCount = visitCount;
}
public void setPostedDate(Date postedDate) {
this.postedDate = postedDate;
}
public boolean isPublishable() {
return publishable;
}
public void setPublishable(boolean publishable) {
this.publishable = publishable;
}
public Set<Category> getCategories() {
return categories;
}
public void setCategories(Set<Category> categories) {
this.categories = categories;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
@Entity
@Table(name = "categories")
public class Category {
@Id
@Column(name = "categoryid")
@GeneratedValue(strategy = GenerationType.AUTO)
private long categoryId;
@Column(name = "categoryName")
private String categoryName;
@Column(name = "createdDate")
private Date createdDate;
@ManyToOne
@JoinColumn(name = "parent_category_id")
private Category parentCategory;
@OneToMany(mappedBy = "parentCategory", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
public Set<Category> subCategories = new HashSet<>();
// @ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE}, fetch = FetchType.EAGER, targetEntity = Post.class)
// @JoinTable(name = "post_category", joinColumns = {@JoinColumn(name = "categoryid")}, inverseJoinColumns = {@JoinColumn(name = "postid")})
@ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE}, fetch = FetchType.EAGER,mappedBy = "categories")
private Set<Post> posts = new HashSet<>();
public Category() {
}
public Category(String categoryName) {
this.categoryName = categoryName;
}
public Category(String categoryName, Date createdDate, Category parentCategory) {
this.categoryName = categoryName;
this.createdDate = createdDate;
this.parentCategory = parentCategory;
this.subCategories = new HashSet<>();
if (parentCategory != null) {
parentCategory.subCategories.add(this);
}
}
public Set<Post> getPosts() {
return posts;
}
public void setPosts(Set<Post> posts) {
this.posts = posts;
}
public long getCategoryId() {
return categoryId;
}
public void setCategoryId(long categoryId) {
this.categoryId = categoryId;
}
public String getCategoryName() {
return categoryName;
}
public void setCategoryName(String categoryName) {
this.categoryName = categoryName;
}
public Date getCreatedDate() {
return createdDate;
}
public void setCreatedDate(Date createdDate) {
this.createdDate = createdDate;
}
public Category getParentCategory() {
return parentCategory;
}
public void setParentCategory(Category parentCategory) {
this.parentCategory = parentCategory;
}
public Set<Category> getSubCategories() {
return subCategories;
}
public void setSubCategories(Set<Category> subCategories) {
this.subCategories = subCategories;
}
}
编辑
后编辑DAO方法
更新
几天来,我一直在谷歌上搜索和查看不同的源代码,最后我决定在非J2EE环境中使用Hibernate和EclipseLink JPA测试整个结构和实体类,而不使用Spring。我逐渐意识到,在Spring容器中使用应用程序时,问题仍然存在,但如果没有Spring环境,令人惊讶的是根本就没有这样的问题。所有的测试都很好,双向多对多注释也很好,我一直想让它工作
我想在此分享spring配置和maven pom配置,供您观察并提出建议。简单地说,我在hibernate端管理事务。如果你看到任何差距或错误,我将非常感谢你的帮助
再次感谢
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<context:property-placeholder location="classpath:hibernate.properties"/>
<!-- Hibernate connection configuration -->
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${orm.connection.driver_class}"/>
<property name="url" value="${orm.connection.url}"/>
<property name="username" value="${orm.connection.username}"/>
<property name="password" value="${orm.connection.password}"/>
</bean>
<!-- Hibernate configuration settings -->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="packagesToScan" value="com.tugrulaslan.entity"/>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${orm.dialect}</prop>
<prop key="hibernate.show_sql">${orm.show_sql}</prop>
<prop key="hibernate.hbm2ddl.auto">${orm.hbm2ddl.auto}</prop>
<!-- --> <prop key="current_session_context_class">thread</prop>
</props>
</property>
</bean>
<!-- Hibernate Session Factory creation
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/> -->
<context:component-scan base-package="com.tugrulaslan"/>
</beans>
${orm.dial}
${orm.show_sql}
${orm.hbm2ddl.auto}
线
pom.xml
http://maven.apache.org/maven-v4_0_0.xsd">
4.0.0
com.tugrulaslan
网络应用
战争
1.0-快照
BlogWebApp Maven Webapp
1.7
3.1
4.11
5.1.34
4.3.6.最终版本
1.0.2
4.0.6.1发布
朱尼特
朱尼特
${junit.version}
测试
mysql
mysql连接器java
${mysql connector.version}
org.hibernate
冬眠核心
${hibernate.version}
javax.persistence
持久性api
${javax persistence api.version}
org.springframework
spring上下文
${spring.version}
org.springframework
春季甲虫
${spring.version}
org.springframework
弹簧试验
${spring.version}
BlogWebApp
org.apache.maven.plugins
maven编译器插件
${maven编译器plugin.version}
${project java.version}
${project java.version}
在您的服务中,检查您是否在删除后提交,如下所示
session.getTransaction().commit();
经过长时间的研究和测试,我发现在调试应用程序时出现了什么问题。当我调试删除部分时,我确实突然注意到集合中的大小和元素与删除操作之前相同。无法确定目标集合中对象的相等性,因此删除操作会导致l操作无法继续 在我承认这一点之后,我立即重写了object equals方法,并包含了唯一的不可变和不可变字段只有在我的例子中,它似乎是category id,其他字段可以立即互换。因此,在下面的示例中,您可以找到完整的category实体,其中包含IntelliJ IDE生成的重写对象等于方法 除此之外,我还针对两种情况进行了案例研究,以了解我在Category实体中定义的post集合上碰巧定义的cascade选项是否重要,其中提到了“cascade={CascadeType.PERSIST,CascadeType.MERGE}”所以我最终意识到,在多对多关系中定义的对应级联的存在与否没有区别。它的存在并没有改变其他不同测试用例中所经历的任何事情 我希望我的问题和解决方案能给你带来一些启发,如果你遇到类似的问题,能帮助你解决
@Entity
@Table(name = "categories")
public class Category {
@Id
@Column(name = "categoryid")
@GeneratedValue(strategy = GenerationType.AUTO)
private long categoryId;
@Column(name = "categoryName")
private String categoryName;
@Column(name = "createdDate")
private Date createdDate;
@ManyToOne
@JoinColumn(name = "parent_category_id")
private Category parentCategory;
@OneToMany(mappedBy = "parentCategory", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private Set<Category> subCategories = new HashSet<>();
@ManyToMany(fetch = FetchType.EAGER, mappedBy = "categories")
private Set<Post> posts = new HashSet<>();
public Category() {
}
public Category(String categoryName) {
this.categoryName = categoryName;
}
public Category(String categoryName, Date createdDate, Category parentCategory, Set<Category> subCategories, Set<Post> posts) {
this.categoryName = categoryName;
this.createdDate = createdDate;
this.parentCategory = parentCategory;
this.subCategories = new HashSet<>();
if (parentCategory != null) {
parentCategory.subCategories.add(this);
}
this.subCategories = subCategories;
this.posts = posts;
}
public Set<Post> getPosts() {
return posts;
}
public void setPosts(Set<Post> posts) {
this.posts = posts;
}
public long getCategoryId() {
return categoryId;
}
public void setCategoryId(long categoryId) {
this.categoryId = categoryId;
}
public String getCategoryName() {
return categoryName;
}
public void setCategoryName(String categoryName) {
this.categoryName = categoryName;
}
public Date getCreatedDate() {
return createdDate;
}
public void setCreatedDate(Date createdDate) {
this.createdDate = createdDate;
}
public Category getParentCategory() {
return parentCategory;
}
public void setParentCategory(Category parentCategory) {
this.parentCategory = parentCategory;
}
public Set<Category> getSubCategories() {
return subCategories;
}
public void setSubCategories(Set<Category> subCategories) {
this.subCategories = subCategories;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Category category = (Category) o;
return categoryId == category.categoryId;
}
@Override
public int hashCode() {
return (int) (categoryId ^ (categoryId >>> 32));
}
@实体
@表(name=“categories”)
公共类类别{
@身份证
@列(name=“categoryid”)
@GeneratedValue(策略=GenerationType.AUTO)
私人长类别;
@列(name=“categoryName”)
私有字符串categoryName;
@列(name=“createdDate”)
私人日期创建日期;
@许多酮
@JoinColumn(name=“父类\类别\ id”)
私人类;
@OneToMany(mappedBy=“parentCategory”,cascade=CascadeType.ALL,fetch=FetchType.EAGER)
私有集子类别=新HashSet();
@ManyToMany(fetch=FetchType.EAGER,mappedBy=“categories”)
private Set posts=new HashSet();
公共类别(){
}
公共类别(字符串类别名称){
this.categoryName=categoryName;
}
公共类别(字符串类别名称、创建日期、类别父类别、设置子类别、设置帖子){
this.categoryName=categoryName;
this.createdDate=createdDate;
this.parentCategory=parentCategory;
this.subCategories=new HashSet();
if(parentCategory!=null){
parentCategory.subCategories.add(此);
}
this.subCategories=子类别;
<properties>
<project-java.version>1.7</project-java.version>
<maven-compiler-plugin.version>3.1</maven-compiler-plugin.version>
<junit.version>4.11</junit.version>
<mysql-connector.version>5.1.34</mysql-connector.version>
<hibernate.version>4.3.6.Final</hibernate.version>
<javax-persistance-api.version>1.0.2</javax-persistance-api.version>
<spring.version>4.0.6.RELEASE</spring.version>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql-connector.version}</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>${hibernate.version}</version>
</dependency>
<dependency>
<groupId>javax.persistence</groupId>
<artifactId>persistence-api</artifactId>
<version>${javax-persistance-api.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>${spring.version}</version>
</dependency>
<!--
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring.version}</version>
</dependency>-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
</dependency>
</dependencies>
<build>
<finalName>BlogWebApp</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven-compiler-plugin.version}</version>
<configuration>
<source>${project-java.version}</source>
<target>${project-java.version}</target>
</configuration>
</plugin>
</plugins>
</build>
session.getTransaction().commit();
@Entity
@Table(name = "categories")
public class Category {
@Id
@Column(name = "categoryid")
@GeneratedValue(strategy = GenerationType.AUTO)
private long categoryId;
@Column(name = "categoryName")
private String categoryName;
@Column(name = "createdDate")
private Date createdDate;
@ManyToOne
@JoinColumn(name = "parent_category_id")
private Category parentCategory;
@OneToMany(mappedBy = "parentCategory", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private Set<Category> subCategories = new HashSet<>();
@ManyToMany(fetch = FetchType.EAGER, mappedBy = "categories")
private Set<Post> posts = new HashSet<>();
public Category() {
}
public Category(String categoryName) {
this.categoryName = categoryName;
}
public Category(String categoryName, Date createdDate, Category parentCategory, Set<Category> subCategories, Set<Post> posts) {
this.categoryName = categoryName;
this.createdDate = createdDate;
this.parentCategory = parentCategory;
this.subCategories = new HashSet<>();
if (parentCategory != null) {
parentCategory.subCategories.add(this);
}
this.subCategories = subCategories;
this.posts = posts;
}
public Set<Post> getPosts() {
return posts;
}
public void setPosts(Set<Post> posts) {
this.posts = posts;
}
public long getCategoryId() {
return categoryId;
}
public void setCategoryId(long categoryId) {
this.categoryId = categoryId;
}
public String getCategoryName() {
return categoryName;
}
public void setCategoryName(String categoryName) {
this.categoryName = categoryName;
}
public Date getCreatedDate() {
return createdDate;
}
public void setCreatedDate(Date createdDate) {
this.createdDate = createdDate;
}
public Category getParentCategory() {
return parentCategory;
}
public void setParentCategory(Category parentCategory) {
this.parentCategory = parentCategory;
}
public Set<Category> getSubCategories() {
return subCategories;
}
public void setSubCategories(Set<Category> subCategories) {
this.subCategories = subCategories;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Category category = (Category) o;
return categoryId == category.categoryId;
}
@Override
public int hashCode() {
return (int) (categoryId ^ (categoryId >>> 32));
}