Java中用Hibernate框架:实现多对多关联删除问题!

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java中用Hibernate框架:实现多对多关联删除问题!相关的知识,希望对你有一定的参考价值。

实现方法:我也设置XML属性了! inverse="true" cascade="all" 在删除时还是提示于数据库约束冲突//删除项目 public void deleteProject() Session session=HibernateSessionFactory.getSession(); Transaction tran=null; try tran=session.beginTransaction(); Project project=(Project)session.load(Project.class, new Long(7)); Employee employee=(Employee)session.load(Employee.class, new Long(14)); Hibernate.initialize(project.getEmployees());//加载关联信息 project.getEmployees().remove(employee); employee.getProjects().remove(project); project.getEmployees().removeAll(project.getEmployees()); employee.getProjects().removeAll(employee.getProjects()); session.update(employee); session.update(project); session.delete(project); tran.commit(); catch(Exception ex) tran.rollback(); ex.printStackTrace(); finally session.close();

级联删除操作是很危险的,尽量还是不要使用。一定要使用的话要确保只是两张表之间有删除的级联操作,拿a、b、c三张表来说,a表和b表删除级联且b与c没有关联上删除级联,则可以删除,如果b与c也有删除级联,那就可能提升约束冲突。 参考技术A 萨芬

Hibernate:n-n关联关系

  • 背景:

  在实际开发中我们会遇到表的多对多关联,比如:一篇博客文章,它可以同时属于JAVA分类、Hibernate分类。

  因此,我们在hibernate的学习文章系列中,需要学会如何使用hibernate来实现多对多的关联关系。

  在hibernate实现多对多的关联关系中,也是需要创建一个中间表来存储、维护两张表的多对多的关系。具体实现有两种可选方案:单向多对多、双向多对多。

  • 单向多对多:

 新建一个java project,定义项目名称为:hibernate07;在src下添加hibernate.cfg.xml

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <!DOCTYPE hibernate-configuration PUBLIC
 3         "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
 4         "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
 5 <hibernate-configuration>
 6     <session-factory>
 7         <property name="hibernate.connection.username">root</property>
 8         <property name="hibernate.connection.password">123456</property>
 9         <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
10         <property name="hibernate.connection.url">jdbc:mysql://localhost/hibernate_01</property>
11 
12         <!-- <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property> 
13             <property name="hibernate.dialect">org.hibernate.dialect.MySQLInnoDBDialect</property> -->
14         <property name="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property>
15 
16         <property name="hibernate.show_sql">true</property>
17 
18         <property name="hibernate.format_sql">true</property>
19 
20         <property name="hibernate.hbm2ddl.auto">update</property>
21 
22         <property name="hibernate.current_session_context_class">thread</property>
23 
24         <property name="hibernate.c3p0.max_size">500</property>
25         <property name="hibernate.c3p0.min_size">20</property>
26         <property name="hibernate.c3p0.max_statements">10</property>
27         <property name="hibernate.c3p0.timeout">2000</property>
28         <property name="hibernate.c3p0.idle_test_period">2000</property>
29         <property name="hibernate.c3p0.acquire_increment">10</property>
30 
31         <mapping resource="com/dx/hibernate06/n2n/ProductCategory.hbm.xml" />        
32         <mapping resource="com/dx/hibernate06/n2n/ProductItem.hbm.xml" />
33             
34     </session-factory>
35 </hibernate-configuration>
View Code

在src下创建包com.dx.hibernate06.n2n,在包下创建:

ProductCategory.java(在category这个类中创建了一个Set<ProductItem> productItems 属性)

 1 package com.dx.hibernate06.n2n;
 2 
 3 import java.util.HashSet;
 4 import java.util.Set;
 5 
 6 public class ProductCategory {
 7     private Integer id;
 8     private String name;
 9     private String detail;
10     private Set<ProductItem> productItems = new HashSet<>();
11 
12     public ProductCategory() {
13 
14     }
15 
16     public ProductCategory(String name, String detail) {
17         super();
18         this.name = name;
19         this.detail = detail;
20     }
21 
22     public Integer getId() {
23         return id;
24     }
25 
26     public void setId(Integer id) {
27         this.id = id;
28     }
29 
30     public String getName() {
31         return name;
32     }
33 
34     public void setName(String name) {
35         this.name = name;
36     }
37 
38     public String getDetail() {
39         return detail;
40     }
41 
42     public void setDetail(String detail) {
43         this.detail = detail;
44     }
45 
46     public Set<ProductItem> getProductItems() {
47         return productItems;
48     }
49 
50     public void setProductItems(Set<ProductItem> productItems) {
51         this.productItems = productItems;
52     }
53 
54 }
View Code

