Hibernate是一款重量级的持久层框架,目前市面上的我很少见还有项目在开发时候使用他,之所以要学习这个,因为公司最近有一个系统升级的项目,之前的老系统用到了Hibernate。
同样还是老套路,学习一个新技术或者新知识,首先去他的官网看
【官网】:https://hibernate.org/orm/
【官方教程】:https://hibernate.org/orm/documentation/getting-started/
【github地址】:https://github.com/hibernate
目前hibernate已经更新到了6的版本,这里使用的5的版本
文章目录注意: Hibernate5.1;5.2官方推荐使用JDK1.8以及JDBC4
- hibernate
- 一、generator主键策略
- 二、对象关系映射:一对多映射
- 2.1 测试准备
- 2.2 创建实体
- 2.3 hbm.xml文件修改
- 2.4 编写测试类
- 三、casecode和inverse配置
- 3.1 CaseCade级联操作
- 3.2 INVERSE反转配置
- 四、对象关系映射:多对多映射
- 4.1 多对多插入操作
- 4.1.1 数据库设计
- 4.1.2 对象设计
- 4.1.3 映射的配置:fire::fire:
- 4.2 多对多查询
- 4.3 多对多级联添加操作
- 五、对象关系映射:一对一映射
- 5.1 数据库设计
- 5.2 实体类设计
- 5.2.1 外键关联
- 5.2.2 主键关联
- 5.3 配置文件
- 5.3.1 外键关联
- 5.3.2 主键关联
- 5.4 测试
- 5.4.1 外键关联
- 5.4.2 主键关联
一、generator主键策略
generator配置:代表hibernate主键生成策略
【我们可以将其分为三大类】:
- 由数据库维护
- identity:Mysql的auto_increment维护主键自增策略
- sequence:Oracle使用sequence序列维护主键自增策略
- native :本地策略,由hibernate自己根据数据库选择最优策略
- 由hibernate维护
- uuid:生成32位16进制的无效字符串【记住是一个字串】
- increment:生成递增的数值类型(每次先查当前的最大的id值+1)
- 由开发者维护
- asigned:必须要有程序员给定id的值,否则报错
需求案例:客户 与 订单的需求关系:典型的一对多的关系
2.1 测试准备这里我们需要在创建一张表t_order
CREATE TABLE `t_order` ( `id` INT(10) NOT NULL AUTO_INCREMENT, `order_no` VARCHAr(20) NULL DEFAULT NULL COMMENT '订单编号' COLLATE 'utf8mb4_general_ci', `product_name` VARCHAr(20) NULL DEFAULT NULL COMMENT '产品名称' COLLATE 'utf8mb4_general_ci', `cust_id` INT(10) NULL DEFAULT NULL, PRIMARY KEY (`id`) USING BTREE, UNIQUE INDEX `t_order_id_uindex` (`id`) USING BTREE, INDEX `t_order_t_customer_c_id_fk` (`cust_id`) USING BTREE, CONSTRAINT `t_order_t_customer_c_id_fk` FOREIGN KEY (`cust_id`) REFERENCES `hibernate_db`.`t_customer` (`c_id`) ON UPDATE NO ACTION ON DELETE NO ACTION ) COLLATE='utf8mb4_general_ci' ENGINE=InnoDB AUTO_INCREMENT=2;2.2 创建实体
注意事项:
需要在Custom实体中先给一个List
来关联多方的实体信息 order实体表也需要给一个Custom的JavaBean对其进行关联
【Order】
public class Order implements Serializable {
private static final long serialVersionUID = 1L;
private String id; // 订单表主键
private String orderNo; // 订单编号
private String prodName; // 产品名称
private Integer custId; // 外键客户id
private Customer customer;
}
2.3 hbm.xml文件修改
【customer.hbm.xml】
在Custom.hbm.xml文件里,我们需要做的是将order进行关联用set标签
一表中的关联配置使用的标签是:
【order.hbm.xml】
2.4 编写测试类多表中所关联的字段是用的标签是
@Test
public void test1() throws HibernateException {
// 准备数据
Customer lisi = new Customer();
lisi.setName("里斯");
lisi.setGender("1");
lisi.setAge(32);
lisi.setLevel("至尊VIP,年卡8级");
Set orders = new HashSet<>();
// 订单1
Order order1 = new Order();
order1.setOrderNo("20220807111");
order1.setProdName("小米Ultr11");
order1.setCustomer(lisi);
// 订单2
Order order2 = new Order();
order2.setOrderNo("20220807134");
order2.setProdName("华为MateBook_Pro 512G+8G");
order2.setCustomer(lisi);
// 客户添加订单
orders.add(order1);
orders.add(order2);
lisi.setOrders(orders);
Session session = HibernateUtil.getConnection();
//4、开启事务
Transaction tx = session.beginTransaction();
//5、执行添加操作
session.save(lisi);
session.save(order1);
session.save(order2);
//6、提交事务
tx.commit();
//7、关闭资源
HibernateUtil.closeSession(session);
}
【订单表】
【客户表】
为了可以证实是否插入成功,我么可以再写一个方法来查询某一个客户的订单
@Test
public void test2() throws HibernateException {
Session session = HibernateUtil.getConnection();
//4、开启事务
Transaction tx = session.beginTransaction();
//5、执行添加操作
Customer customer = session.get(Customer.class, 5);
System.out.println("用户名称:"+customer.getName());
Set orders = customer.getOrders();
for (Order order : orders) {
System.out.println("订单:"+order.getOrderNo());
}
//6、提交事务
tx.commit();
//7、关闭资源
HibernateUtil.closeSession(session);
}
三、casecode和inverse配置
3.1 CaseCade级联操作
级联操作,就是操作一个对象的时候,相同时操作他的关联对象。
- 级联保存
【测试】
@Test
public void test3() throws HibernateException {
// 准备数据
Customer lisi = new Customer();
lisi.setName("马云云");
lisi.setGender("1");
lisi.setAge(34);
lisi.setLevel("至尊VIP,年卡n级");
Set orders = new HashSet<>();
// 订单1
Order order1 = new Order();
order1.setOrderNo("20220808123");
order1.setProdName("阿里巴巴");
order1.setCustomer(lisi);
// 订单2
Order order2 = new Order();
order2.setOrderNo("20220808141");
order2.setProdName("华强北 只能IPHONE watch");
order2.setCustomer(lisi);
// 客户添加订单
orders.add(order1);
orders.add(order2);
lisi.setOrders(orders);
Session session = HibernateUtil.getConnection();
//4、开启事务
Transaction tx = session.beginTransaction();
//5、执行添加操作
session.save(lisi); // 保存客户
// 级联保存订单数据,所以配置在客户的映射文件中
//6、提交事务
tx.commit();
//7、关闭资源
HibernateUtil.closeSession(session);
}
- 级联删除
【测试】
@Test
public void test4() throws HibernateException {
Session session = HibernateUtil.getConnection();
//4、开启事务
Transaction tx = session.beginTransaction();
//5、执行添加操作
Customer cus = session.get(Customer.class, 6);// 级联删除
//6、提交事务
session.delete(cus);
tx.commit();
//7、关闭资源
HibernateUtil.closeSession(session);
}
如果没有级联删除,则会把外键的值置为空。级联删除则会在删除一个对象的同时将其关联的的对象也删除。
【实现级联操作的注意事项】:
-
搞清楚谁级联操作谁?添加A的时候,级联添加B,那么级联操作的就是B,配置就在A
-
级联操作的核心是cascade="级联操作的属性"
- save-update:级联保存
- delete:级联删除
- all:级联保存和删除
第一次听到这个概念让我想起了Spring的IOC
inverse配置:表示是否把关联表的维护权反转(放弃)
- true:放弃
- false:不放弃(不反转)
这里我们可以看一下级联保存的的时候,wmendeHibernate会自动地有两条SQL帮助我们去维护被关联的表
结论:
通常在一对多的关联关系中,多方不能放弃维护权,建议放弃一方,意味着需要在一方加上inverse=true的配置
需求:用户 与 角色的关联关系:多对多的关系
4.1 多对多插入操作 4.1.1 数据库设计 4.1.2 对象设计【User表】
public class User implements Serializable {
private Integer id;
private String name;
// getter、setter...
}
【Role表】
public class Role implements Serializable {
private Integer id;
private String name;
// getter、setter...
}
4.1.3 映射的配置
【Role.hbm.xml】
【User.hbm.xml】
注意事项:
- 在配置任意一方的set集合关联字段的时候,我们知道hibernate是默认inverse=false的,这样一来在多对多的关系中,就会出现重复的维护冲突,所以我们需要在任意一方设置inverse=true
- 这里建议使用MySQL5的版本,因为hibernate创建表的时候会将存储引擎设置为myisam,如果使用了Mysql8的版本,需要在全局的核心配置文件中设置上
org.hibernate.dialect.MySQL5InnoDBDialect ,否则会报SQL语法错误- 在任意一方配置是都不能配置主键策略,否则无法关联外键的关联关系
4.2 多对多查询org.hibernate.dialect.MySQL5InnoDBDialect
@Test
public void test6() throws HibernateException {
// 准备数据
Session session = HibernateUtil.getConnection();
//4、开启事务
Transaction tx = session.beginTransaction();
//5、执行添加操作
User user = session.get(User.class, 1);
System.out.println("当前用户:"+user.getName());
Set roles1 = user.getRoles();
for (Role role : roles1) {
System.out.println("当前用户的角色:"+role.getName());
}
User user2 = session.get(User.class, 2);
System.out.println("当前用户:"+user2.getName());
Set roles = user2.getRoles();
for (Role role : roles) {
System.out.println("当前用户的角色:"+role.getName());
}
//6、提交事务
tx.commit();
//7、关闭资源
HibernateUtil.closeSession(session);
}
4.3 多对多级联添加操作
User.hbm.xml配置
注意事项:
1.级联操作就是在任意一方设置casecade=级联配置—> 比如级联保存是save-update
@Test
public void test7() throws HibernateException {
// 准备数据
Session session = HibernateUtil.getConnection();
//4、开启事务
Transaction tx = session.beginTransaction();
//5、执行添加操作
User user1 = new User();
user1.setId(3);
user1.setName("大公鸡");
Role r1 = new Role();
r1.setName("五星红钻");
r1.setId(3);
Set roles = new HashSet<>();
roles.add(r1);
user1.setRoles(roles);
session.save(user1);
//6、提交事务
tx.commit();
//7、关闭资源
HibernateUtil.closeSession(session);
}
五、对象关系映射:一对一映射不过通常我更偏向于使用all 包括了级联保存和删除
需求:中华人民共和国公民 与 个人身份证 是典型的一对一关系
5.1 数据库设计 5.2 实体类设计 5.2.1 外键关联【IdCard实体类】
public class IdCard implements Serializable {
private Integer id;
private String name;
private Person person;
//getter、setter...
}
【Person实体类】
public class Personimplements Serializable {
private Integer id;
private String name;
private IdCard card;
//getter、setter...
}
5.2.2 主键关联
【IdCard实体类】
public class IdCard implements Serializable {
private Integer id;
private String name;
private Person person;
//getter、setter...
}
【Person实体类】
public class Personimplements Serializable {
private Integer id;
private String name;
private IdCard card;
//getter、setter...
}
5.3 配置文件
5.3.1 外键关联
【Person.hbm.xml】
【IdCard.hbm.xml】
5.3.2 主键关联注意事项
- 在一对一的配置中给,我们需要设置任意一方的属性为many-to-one,然后通过核心的unique设置其外键是唯一
【Person.hbm.xml】
与外键关联保持一致
【IdCard.hbm.xml】
5.4 测试 5.4.1 外键关联注意事项:
- 逐渐概念需要使用one-to-one标签 其中使用constraint=”true“配置主键关联
@Test
public void test8() throws HibernateException {
// 准备数据
Person p = new Person();
p.setName("魏巍");
IdCard idCard = new IdCard();
idCard.setName("中华人民共和国个人身份证:61020210213826465456");
idCard.setPerson(p);
p.setCard(idCard);
Session session = HibernateUtil.getConnection();
//4、开启事务
Transaction tx = session.beginTransaction();
//5、执行添加操作
session.save(p);
session.save(idCard);
//6、提交事务
tx.commit();
//7、关闭资源
HibernateUtil.closeSession(session);
}
5.4.2 主键关联
@Test
public void test10(){
Session session = HibernateUtil.getConnection();
Transaction tx = session.beginTransaction();
com.wei.domain.onetoone_pk.Person p = new com.wei.domain.onetoone_pk.Person();
p.setName("刘虎");
com.wei.domain.onetoone_pk.IdCard card = new com.wei.domain.onetoone_pk.IdCard();
card.setName("中国台湾身份证6675677457576386");
card.setPerson(p);
p.setCard(card);
session.save(p);
session.save(card);
tx.commit();
HibernateUtil.closeSession(session);
}
【至此,第二章的hibernate的学习就此结束】
总结:
- 配置文件的方式配置一对一,一对多或者是多对多的关系都比较冗余(个人觉得),后期会学习注解是的JPA开发



