需求:有两个表,分别是客户表和联系人表,一个客户有多个联系人,一个联系人只有一个客户
两个POJO类
public class Customer {
private Long cust_id;
private String cust_name;
private String cust_source;
private String cust_industry;
private String cust_level;
private String cust_phone;
private String cust_mobile;
//一个客户有多个联系人
private Set<Linkman> linkmen = new HashSet<>();
}
public class Linkman {
private Long link_id;
private String link_name;
private String link_gender;
private String link_phone;
private String link_mobile;
private String link_email;
private String link_qq;
private String link_position;
private String link_memo;
private Long link_cust_id;
//一个联系人对应一个客户
private Customer customer;
}
数据库两张表的DDL
客户表:
CREATE TABLE `customer` (
`cust_id` bigint(20) NOT NULL AUTO_INCREMENT,
`cust_name` varchar(255) DEFAULT NULL,
`cust_source` varchar(255) DEFAULT NULL,
`cust_industry` varchar(255) DEFAULT NULL,
`cust_level` varchar(255) DEFAULT NULL,
`cust_phone` varchar(255) DEFAULT NULL,
`cust_mobile` varchar(255) DEFAULT NULL,
PRIMARY KEY (`cust_id`)
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8;
联系人表:
CREATE TABLE `linkman` (
`link_id` bigint(20) NOT NULL AUTO_INCREMENT,
`link_name` varchar(255) DEFAULT NULL,
`link_gender` varchar(255) DEFAULT NULL,
`link_phone` varchar(255) DEFAULT NULL,
`link_mobile` varchar(255) DEFAULT NULL,
`link_email` varchar(255) DEFAULT NULL,
`link_qq` varchar(255) DEFAULT NULL,
`link_position` varchar(255) DEFAULT NULL,
`link_memo` varchar(255) DEFAULT NULL,
`link_cust_id` bigint(20) DEFAULT NULL,
PRIMARY KEY (`link_id`),
KEY `link_cust_id` (`link_cust_id`),
CONSTRAINT `linkman_ibfk_1` FOREIGN KEY (`link_cust_id`) REFERENCES `customer` (`cust_id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
配置文件:
客户表的配置文件 对客户来说是一对多 因此要配置一对多
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.bullet.domain.Customer" table="customer">
<!--建立类中的属性与表中的主键对应-->
<id name="cust_id" column="cust_id" >
<generator class="native"/>
</id>
<!--建立类中的普通的属性和表的字段的对应-->
<property name="cust_name" column="cust_name" />
<property name="cust_source" column="cust_source"/>
<property name="cust_industry" column="cust_industry"/>
<property name="cust_level" column="cust_level"/>
<property name="cust_phone" column="cust_phone"/>
<property name="cust_mobile" column="cust_mobile"/>
<!-- 一对多的配置 -->
<!--set集合属性名称-->
<set name="linkmen" cascade="save-update,delete" inverse="true">
<key column="link_cust_id"></key><!--外键-->
<!--set集合泛型的全路径-->
<one-to-many class="com.bullet.domain.Linkman"></one-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://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.bullet.domain.Linkman" table="linkman">
<!--建立类中的属性与表中的主键对应-->
<id name="link_id" column="link_id" >
<generator class="native"/>
</id>
<!--建立类中的普通的属性和表的字段的对应-->
<property name="link_name" column="link_name" />
<property name="link_gender" column="link_gender"/>
<property name="link_phone" column="link_phone"/>
<property name="link_mobile" column="link_mobile"/>
<property name="link_email" column="link_email"/>
<property name="link_qq" column="link_qq"/>
<property name="link_position" column="link_position"/>
<property name="link_memo" column="link_memo"/>
<!-- 配置多对一关系 -->
<!--存储关联对象的名称--> <!--存储关联对象的全路径-->
<many-to-one name="customer" class="com.bullet.domain.Customer">
<!--外键-->
<column name="link_cust_id"/>
</many-to-one>
</class>
</hibernate-mapping>
添加操作
在一对多的添加操作中
可以对双方的关系进行双向配置 也可以进行单向配置 但一般都采取双向配置
如果要使用双向配置,为了提高性能,就要让其中一方放弃维护权,一般是外键在哪张表里,就让谁来维护,也就是说要让另外一张表放弃外键维护权 。
例如上面两张波,外键在linkman表中,因此让customer放弃外键维护权
<!-- 一对多的配置 -->
<set name="linkmen" cascade="save-update,delete" inverse="true"> <!--set集合属性名称-->
<key column="link_cust_id"></key><!--外键-->
<one-to-many class="com.bullet.domain.Linkman"></one-to-many><!--set集合存储的类型-->
</set>
在保存操作时,保存时必须保存两边,如:
//保存 必须保存两边
// 如果只保存一遍,会发生瞬时对象异常
//原因:持久态对象关联了一个瞬态对象
//如果想只保存一边 得在配置文件中配置 cascade="save-update"
currentSession.save(customer1);
currentSession.save(customer2);
currentSession.save(customer3);
currentSession.save(linkman1);
currentSession.save(linkman2);
currentSession.save(linkman3);
如果只保存一边,会跑出瞬时对象异常。
如果要保存一边,就要配置,保存谁就在谁的配置文件中配置级联保存
<!-- 一对多的配置 -->
<set name="linkmen" cascade="save-update,delete" inverse="true"> <!--set集合属性名称-->
<key column="link_cust_id"></key><!--外键-->
<one-to-many class="com.bullet.domain.Linkman"></one-to-many><!--set集合存储的类型-->
</set>
cascade=“save-update” 表示级联保存
查询操作
查询操作时,hibernate内置懒加载,如果没使用到关联对象的属性,是不会发送SQL语句,只有用到时才会发送。
删除操作
默认的删除操作是不会级联删除的,默认的删除操作时打破两者之间的联系,然后删除。注意:默认的删除是不会删除级联对象,只会删除操作对象
要想实现级联删除,同样删除谁在谁的配置文件中进行配置
cascade=“delete”
更新操作
分别查出两个对象,然后设置外键即可。
设置双向维护 一方放弃维护权
进行级联保存,保存谁在谁的配置文件中配置。
代码:
public class HibernateTest {
/**
* 添加操作
*/
@Test
public void test1(){
Session currentSession = HibernateUtil.getCurrentSession();
Transaction transaction = currentSession.beginTransaction();
Customer customer1 = new Customer();
customer1.setCust_name("客户1");
Customer customer2 = new Customer();
customer2.setCust_name("客户2");
Customer customer3 = new Customer();
customer3.setCust_name("客户3");
Linkman linkman1 = new Linkman();
linkman1.setLink_name("联系人1");
Linkman linkman2 = new Linkman();
linkman2.setLink_name("联系人2");
Linkman linkman3 = new Linkman();
linkman3.setLink_name("联系人3");
/**
* 配置关系 单向维护 双向维护
* 一般都采用双向维护
* 双向维护时,一般让一方放弃维护权
* 一般是外键在谁里面,就让谁维护 inverse="true" true代表放弃外键维护权
*/
customer1.getLinkmen().add(linkman1);
customer1.getLinkmen().add(linkman2);
customer2.getLinkmen().add(linkman3);
//反过来再配置
linkman1.setCustomer(customer1);
linkman2.setCustomer(customer1);
linkman3.setCustomer(customer2);
//保存 必须保存两边
// 如果只保存一遍,会发生瞬时对象异常
//原因:持久态对象关联了一个瞬态对象
//如果想只保存一边 得在配置文件中配置 cascade="save-update"
currentSession.save(customer1);
currentSession.save(customer2);
currentSession.save(customer3);
currentSession.save(linkman1);
currentSession.save(linkman2);
currentSession.save(linkman3);
transaction.commit();
currentSession.close();
}
/**
* 查询操作
*/
@Test
public void test2(){
Session currentSession = HibernateUtil.getCurrentSession();
Transaction transaction = currentSession.beginTransaction();
Linkman linkman = currentSession.get(Linkman.class, 1L);
transaction.commit();
System.out.println(linkman);
currentSession.close();
}
/**
* 删除操作
*/
@Test
public void test3(){
Session currentSession = HibernateUtil.getCurrentSession();
Transaction transaction = currentSession.beginTransaction();
//默认删除
//先打断两表之间的联系,再删除customer 但相关联的linkman并没有被删除
//并没有级联的删除
//进行配置,删除谁对谁配置
Customer customer = currentSession.get(Customer.class, 8L);
currentSession.delete(customer);
transaction.commit();
currentSession.close();
}
/**
* 更新操作
*/
@Test
public void test4(){
Session currentSession = HibernateUtil.getCurrentSession();
Transaction transaction = currentSession.beginTransaction();
//更新
Linkman linkman1 = currentSession.get(Linkman.class, 1L);
Customer customer3 = currentSession.get(Customer.class, 9L);
//关联
linkman1.setCustomer(customer3);
transaction.commit();
currentSession.close();
}
}