理解Hibernate的inverse和cascade属性(实例)

1.理解cascade属性
创建CUSTOMERS和ORDERS数据库表
CREATE TABLE `hiber`.`customers` (
`ID` bigint(20) NOT NULL AUTO_INCREMENT,
`NAME` varchar(45) DEFAULT NULL,
PRIMARY KEY (`ID`)
) ENGINE=MyISAM;

CREATE TABLE `hiber`.`orders` (
`ID` bigint(20) NOT NULL AUTO_INCREMENT,
`ORDER_NO` varchar(45) DEFAULT NULL,
`CUSTOMER_ID` bigint(20) DEFAULT NULL,
PRIMARY KEY (`ID`)
) ENGINE=MyISAM;

创建持久化对象
Customer类:
package com;

import java.io.Serializable;

public class Customer implements Serializable {

private static final long serialVersionUID = 1L;

private long id;
private String name;
public long getId() {
return id;
}
private void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}

}

Customer类的配置文件(Customer.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>
<class name="com.Customer" table="CUSTOMERS">
<id name="id" column="ID" type="long">
<generator class="native"/>
</id>

<property name="name" column="NAME" type="string"/>
</class>
</hibernate-mapping>

Order类:
package com;

import java.io.Serializable;

public class Order implements Serializable {

private static final long serialVersionUID = 1L;

private long id;
private String orderNo;
private Customer customer;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getOrderNo() {
return orderNo;
}
public void setOrderNo(String orderNo) {
this.orderNo = orderNo;
}
public Customer getCustomer() {
return customer;
}
public void setCustomer(Customer customer) {
this.customer = customer;
}

}

Order类的配置文件(Order.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="com">
<class name="Order" table="ORDERS">
<id name="id" column="ID" type="long">
<generator class="identity"/>
</id>

<property name="orderNo" column="ORDER_NO" type="string" not-null="true"/>
<many-to-one name="customer" column="CUSTOMER_ID" class="com.Customer" />
</class>
</hibernate-mapping>

创建一个工具类
package tool;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

import com.Customer;
import com.Order;

public class HibernateUtil {

private static SessionFactory sessionFactory;

static {
Configuration config = new Configuration();
//适合Java属性配置连接数据库
config.addClass(Customer.class)
.addClass(Order.class);

//适合XML配置连接数据库
//config.configure();
sessionFactory = config.buildSessionFactory();
}

public static SessionFactory getSessionFactory() {
return sessionFactory;
}

public static Session getSession() {
return sessionFactory.openSession();
}

}

配置Hibernate的连接数据库(有2种方式)
1.Java属性(hibernate.properties文件)
hibernate.dialect=org.hibernate.dialect.MySQLDialect
hibernate.connection.driver_class=com.mysql.jdbc.Driver
hibernate.connection.url=jdbc:mysql://localhost:3306/hiber
hibernate.connection.username=root
hibernate.connection.password=123456
hibernate.show_sql=true

2.XML(hibernate.cfg.cml)
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">

<hibernate-configuration>
<session-factory>

<!-- Database connection settings(MySQL) -->
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="connection.url">jdbc:mysql://localhost:3306/hiber</property>
<property name="connection.username">root</property>
<property name="connection.password">123456</property>

<!-- SQL dialect -->
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>

<property name="show_sql">true</property>

<!-- 映射配置文件 -->
<mapping resource="com/Customer.hbm.xml"/>
<mapping resource="com/Order.hbm.xml"/>

</session-factory>
</hibernate-configuration>


创建测试类
package service;

import org.hibernate.Session;
import org.hibernate.Transaction;

import tool.HibernateUtil;

import com.Customer;
import com.Order;

public class BusinessService {

/**
* @param args
*/
public static void main(String[] args) {
Session session = HibernateUtil.getSession();
Transaction tx = null;
try {
tx = session.beginTransaction();
Customer customer = new Customer();
customer.setName("David");
Order o = new Order();
o.setOrderNo("no_003");
//建立单向关联
o.setCustomer(customer);
session.save(o); //因为在Order.hbm.xml中配置了cascade="save-update",所以会级联保存
System.out.println(customer.getId()); //在save()操作后,事物提交前,已经能获得ID
customer.setName("Phil"); //会执行一条Update语句
tx.commit();
customer.setName("Bruce"); //事物提交后,持久化类的修改不会被保存
} catch(Exception e) {
if (tx != null) {
tx.rollback();
}
e.printStackTrace();
} finally {
session.close();
}
}

}
运行会抛以下异常
org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient

instance before flushing: com.Customer
因为Order类对象参照的Customer不是持久化对象,而是临时对象。在保存Order对象之前,应该先保存Customer对象。可以使用级

联,修改配置文件(Order.hbm.xml)如下(加上cascade="save-update"):
<many-to-one name="customer" column="CUSTOMER_ID" class="com.Customer" cascade="save-update" />

再次运行
/**Output:
Hibernate: insert into CUSTOMERS (NAME) values (?)
Hibernate: insert into ORDERS (ORDER_NO, CUSTOMER_ID) values (?, ?)
7
Hibernate: update CUSTOMERS set NAME=? where ID=?
*/

以上输出,没有生成查询ID的语句(Hibernate: select max(ID) from CUSTOMERS)。因为我设置的标识符生成器是native和

identity的,这会由底层数据库负责生成ID,可以看到创建数据库表的时候设置了主键的auto_increment。如果数据库表没有设置

主键的auto_increment或者数据库不支持主键自动增涨,可以将标识符生成器设置为increment,这时持久化对象时会生成查询ID

的语句。

/*
查看数据库
select * from customers where id = 7;

ID NAME
7 Phil

select * from orders where customer_id = 7;

ID ORDER_ID CUSTOMER_ID
13 no_001 7
*/

总结:
cascade表示级联,可选值有:
<1>."none":(默认值)不级联
<2>."save-update":级联保存和更新
<3>."delete":级联删除
<4>."all":包括save-update和delete
<5>."delete-orphan":删除所有和本对象已经解除关系了的对象
<6>."all-delete-orphan":包括all和delete-orphan


2.理解inverse属性

将上面的单向关联改成双向关联
在Customer.java持久化类里填加Order
private Set orders = new HashSet();
public Set getOrders() {
return orders;
}
public void setOrders(Set orders) {
this.orders = orders;
}

在Customer.hbm.xml中填加orders属性的配置
<set name="orders" cascade="all" inverse="false">
<key column="CUSTOMER_ID"/>
<one-to-many class="com.Order"/>
</set>

修改测试类:
package service;

import org.hibernate.Session;
import org.hibernate.Transaction;

import tool.HibernateUtil;

import com.Customer;
import com.Order;

public class BusinessService {

/**
* @param args
*/
public static void main(String[] args) {
Session session = HibernateUtil.getSession();
Transaction tx = null;
try {
tx = session.beginTransaction();
Customer customer = new Customer();
customer.setName("David");
Order o = new Order();
o.setOrderNo("no_001");

session.save(customer);
session.save(o);

//建立双向关联
customer.getOrders().add(o);
o.setCustomer(customer);

tx.commit();
} catch(Exception e) {
if (tx != null) {
tx.rollback();
}
e.printStackTrace();
} finally {
session.close();
}
}

}
/**Output:
Hibernate: insert into CUSTOMERS (NAME) values (?)
Hibernate: insert into ORDERS (ORDER_NO, CUSTOMER_ID) values (?, ?)
Hibernate: update ORDERS set ORDER_NO=?, CUSTOMER_ID=? where ID=?
Hibernate: update ORDERS set CUSTOMER_ID=? where ID=?
*/
如果Customer.hbm.xml配置文件<set>设置inverse="true",就不会输出最后1条update语句,表示Customer持久化类不维护关联关

系;如果设置inverse="false"(默认值)或者不设置该属性,表示Customer持久化类维护关联关系,这样造成多执行一次update

操作;一般都把<set>加上inserve="true"属性,以免影响Java应用的性能。<many-to-one>没有inverse属性,它运行行为默认维

护关联关系(inverse="false")。

修改Customer.hbm.xml文件orders属性的配置(inverse="true")
<set name="orders" cascade="all" inverse="true">
<key column="CUSTOMER_ID"/>
<one-to-many class="com.Order"/>
</set>

再次运行
/**Output:
Hibernate: insert into CUSTOMERS (NAME) values (?)
Hibernate: insert into ORDERS (ORDER_NO, CUSTOMER_ID) values (?, ?)
Hibernate: update ORDERS set ORDER_NO=?, CUSTOMER_ID=? where ID=?
*/

总结:在双向关联关系中,一般设置一的一端为inverse="true",多的一端为inverse="false"。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值