Hibernate Spring双向多向删除无法正常工作

时间:2015-06-19 13:46:25

标签: java mysql spring hibernate java-ee

我在尝试以多对多关系进行删除时遇到问题。首先,我想提一下这个故事。我有两个名为Post和Category的实体类,这里的帖子与Categories相关联,而且其他方式也是如此。我可以创建类别和发布,在创建或编辑帖子时,我可以将类别关联没问题。当我从帖子中删除某个类别时会出现此问题。没有抛出异常或错误,但它不会删除它。

正常情况下,您将看到代码,在帖子集中,当我删除类别对象并保存对象时,hibernate将负责删除共享表中的关系关系,但它不会发生! / p>

除此之外,我尝试了多种解决方案,但它们也没有完全解决。

  1. https://forum.hibernate.org/viewtopic.php?f=1&t=17
  2. Hibernate Bidirectional ManyToMany delete issue 3。http://www.codereye.com/2009/06/hibernate-bi-directional-many-to-many.html 4。Hibernate Bi-Directional Many to Many association creates duplicates 5。https://howtoprogramwithjava.com/hibernate-manytomany-unidirectional-bidirectional/
  3. 发布实体

    @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;
        }
    }
    

    测试

    @Test
        public void stage09_EditCreatedPostTest() {
            //Fetch the post
            Post post = appService.getPostByName(postName);
    
            //Fetch the child category;
            Category category = appService.getCategoryByName(childCatName);
    
            //Remove the child category
            post.getCategories().remove(category);
    
            //Selected child category is not null
            assertNotNull(category);
    
            appService.editPost(post);
    
            //Fetch the post again
            Post post2 = appService.getPostByName(postName);
    
            //Check the post2 object it is not null
            assertNotNull(post2);
    
            //Check category size
            assertEquals(1, post2.getCategories().size());
        }
    

    修改 发布编辑DAO方法

    public void editPost(Post post) {
            Session session = sessionFactory.openSession();
            Transaction transaction = session.beginTransaction();
            try {
                session.update(post);
                transaction.commit();
            } catch (HibernateException e) {
                System.err.println(e);
                transaction.rollback();
            } finally {
                session.close();
            }
        }
    

    更新

    几天来,我一直在谷歌上搜索并查看不同的来源,最后我决定在没有Spring的情况下使用Hibernate和EclipseLink JPA在非J2EE环境中测试整个结构和实体类。我已经意识到在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>
    

    的pom.xml http://maven.apache.org/maven-v4_0_0.xsd">     4.0.0     com.tugrulaslan     Web应用程序     战争     1.0-SNAPSHOT     BlogWebApp Maven Webapp     http://maven.apache.org

    <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>
    

2 个答案:

答案 0 :(得分:0)

在您的服务中检查您是否在删除后提交

session.getTransaction().commit(); 

答案 1 :(得分:0)

经过长时间的研究和测试,我发现在调试应用程序时问题是什么。当我调试删除部分时,我突然注意到Set集合中的大小和元素与删除操作之前的相同。无法确定目标集合中对象的相等性,因此无法继续执行删除操作。

在我承认这一点之后,我已经及时覆盖了对象equals方法并包含了唯一的不可变和不可更改的字段,只有在我的情况下似乎是类别id,其他字段是可立即互换的。因此,下面你将找到完整的Category实体,其中被覆盖的对象等于IntelliJ IDE生成的方法。

除此之外,我已经针对两种情况进行了案例,以确定我在类别实体中定义的上面集合定义的级联选项是否至关重要,提到“ 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));
    }