这一章主要是对Hibernate多对多的实例进行讲解。其实多对多我们可以很好理解。就是我们平常的数据库表中的关系。无法直接用外键描述两个对象之间的关系是,我们引入第三章表来进行描述多对多的现象。例如(课程,学生,学生选课)这些关系就是典型的例子。
下面直接简单粗暴一点:
上代码:
数据库表信息:
-- 商品分类 create table tbl_category( category_id char(32) primary key, -- 分类ID category_name varchar(30) not null -- 分类名称 ); -- 商品表 create table tbl_goods( goods_id int primary key, -- 商品主键编号 goods_name varchar(30) not null, -- 商品 名称 goods_price number default 0.0 -- 商品 价格 ) -- 分裂货物表 create table tbl_category_goods( category_id char(32) not null, goods_id int null, constraint PK_CTG_GOODS primary key(category_id,goods_id), constraint FK_CTG_GOODS foreign key(goods_id) references tbl_goods(goods_id), constraint FK_CTG_CATEGORYS foreign key(category_id) references tbl_category(category_id) )
分类信息:Category.java
/** * @Title: Category.java * @package: edu.fjnu.domain * @author: Zhou kailun * @date: 2018年5月30日 下午4:01:54 * @version: V1.0 */ package edu.fjnu.domain; import java.util.HashSet; import java.util.Set; /** * ClassName: Category * Description: TODO * Author: Zhou kailun * */ public class Category { /**分类编号*/ private String categoryId; /**分类名称*/ private String categoryName; private Set<Goods> goods=new HashSet<Goods>(); /** * <p>Title: </p> * <p>Description: </p> */ public Category() { // TODO Auto-generated constructor stub } public String getCategoryId() { return categoryId; } public void setCategoryId(String categoryId) { this.categoryId = categoryId; } public String getCategoryName() { return categoryName; } public void setCategoryName(String categoryName) { this.categoryName = categoryName; } public Set<Goods> getGoods() { return goods; } public void setGoods(Set<Goods> goods) { this.goods = goods; } }
货物信息:Goods.java
/** * @Title: Goods.java * @package: edu.fjnu.domain * @author: Zhou kailun * @date: 2018年5月30日 下午4:02:21 * @version: V1.0 */ package edu.fjnu.domain; import java.util.HashSet; import java.util.Set; /** * ClassName: Goods * Description: TODO * Author: Zhou kailun * */ public class Goods { /**货物编号*/ private Integer goodsId; /**货物名称*/ private String goodsName; /**货物价格*/ private double goodsPrice; /**货物分类*/ private Set<Category> category=new HashSet<Category>(); /** * <p>Title: </p> * <p>Description: </p> */ public Goods() { // TODO Auto-generated constructor stub } public Integer getGoodsId() { return goodsId; } public void setGoodsId(Integer goodsId) { this.goodsId = goodsId; } public String getGoodsName() { return goodsName; } public void setGoodsName(String goodsName) { this.goodsName = goodsName; } public double getGoodsPrice() { return goodsPrice; } public void setGoodsPrice(double goodsPrice) { this.goodsPrice = goodsPrice; } public Set<Category> getCategory() { return category; } public void setCategory(Set<Category> category) { this.category = category; } }
分类信息配置文件:Category.hbm.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" > <hibernate-mapping package="edu.fjnu.domain"> <!-- 货物分类信息与数据库匹配 --> <class name="Category" table="tbl_category"> <id name="categoryId" column="category_id" type="java.lang.String" length="32"> <!-- uuid:全球资源唯一标志符(时间,mac....,理论上是不会重复的,128为二进制数,32为字符); uuid.hex的主键是依靠hibernate来完成的,不依靠任何的数据库,不如sequence生成,只有oracle,db2支持。 --> <generator class="uuid.hex"></generator> </id> <property name="categoryName" column="category_name" type="java.lang.String" length="30" not-null="true"></property> <!-- 1 提供各种条件让hibernate 找到goods(必须 a.table="tbl_category_goods" select * from tbl_category_goods; b.<key column="category_id"/> select * from tbl_category_goods where category_id=? c.当前的category的id select * from tbl_category_id where [email protected]; d.<many-to-many class="Goods" column="goods_id"></many-to-many> select goods_id from tbl_category_goods where [email protected]; e.class="Goods" select * from tbl_goods where goods_id=@goods_id 2 根据业务需求,提供各种调优参数(可选 a. cascade=true 级联保存 b. fetch="true" 联合查询,缩减SQL语句 c. lazy="false" 缩减SQL数据库。 --> <set name="goods" table="tbl_category_goods" cascade="all" fetch="join" lazy="false"> <key column="category_id" ></key> <many-to-many class="Goods" column="goods_id"></many-to-many> </set> </class> </hibernate-mapping>
货物信息配置文件:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" > <hibernate-mapping package="edu.fjnu.domain"> <!-- 公交卡信息与数据库匹配 --> <class name="Goods" table="tbl_goods"> <id name="goodsId" column="goods_id" type="java.lang.Integer"> <generator class="assigned"> </generator> </id> <property name="goodsName" column="goods_name" type="java.lang.String" length="30" not-null="true"></property> <property name="goodsPrice" column="goods_price" type="double" not-null="true"></property> <!-- 注意:这里的constraint="true",表明了当前的BusCard必须和一个Citizen对象关联,这个关系是强制的。 当使用one-to-one获得对象的时候,如果能够加constrained=true的,尽量加,因为很多情况下,一个实体通过one-to-one关联的实体 可能存在,也可能不存在,这时候,在查询实体的时候,hibernate总是发起一次查询检查《one-to-one》所关联的实体是否存在,而如果把 constrained设置weitrue,这个不走则可以省略,直接加载对象 --> <set name="category" table="tbl_category_goods" cascade="all"> <key column="goods_id"></key> <many-to-many class="Category" column="category_id" ></many-to-many> </set> </class> </hibernate-mapping>
测试代码:CategoryTest.java
/** * @Title: CategoryTest.java * @package: edu.fjnu.test * @author: Zhou kailun * @date: 2018年5月30日 下午4:39:01 * @version: V1.0 */ package edu.fjnu.test; import org.hibernate.HibernateException; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; import org.junit.After; import org.junit.Before; import org.junit.Test; import edu.fjnu.domain.Category; import edu.fjnu.domain.Goods; /** * ClassName: CategoryTest * Description: TODO * Author: Zhou kailun * */ public class CategoryTest { /**Hibernate的sessionFactroy*/ private SessionFactory factory; /**Hibernate的Session对象*/ private Session session; /** * Title:setUp <br> * Description:TODO <br> * @param @throws java.lang.Exception : * @return void * @throws */ @Before public void setUp() throws Exception { Configuration config=new Configuration();//构建一个配置器 config.configure("edu/fjnu/config/hibernate.cfg.xml"); factory=config.buildSessionFactory(); session=factory.openSession(); } /** * Title:tearDown <br> * Description:TODO <br> * @param @throws java.lang.Exception : * @return void * @throws */ @After public void tearDown() throws Exception { if(session.isOpen()){ session.close(); } if(!factory.isClosed()){ factory.close(); } } @Test public void testAddCategory() { Category c1=new Category(); c1.setCategoryName("化妆品"); // c1.setCategoryId("uuuuuuuuuuuuuuuuuuuu"); Category c2=new Category(); c2.setCategoryName("学习用品"); Goods g1=new Goods(); g1.setGoodsId(109); g1.setGoodsName("文具盒"); g1.setGoodsPrice(20.5); Goods g2=new Goods(); g2.setGoodsId(110); g2.setGoodsName("橡皮檫"); g2.setGoodsPrice(5.5); Goods g3=new Goods(); g3.setGoodsId(111); g3.setGoodsName("铅笔"); g3.setGoodsPrice(2); // g1.getCategory().add(c1); // g1.getCategory().add(c2); c1.getGoods().add(g1); c1.getGoods().add(g2); c1.getGoods().add(g3); // c2.getGoods().add(g3); Transaction trans=null; try{ trans=session.beginTransaction(); session.save(c1); session.save(c2); // session.saveOrUpdate(g1); trans.commit(); }catch(HibernateException e){ e.printStackTrace(); trans.rollback(); } } @Test public void testCheckCategory(){ Transaction trans=null; try{ trans=session.beginTransaction(); Category category=session.get(Category.class,"8aa2d51563b047ac0163b047ae0d0000"); System.out.println(category.getCategoryName()+",total goods:"+category.getGoods().size()); trans.commit(); }catch(HibernateException e){ e.printStackTrace(); trans.rollback(); } } }
注意:在我们的测试中,有时候关于uuid.hex这个使用要小心,容易导致我们出现主键唯一约束异常,从而无法存入数据库。
所以基本需要控制好主键唯一约束异常。