ProductCategory.hbm.xml

 1 <?xml version="1.0"?>
 2 <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
 3 "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
 4 <!-- Generated 2017-6-7 22:33:53 by Hibernate Tools 3.5.0.Final -->
 5 <hibernate-mapping package="com.dx.hibernate06.n2n">
 6     <class name="ProductCategory" table="PRODUCT_CATEGORY">
 7         <id name="id" type="java.lang.Integer">
 8             <column name="ID" />
 9             <generator class="native" />
10         </id>
11         <property name="name" type="java.lang.String">
12             <column name="NAME" />
13         </property>
14         <property name="detail" type="java.lang.String">
15             <column name="DETAIL" />
16         </property>
17 
18         <set name="productItems" table="PRODUCT_CATEGORY_ITEM">
19             <key>
20                 <column name="CATEGORY_ID" />
21             </key>
22             <many-to-many class="ProductItem" column="ITEM_ID"></many-to-many>
23         </set>
24     </class>
25 </hibernate-mapping>
View Code

备注:在ProductCategory.hbm.xml的set节点我们定义的table属性,并定义了many-to-many节点用来指向ProductItem。

ProductItem.java

 1 package com.dx.hibernate06.n2n;
 2 
 3 public class ProductItem {
 4     private Integer id;
 5     private String title;
 6     private double price;
 7 
 8     public ProductItem() {
 9     }
10 
11     public ProductItem(String title, double price) {
12         super();
13         this.title = title;
14         this.price = price;
15     }
16 
17     public Integer getId() {
18         return id;
19     }
20 
21     public void setId(Integer id) {
22         this.id = id;
23     }
24 
25     public String getTitle() {
26         return title;
27     }
28 
29     public void setTitle(String title) {
30         this.title = title;
31     }
32 
33     public double getPrice() {
34         return price;
35     }
36 
37     public void setPrice(double price) {
38         this.price = price;
39     }
40 
41 }
View Code

ProductItem.hbm.xml

 1 <?xml version="1.0"?>
 2 <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
 3 "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
 4 <!-- Generated 2017-6-7 22:33:53 by Hibernate Tools 3.5.0.Final -->
 5 <hibernate-mapping>
 6     <class name="com.dx.hibernate06.n2n.ProductItem" table="PRODUCT_ITEM">
 7         <id name="id" type="java.lang.Integer">
 8             <column name="ID" />
 9             <generator class="native" />
10         </id>
11         <property name="title" type="java.lang.String">
12             <column name="TITLE" />
13         </property>
14         <property name="price" type="double">
15             <column name="PRICE" />
16         </property>
17     </class>
18 </hibernate-mapping>
View Code

测试类TestMain.java 

 1 package com.dx.hibernate06.n2n;
 2 
 3 import java.util.Date;
 4 import java.util.Set;
 5 
 6 import org.hibernate.Session;
 7 import org.hibernate.SessionFactory;
 8 import org.hibernate.Transaction;
 9 import org.hibernate.boot.Metadata;
10 import org.hibernate.boot.MetadataSources;
11 import org.hibernate.boot.model.naming.ImplicitNamingStrategyComponentPathImpl;
12 import org.hibernate.boot.registry.StandardServiceRegistry;
13 import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
14 import org.hibernate.metamodel.internal.MapMember;
15 import org.junit.After;
16 import org.junit.Before;
17 import org.junit.Test;
18 
19 public class TestMain {
20     private SessionFactory sessionFactory = null;
21     private Session session = null;
22     private Transaction transaction = null;
23 
24     @Before
25     public void init() {
26         StandardServiceRegistry standardRegistry = new StandardServiceRegistryBuilder().configure().build();
27         Metadata metadata = new MetadataSources(standardRegistry).getMetadataBuilder().applyImplicitNamingStrategy(ImplicitNamingStrategyComponentPathImpl.INSTANCE).build();
28 
29         sessionFactory = metadata.getSessionFactoryBuilder().build();
30         session = sessionFactory.getCurrentSession();
31         transaction = session.beginTransaction();
32     }
33 
34     @After
35     public void destory() {
36         transaction.commit();
37         session.close();
38         sessionFactory.close();
39     }
40 }
View Code

 测试代码:

