1、回顾
1.1 Hibernate的持久化类的编写规则
- 无参构造
- 属性私有
- 属性尽量使用包装类
- 提供一个唯一的OID与其对应
- 不要使用final修饰
1.2 Hibernate的主键生成策略
- 主要分类
- 自然主键
- 代理主键
- 主键生成策略
- increment
- identity
- sequence
- UUID
- native
- assigned
- foreign
1.3 Hibernate的持久化类的三种装态
- 三种状态
- 瞬时态:没有唯一标识OID,也没有被Session管理
- 持久态:有唯一标识OID,且被Session管理
- 脱管态:有唯一的标识OID,但没有被Session管理
- 状态转换
1.4 Hibernate的一级缓存
- 一级缓存:Hibernate优化手段,成为Session级别的缓存,是自带的,不可卸载的
- 一级缓存:快照区
1.5 Hibernate的事务管理
- 事务的回顾
- 事务的概念:
- 事务的特性:
- 引发安全性问题:
- 安全性问题解决:
- HIbernate解决读问题
- 配置设置隔离级别
- Hibernate解决Service事务
- 采用的是线程绑定的方式:getCurrentSession()
1.6 Hibernate的其他API
- Query: ;HQL面向对象的方式查询
- Criteria: ;QBC完成面向对象化
- SQLQuery: ;SQL查询
2、Hibernate一对多关联映射
2.1 一对多关系
- 什么样关系属于一对多?
- 一个部门对对于多个员工,一个员工只能属于某一个部门。
- 一个客户对应多个联系人,一个联系人只能属于某一个客户。
- 一对多的建表原则
- 在多的一方 创建外键,指向一的一方的主键
2.2 多对多关系
- 什么样的关系属于多对多?
- 一个学生可以选择对门课程,一门课程也可以被多个学生选择。
- 一个订单下可以有不同的商品,一个商品也可以在不同的订单里面。
- 一个用户可以选择多个角色,一个角色也可以被多个用户选择。
- 多对多的建表原则
- 创建一个中间表,中间表至少有两个字段,分别作为外键指向多对多双方的主键。
2.3 一对一关系(了解)
- 什么样的额关系属于一对第一?
- 一个公司只能有一个注册地址,一个注册地址也只能被一个公司注册。
- 一对一的建表原则
- 方式一:唯一外键对应
- 方式二:主键对应
2.4 Hibernate一对多的配置关系
-
创建数据库和表
CREATE TABLE `cst_customer` ( `cust_id` BIGINT(32) NOT NULL AUTO_INCREMENT COMMENT '客户编号(主键)', `cust_name` VARCHAR(32) NOT NULL COMMENT '客户名称(公司名称)', `cust_source` VARCHAR(32) DEFAULT NULL COMMENT '客户信息来源', `cust_industry` VARCHAR(32) DEFAULT NULL COMMENT '客户所属行业', `cust_level` VARCHAR(32) DEFAULT NULL COMMENT '客户级别', `cust_phone` VARCHAR(64) DEFAULT NULL COMMENT '固定电话', `cust_mobile` VARCHAR(16) DEFAULT NULL COMMENT '移动电话', PRIMARY KEY (`cust_id`) ) ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; --------------------------------------------------------------------- CREATE TABLE `cst_linkman` ( `lkm_id` BIGINT(32) NOT NULL AUTO_INCREMENT COMMENT '联系人编号(主键)', `lkm_name` VARCHAR(16) DEFAULT NULL COMMENT '联系人姓名', `lkm_cust_id` BIGINT(32) NOT NULL COMMENT '客户id', `lkm_gender` CHAR(1) DEFAULT NULL COMMENT '联系人性别', `lkm_phone` VARCHAR(16) DEFAULT NULL COMMENT '联系人办公电话', `lkm_mobile` VARCHAR(16) DEFAULT NULL COMMENT '联系人手机', `lkm_email` VARCHAR(64) DEFAULT NULL COMMENT '联系人邮箱', `lkm_qq` VARCHAR(16) DEFAULT NULL COMMENT '联系人qq', `lkm_position` VARCHAR(16) DEFAULT NULL COMMENT '联系人职位', `lkm_memo` VARCHAR(512) DEFAULT NULL COMMENT '联系人备注', PRIMARY KEY (`lkm_id`), KEY `FK_cst_linkman_lkm_cust_id` (`lkm_cust_id`), CONSTRAINT `FK_cst_linkman_lkm_cust_id` FOREIGN KEY (`lkm_cust_id`) REFERENCES `cst_customer` (`cust_id`) ON DELETE NO ACTION ON UPDATE NO ACTION ) ENGINE=INNODB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
-
创建实体
public class LinkMan { private Long lkm_id; private String lkm_name; private String lkm_gender; private String lkm_phone; private String lkm_mobile; private String lkm_email; private String lkm_qq; private String lkm_position; private String lkm_memo; //通过ORM方式表示:一个联系人只能属于一个客户 //放置的是一的一方的对象。 private Customer customer; ----------------------------------------------------- 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; //通过ORM方式表示:一个客户对应多个联系人 //放置多的一方的集合:Hibernate默认用的是Set集合 private Set<LinkMan> linkMans = new HashSet<LinkMan>();
-
创建映射
-
linkMan.hbm.xml
<?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.hibernate.demo01.LinkMan" table="cst_linkman"> <id name="lkm_id" column="lkm_id"> <generator class="native"></generator> </id> <property name="lkm_name" column="lkm_name"></property> <property name="lkm_gender" column="lkm_gender"></property> <property name="lkm_phone" column="lkm_phone"></property> <property name="lkm_mobile" column="lkm_mobile"></property> <property name="lkm_email" column="lkm_email"></property> <property name="lkm_qq" column="lkm_qq"></property> <property name="lkm_position" column="lkm_position"></property> <property name="lkm_memo" column="lkm_memo"></property> <!-- 配置多对一的关系 :放置的是一 的一方的对象--> <!-- many-to-one 标签: * name :一的一方的对象的属性名 * class :一的一方的类的全路径 * column :在多的一方的外键的名称 --> <many-to-one name="customer" class="com.hibernate.demo01.Customer" column="lkm_cust_id"></many-to-one> </class> </hibernate-mapping>
-
Customer.hb,.xml
<?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.hibernate.day02.Customer" table="cst_customer"> <!-- 建立类中的属性与表中的主键对应 --> <id name="cust_id" column="cust_id"> <!-- 主键生成策略 --> <generator class="native"></generator> </id> <!-- 建立类中的普通的属性和表的字段的对应 --> <property name="cust_name" column="cust_name"></property> <property name="cust_source" column="cust_source"></property> <property name="cust_industry" column="cust_industry"></property> <property name="cust_level" column="cust_level"></property> <property name="cust_phone" column="cust_phone"></property> <property name="cust_mobile" column="cust_mobile"></property> <!--配置一对多的映射:放置的是多的一方的对象的集合 --> <!-- set标签: * name :多的一方的对象集合的属性名称 --> <set name="linkMans"> <!-- key标签: * column:多的一方的外键的名称 --> <key column="lkm_cust_id"></key> <!-- one=to-many:标签 * class: 多的一方的类的全路径 --> <one-to-many class="com.hibernate.domain.LinkMan"/> </set> </class> </hibernate-mapping>
-
-
创建核心配置文件
<!-- 引入映射--> <mapping resource="com/hibernate/domain/Customer.hbm.xml"/> <mapping resource="com/hibernate/domain/LinkMan.hbm.xml"/>
-
一对多的关系只保存一边是否可以?(不可以)
public void Test02() { Session session = HibernateUtils.openSession(); Transaction transaction = session.beginTransaction(); Customer customer = new Customer(); customer.setCust_name("Jackson"); LinkMan linkMan = new LinkMan(); linkMan.setLkm_name("Tony"); customer.getLinkMans().add(linkMan); //只保存一边是否可以:不可以,报一个瞬时对象异常。持久态对象关联了一个瞬时态对象 //session.save(customer); session.save(linkMan); transaction.commit(); }
2.5 一对多的级联操作
- 什么叫做级联:
- 级联指的是,操作某一个对象的时候,是否会同时操作其关联的对象。
- 级联是有方向性:
- 操作一的一方的时候,是否操作的多的一方。
- 操作多的一方的时候,是否会操作到一的一方。
-
级联保存或更新:
- 保存客户,级联联系人。
-
保存联系人,级联客户。
/** * 级联保存或更新 * * 保存客户级联联系人:操作的主体是客户对象,需要在Customer.hbm.xml中进行配置 * * <set name="linkMans" cascade="save-update"> * * 添加cascade属性 * * * 保存联系人级联客户:操作的主体是联系人,需要在LinkMan.hbm.xml中进行配置 * * <many-to-one name="customer" cascade="save-update" class="com.hibernate.domain.Customer" column="lkm_cust_id" /> * * 添加cascade属性 */ public void test03() { Session session = HibernateUtils.openSession(); Transaction transaction = session.beginTransaction(); Customer customer = new Customer(); customer.setCust_name("陈平"); LinkMan linkMan = new LinkMan(); linkMan.setLkm_name("江婉"); customer.getLinkMans().add(linkMan); linkMan.setCustomer(customer); //session.save(customer); session.save(linkMan); transaction.commit(); }
-
级联删除:
-
删除一边的时候,同时将另一方的数据也一并删除。
@Test /** * 级联删除 * * 删除客户,级联删除联系人 * <set name="linkMans" cascade="save-update,delete"> * 属性cascade中添加了delete */ public void demo04() { Session session = HibernateUtils.openSession(); Transaction transaction = session.beginTransaction(); //没有设置级联删除,默认情况下,先将外键设置为null Customer customer = session.get(Customer.class, 1l); session.delete(customer); transaction.commit(); }
-
- 一对多设置了双向关联产生多余的SQL语句
- 解决多余的SQL语句
- 单向维护
- 使一方放弃外键维护权
- 一的一方放弃。在set上配置inverse为true。
- 一对多的关联查询的修改的时候。
- 解决多余的SQL语句
-
3 Hibernate的多对多关联映射
3.1 HIbernate多对多关系的配置
3.1.1 创建表
-
用户表
CREATE TABLE `sys_user` ( `user_id` BIGINT(32) NOT NULL AUTO_INCREMENT COMMENT '用户id', `user_code` VARCHAR(32) NOT NULL COMMENT '用户账号', `user_name` VARCHAR(64) NOT NULL COMMENT '用户名称', `user_password` VARCHAR(32) NOT NULL COMMENT '用户密码', `user_state` CHAR(1) NOT NULL COMMENT '1:正常,0:暂停', PRIMARY KEY (`user_id`) ) ENGINE=INNODB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8;
-
角色表
CREATE TABLE `sys_role` ( `role_id` bigint(32) NOT NULL AUTO_INCREMENT, `role_name` varchar(32) NOT NULL COMMENT '角色名称', `role_memo` varchar(128) DEFAULT NULL COMMENT '备注', PRIMARY KEY (`role_id`) ) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;
-
中间表
CREATE TABLE `sys_user_role` ( `role_id` bigint(32) NOT NULL COMMENT '角色id', `user_id` bigint(32) NOT NULL COMMENT '用户id', PRIMARY KEY (`role_id`,`user_id`), KEY `FK_user_role_user_id` (`user_id`), CONSTRAINT `FK_user_role_role_id` FOREIGN KEY (`role_id`) REFERENCES `sys_role` (`role_id`) ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT `FK_user_role_user_id` FOREIGN KEY (`user_id`) REFERENCES `sys_user` (`user_id`) ON DELETE NO ACTION ON UPDATE NO ACTION ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
3.1.2 创建实体类
-
创建用户实体类User,生成set,get方法
public class User { private Long user_id; private String user_code; private String user_name; private String user_password; private String user_state; //设置多对多关系:表示一个用户选择多个角色 private Set<Role> roles = new HashSet<Role>();
-
创建角色实体类Role,生成set,get方法
public class Role { private Long role_id; private String role_name; private String role_memo; //一个角色被多个用户选择 //放置的是用户的集合 private Set<User> users = new HashSet<>();
3.1.4 创建映射
-
user.hbm.xml
<?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.hibernate.domain.User" table="sys_user"> <id name="user_id" column="user_id"> <generator class="native"></generator> </id> <property name="user_code" column="user_code"></property> <property name="user_name" column="user_name"></property> <property name="user_password" column="user_password"></property> <property name="user_state" column="user_state"></property> <!-- 建立与角色的多对多的映射关系 --> <!-- * set 集合: * name :对方的集合的属性名称 * table :多对多关系需要使用中间表,放的是中间表单的名称 --> <set name="roles" table="sys_user_role"> <!-- column : 当前对象对应的中间表的外键的名称--> <key column="user_id"></key> <!-- class :对方类的全路径 colummn :对方的对象在中间表的外键的名称 --> <many-to-many class="com.hibernate.domain.Role" column="role_id"/> </set> </class> </hibernate-mapping>
-
Role.hbm.xml
<?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.hibernate.domain.Role" table="sys_role"> <id name="role_id" column="role_id"> <generator class="native"></generator> </id> <property name="role_name" column="role_name"></property> <property name="role_memo" column="role_name"></property> <set name="users" table="sys_user_role"> <key column="role_id"></key> <many-to-many class="com.hibernate.domain.User" column="user_id"/> </set> </class> </hibernate-mapping>
3.1.5创建测试类
@Test
/**
* 保存多条记录:保存多个用户和角色
*/
public void demo02() {
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction();
//创建两个用户
User user1 = new User();
user1.setUser_name("赵子龙");
User user2 = new User();
user2.setUser_name("周瑜");
//创建三个角色
Role role1 = new Role();
role1.setRole_name("研发部");
Role role2= new Role();
role2.setRole_name("市场部");
Role role3 = new Role();
role3.setRole_name("公关部");
//设置双向的关联关系
user1.getRoles().add(role1);
user1.getRoles().add(role2);
user2.getRoles().add(role2);
user2.getRoles().add(role3);
role1.getUsers().add(user1);
role2.getUsers().add(user1);
role2.getUsers().add(user2);
role3.getUsers().add(user2);
//保存操作:多对多建立了双向关系,必须有一方放弃外键保护。
//一般被动方放弃外键维护权
session.save(user1);
session.save(user2);
session.save(role1);
session.save(role2);
session.save(role3);
transaction.commit();
}
3.2 Hibernate多对多的操作
- 只保存一边是否可以?
- 不可以,会报瞬时对象异常
- 多对多的级联保存或更新
- 在用户的映射文件中配置
- 多对多的级联删除