[Hibernate的连表操作]
多个实体(表)的关联关系,继承关系,如何用Hibernate实现级联操作?
关联关系: 继承关系:
级联操作: 级联的增、删、改; 连表查询;
在PO中要添加关联属性 ,在映射配置中要添加关联配置,表达关联关系。 表达关联关系。
优点:
①表间耦合度降低。表间可以尽量少建关联(及主外键关系+约束),使表易于修改、添加
②建立PO间关联。而需要时,可以随时建立PO间关联,实现级联操作、联表查询等功能。如此使用关联,灵活,易于修改。
③关联关系的配置化表达实现。解放了表间的耦合关系,将表间的关联关系等耦合,表达在O/RMapping的配置和PO中。
//也易于阅读。 Session的API:查、.save()、.delete()、.update()方法,会读取关联配置,自动实现级联操作,
不用你单写关联操作语句;
◆一对一映射
特点:Table间没有关联关系,Hibernate也能通过 两个.hbm.xml映射文件间配置,及两个PO互相添加关联属性,实现PO间关联。
步骤:
1)先建SQL,客户和地址是一对一的关系:
create table CUSTOMER ( create table ADDRESS( 关联的业务意义:
ID bigint not null auto_increment, ID bigint not null auto_increment,
NAME varchar(15), STREET varchar(128),
primary key (ID) CITY varchar(128),
); PROVINCE varchar(128),
ZIPCODE varchar(6),
primary key (ID)
);
2)建立项目,建包,打入Hibernate capabilities;
i) 先用工具,生成各个单表的配置;
ii) 在《表1.hbm.xml》与《表2.hbm.xml》中添加关联映射配置;
address的映射配置信息 customer的映射配置信息
◆<one-to-one name="address" ◆<one-to-one name="customer" //本PO类引用对方PO对象
━━━━━ ━━━━━
class="mypack.Customer" class="mypack.Address" //属性Type---对方PO类名
cascade="all" //可做所有级联操作 constrained="true" //彼此两个PO类间,还建立约束。
/> />
◆一边的<one-to-one>配置,只负责单向的关联操作。
iii)在各PO类中添加关联映射属性,PO中属性名及类型,必须与*.hbm.xml中的对应。
private Address address; private Customer customer; ◆添加的关联属性----引用目标方对象。
━━━━━━━━━━━━ ━━━━━━━━━━━━
3)DAO中实现关联映射操作
/**
* 保存Customer PO对象映射的记录时,级联插入关联的Address PO对象映射的记录;
* @param c---临时态PO;
*/
public void saveCustomer(Customer c){
Session session=null;
Transaction tr =null;
try {
session = HibernateSessionFactory.getSession();
//获得session的另外一种方式:new Configuration().configure().bulidSessionFactory().openSession();
tr= session.beginTransaction();
session.save(c); ▲此PO对象放入缓存,进入持久态;其关联属性存放的关联PO对象也被带入缓存进入持久态;将形成两句insert的请求;
tr.commit(); ▲因此本句session.flush()生成sql语句时,两个PO都生成insert()语句,级联插入;提交事务时,确认执行
} catch (Exception e) {
try {
tr.rollback();
} catch (HibernateException e1) {
e1.printStackTrace();
}
e.printStackTrace();
}finally{
try {
session.close();
} catch (HibernateException e) {
e.printStackTrace();
}
}
4)模拟BO中用main()方法来调用DAO 方法:
/**
*级联插入
*/
public static void main(String[] args){
CustomerAddressDAO dao = new CustomerAddressDAO();
Customer customer = new Customer();
customer.setName("夏沫");
Address address = new Address();
address.setCity("长春");
address.setProvince("吉林省");
address.setStreet("台湾街");
address.setZipcode("130003");
customer.setAddress(address); ▲customer的关联属性中放入关联address;由customer--->address单向关联;
dao.saveCustomer(customer); ▲插入Customer PO,会级联插入Address PO;
}
5)
/**
* 根据名字查询用户
* @param name
* @return
*/
public Customer findCustomerByName(String name){
Session session=null;
Transaction tr=null;
Customer c=null;
try {
session = HibernateSessionFactory.getSession();
tr = session.beginTransaction();
Query query = session.createQuery("from Customer u where u.name like '%"+name+"%'");
c = (Customer)query.list().get(0);//▲查取customer PO也将连表查取address PO;
tr.commit();
} catch (Exception e) {
try {
tr.rollback();
} catch (HibernateException e1) {
e1.printStackTrace();
}
}finally{
session.close();
}
return c;
}
6)
/**
*
* 根据id主键号查询用户,使用session.load()方法
*/
public Customer loadCustomer(long id){
Transaction tr =null;
Session session=null;
Customer c=null;
try {
session = HibernateSessionFactory.getSession();
tr = session.beginTransaction();
c = (Customer)session.load(Customer.class,id);
▲缺省的检索策略下,load()方法不能关闭session,否则,无法加载关联PO的代理对象;
tr.commit();
} catch (HibernateException e) {
try {
tr.rollback();
} catch (HibernateException e1) {
e1.printStackTrace();
}
e.printStackTrace();
}finally{
//session.close();
}
return c;
}
★通过主键ID值,查询;
方式I)通过session.load()方法,连表查询;
◆理论:使用session.load();不能session.close();因为load()方法默认使用<惰性加载(也叫延迟检索策略)>;
该方式为避免加载过多PO,先仅加载 主PO的代理对象和关联PO的代理对象,将来使用哪个代理对象时,再临时加载其字段属性值,如此节省内存;//1-*时就必需如此;
关闭session,将导致代理对象消失,之后无法提取关联PO值;强行提取抛异常:LazyInitalizationException;
优点:节省内存;
缺点:不能关闭session;
方式II)通过session.get()方法,连表查询;
◆理论:使用session.get();可以session.close();
因为get()方法默认使用<立即加载策略,该方式将立即得到关联PO属性值,关联PO已生成,关闭session也无影响.
优点:可以关闭session;
缺点:关联PO多时,浪费内存
7) /**
*级联删除
*/
Customer customer = dao.findCustomerByName("貂蝉");
Address address = customer.getAddress();
System.out.println("address:"+address.getId());
dao.deleteCustomer(customer);
DAO:
/**
* 删除Customer PO对象映射的记录时,级联删除关联的Address PO对象映射的记录;
*/
public void deleteCustomer(Customer customer){
Session session=null;
Transaction tr =null;
try {
session = HibernateSessionFactory.getSession();
tr= session.beginTransaction();
session.delete(customer);//会级联删除关联属性中的address PO记录;
tr.commit();
} catch (Exception e) {
try {
tr.rollback();
} catch (HibernateException e1) {
e1.printStackTrace();
}
e.printStackTrace();
}finally{
try {
session.close();
} catch (HibernateException e) {
e.printStackTrace();
}
}
}