添加测试函数1:

 1     @Test
 2     public void testInsert() {
 3         ProductCategory category1 = new ProductCategory();
 4         category1.setName("category1");
 5         category1.setDetail("Detail");
 6 
 7         ProductCategory category2 = new ProductCategory();
 8         category2.setName("category2");
 9         category2.setDetail("Detail");
10 
11         ProductItem item1 = new ProductItem();
12         item1.setTitle("item1");
13         item1.setPrice(110.00);
14 
15         ProductItem item2 = new ProductItem();
16         item2.setTitle("item2");
17         item2.setPrice(110.00);
18 
19         category1.getProductItems().add(item1);
20         category1.getProductItems().add(item2);
21 
22         category2.getProductItems().add(item1);
23         category2.getProductItems().add(item2);
24 
25         session.save(category1);
26         session.save(category2);
27 
28         session.save(item1);
29         session.save(item2);
30     }

控制台打印sql

 1 Hibernate: 
 2     
 3     create table PRODUCT_CATEGORY (
 4        ID integer not null auto_increment,
 5         NAME varchar(255),
 6         DETAIL varchar(255),
 7         primary key (ID)
 8     ) engine=InnoDB
 9 Hibernate: 
10     
11     create table PRODUCT_CATEGORY_ITEM (
12        CATEGORY_ID integer not null,
13         ITEM_ID integer not null,
14         primary key (CATEGORY_ID, ITEM_ID)
15     ) engine=InnoDB
16 Hibernate: 
17     
18     create table PRODUCT_ITEM (
19        ID integer not null auto_increment,
20         TITLE varchar(255),
21         PRICE double precision,
22         primary key (ID)
23     ) engine=InnoDB
24 Hibernate: 
25     
26     alter table PRODUCT_CATEGORY_ITEM 
27        add constraint FKgqq9f2yg5b52m390yk15c8u28 
28        foreign key (ITEM_ID) 
29        references PRODUCT_ITEM (ID)
30 Hibernate: 
31     
32     alter table PRODUCT_CATEGORY_ITEM 
33        add constraint FKtajc52s55t4fk8864s63hsuv2 
34        foreign key (CATEGORY_ID) 
35        references PRODUCT_CATEGORY (ID)
View Code

查询数据库结果信息:

添加测试函数2:

1     @Test
2     public void testSelect() {
3         ProductCategory category = (ProductCategory) session.get(ProductCategory.class, 1);
4         System.out.println(category.getName());
5 
6         System.out.println(category.getProductItems().size());
7     }

后台执行sql及结果:

 1 Hibernate: 
 2     select
 3         productcat0_.ID as ID1_0_0_,
 4         productcat0_.NAME as NAME2_0_0_,
 5         productcat0_.DETAIL as DETAIL3_0_0_ 
 6     from
 7         PRODUCT_CATEGORY productcat0_ 
 8     where
 9         productcat0_.ID=?
10 category1
11 Hibernate: 
12     select
13         productite0_.CATEGORY_ID as CATEGORY1_1_0_,
14         productite0_.ITEM_ID as ITEM_ID2_1_0_,
15         productite1_.ID as ID1_2_1_,
16         productite1_.TITLE as TITLE2_2_1_,
17         productite1_.PRICE as PRICE3_2_1_ 
18     from
19         PRODUCT_CATEGORY_ITEM productite0_ 
20     inner join
21         PRODUCT_ITEM productite1_ 
22             on productite0_.ITEM_ID=productite1_.ID 
23     where
24         productite0_.CATEGORY_ID=?
25 2
  • 双向多对多:

 实现双向多对多,需要再ProductItem的另一端也定义Set属性:Set<ProductCategory> productCategories。还需要在ProductItem.hbm.xml中添加set节点,节点属性配置与ProductCategory.hbm.xml中set节点配置对调。

修改ProductItem.java(在类中添加属性:Set<ProductCategory> productCategories):