百度百科上的级联的概念是:级联在关联映射中是个重要的概念,指当主动方对象执行操作时,被关联对象(被动方)是否同步执行同一操作。
简单的说,在数据库中,实体表之间的关系映射是采用外键来描述的,一对多关系的实现原理就是在多的一方,添加一的一方的主键作为外键。Hibernate中的关联映射就是将关联关系映射到数据库里,在对象模型中就是一个或多个引用。在Hibernate中采用Java对象关系来描述数据表之间的关系:
Java对象描述一对多数据表之间的关系:
class A{ Set <B>bs;//B的集合 } class B{ A a; }
一对多是关联关系映射中最为常见的关联关系,一对多映射关系是由”多“的一方指向”一“的一方。在表示”多“的一方数据表中增加一个外键,来指向”一“的一方的数据表,”一“的一方作为主表,而”多“的一方作为从表。
下面以客户和订单的关联关系为例来进行一对一关联关系映射的学习:
1.表示客户信息的实体类Customer.java
import java.util.HashSet; import java.util.Set; public class Customer { /** * @param args */ private Integer id; private String name; //用户有多个订单 private Set<Order>orders = new HashSet<Order>(); public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Set<Order> getOrders() { return orders; } public void setOrders(Set<Order> orders) { this.orders = orders; } }
其中定义的Set集合注释中也提到了,是表示一个客户有多个订单,使用Set集合是为了保证用户的订单不会重复。
2.表示订单信息的实体类Order.java
public class Order { /** * @param args */ private Integer id; private String address; //订单收货地址 private Double price; //订单总价 private Customer customer; //订单属于某一用户 public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } public Double getPrice() { return price; } public void setPrice(Double price) { this.price = price; } public Customer getCustomer() { return customer; } public void setCustomer(Customer customer) { this.customer = customer; } }
3.Order类的映射文件Order.hbm.xml
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <!-- Generated 2017-8-22 10:37:16 by Hibernate Tools 3.5.0.Final --> <hibernate-mapping> <class name="cn.itcast.onetomany.Customer" table="customer"> <id name="id" column="id" > <generator class="increment"></generator> </id> <!-- 配置普通属性 --> <property name="name" length="20"/> <!-- 一对多关系使用Set集合映射 : inverse属性表示是否放弃对关系的维护,true表示放弃对关系的维护 在一对多关系中最好放弃一方的,因为一方维护一次就要为多方产生数据相同的 sql update语句,影响性能。 false表示保持对关系的维护,是默认值 cascade属性表示级联操作: 属性值有: all-代表在所有的情况下都执行级联操作; none-在所有的情况下都不执行级联操作,是默认值; save-update-在保存和更新的时候执行级联操作 delete-在删除的时候执行级联操作 --> <set name="orders" inverse="true" cascade="delete"> <!-- 确定关联的外键列 --> <key column="cid"/> <!-- 映射到关联类属性 --> <one-to-many class="cn.itcast.onetomany.Order"/> </set> </class> </hibernate-mapping>
4.Customer类的映射文件Customer.hbm.xml
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <!-- Generated 2017-8-22 10:37:16 by Hibernate Tools 3.5.0.Final --> <hibernate-mapping> <class name="cn.itcast.onetomany.Customer" table="customer"> <id name="id" column="id" > <generator class="increment"></generator> </id> <!-- 配置普通属性 --> <property name="name" length="20"/> <!-- 一对多关系使用Set集合映射 --> <set name="orders"> <!-- 确定关联的外键列 --> <key column="cid"/> <!-- 映射到关联类属性 --> <one-to-many class="cn.itcast.onetomany.Order"/> </set> </class> </hibernate-mapping>
5.在xxx.cfg.xml配置文件中添加对映射文件的关联
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory> <property name="show_sql">true</property> <property name="hibernate.dialect">org.hibernate.dialect.Oracle9iDialect</property> <property name="hibernate.connection.driver_class">oracle.jdbc.driver.OracleDriver</property> <property name="hibernate.connection.username">system</property> <property name="hibernate.connection.password">123456</property> <property name="hibernate.connection.url">jdbc:oracle:thin:@localhost:1521:orcl</property> <property name="hibernate.hbm2ddl.auto" >create</property> <!--以下两行为 一对多映射文件的关联 --> <mapping resource="cn/itcast/onetomany/Customer.hbm.xml"/> <mapping resource="cn/itcast/onetomany/Order.hbm.xml"/> </session-factory> </hibernate-configuration>
5.测试类TestOneToMany
import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; import org.junit.Test; //import cn.itcast.utils.HibernateUtils; public class TestOneToMany { /** * @param args */ @Test public void test1() { Configuration conf = new Configuration().configure(); SessionFactory sf = conf.buildSessionFactory(); Session session = sf.openSession(); Transaction tx = session.beginTransaction(); //1.创建一个客户 Customer c = new Customer(); c.setName("张三"); //2.创建两个订单 Order o1 = new Order(); o1.setAddress("哈尔滨"); o1.setPrice(100000d); Order o2 = new Order(); o2.setAddress("上海"); o2.setPrice(5000d); //3.描述关系——订单属于某个客户 o1.setCustomer(c); o2.setCustomer(c); //4.描述关系——客户有多个订单 c.getOrders().add(o1); c.getOrders().add(o2); //5.先存客户再存订单 session.save(c); session.save(o1); session.save(o2); tx.commit(); session.close(); } }经过调试后测试结果如下:
需要注意的是,以上的关联方式属于双向关联(简单的说就是在Customer类中配置了one-to-many属性,同样在Order类中也配置了many-to-one属性),使用双向关联会执行两遍SQL语句,比较浪费资源,因此可以删除测试类中Cutomer对象c的两行get方法,再将Order.hbm.xml文件中的many-to-one标签及其所包含的内容一并删去,便可达成单向关联,避免了资源的浪费,运行测试结果如下图: