Hibernate01-基础
Hibernate01-基础
1.Hibernate入门程序
- 引入依赖。
<dependencies>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-c3p0</artifactId>
<version>5.6.4.Final</version>
</dependency>
</dependencies>
- hibernate.cfg.xml配置文件。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- 数据库配置 -->
<!-- 配置连接MySQL数据库连接的基本参数 -->
<property name="hibernate.connection.driver_class">com.mysql.cj.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql://127.0.0.1:3306/ke?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=UTF-8&useSSL=true&allowMultiQueries=true</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">123456</property>
<!-- hibernate框架配置 -->
<!-- 配置Hibernate的方言 -->
<property name="hibernate.dialect">org.hibernate.dialect.MySQL8Dialect</property>
<!-- 输出执行的SQL -->
<property name="hibernate.show_sql">true</property>
<!-- SQL格式化 -->
<property name="hibernate.format_sql">true</property>
<property name="hibernate.hbm2ddl.auto">update</property>
<!-- 配置c3p0数据库连接池 -->
<property name="hibernate.c3p0.min_size">10</property>
<property name="hibernate.c3p0.max_size">20</property>
<!-- 数据库连接池中的数量超过最大的数量后,没有超过最大的数量,每次向数据库申请2个连接。 -->
<property name="hibernate.c3p0.acquire_increment">2</property>
<!-- 超过最小的数量,空闲2秒后就会被回收。 -->
<property name="hibernate.c3p0.timeout">2000</property>
<!-- 每个两秒检查一次,是否有空闲的连接需要回收 -->
<property name="hibernate.c3p0.idle_test_period">2000</property>
<!-- 可以缓存的最大的statements数量。 -->
<property name="hibernate.c3p0.max_statements">10</property>
<!-- 这两个配置对Mysql是无效的,但是对Oracle是有效的 -->
<!-- fetch_size,查询时每次数据库每次返回100条数据;batch_size,更新时每次更新30条数据。 -->
<property name="hibernate.jdbc.fetch_size">100</property>
<property name="hibernate.jdbc.batch_size">30</property>
<!-- 关联数据库和实体类的映射文件 -->
<mapping resource="mapping/User.hbm.xml" />
</session-factory>
</hibernate-configuration>
- 实体类和数据库表映射的配置文件。
<?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.my.hibernate01.pojo.User" table="tb_user">
<!-- 建立类中的属性与表中的主键的映射 -->
<id name="id" column="id">
<!-- 主键的生成策略,使用数据库本地的方式生成id。 -->
<generator class="native" />
</id>
<!-- 类中普通属性和表中的字段的映射 -->
<property name="name" column="name" />
<property name="age" column="age" />
</class>
</hibernate-mapping>
- 实体类。
@Data
public class User {
private int id;
private String name;
private int age;
}
- 插入数据的Hello World。
public class Test01 {
private Session session;
private Transaction transaction;
private SessionFactory sessionFactory;
@Test
public void testHelloWorld() {
User user = new User();
user.setName("tom");
user.setAge(10);
session.save(user);
}
@Before
public void before() {
// 1 加载Hibernate的核心配置文件
Configuration configuration = new Configuration().configure();
// 2 创建SessionFactory对象,类似于JDBC中的连接池
sessionFactory = configuration.buildSessionFactory();
// 3 通过SessionFactory获取到Session对象,类似于JDBC中的Connection
session = sessionFactory.openSession();
// 4 开启事务
transaction = session.beginTransaction();
}
@After
public void after() {
// 5 关闭事务
transaction.commit();
// 6 释放资源
session.close();
sessionFactory.close();
}
}
2.hibernate核心配置文件hibernate.cfg.xml
- hibernate.hbm2ddl.auto配置。
<!-- 自动生成数据库表的策略。
1 create,每次启动都会重新生成数据库表,会导致之前的数据丢失。
2 create_drop,SessionFactory关闭就会将数据库表删除。
3 update,没有对应的数据库表时,在进行创建。
4 validate,会将数据库表和实体类进行比较,如果不同则抛出异常。
-->
<property name="hibernate.hbm2ddl.auto">update</property>
3.实体类和数据库表映射文件Xxx.hbm.xml
- 配置包名。
<hibernate-mapping package="com.my.hibernate01.pojo">
</hibernate-mapping>
4.hibernate核心类
-
Configuration的作用是启动hibernate程序,加载hibernate.cfg.xml配置文件,通常情况下Configuration对象只有一个实例,即Configuration是单例的。
-
SessionFactory接口的作用加载连接数据库,扩展参数,映射信息,通过这些映
射信息创建Session对象,通常情况下SessionFactory也是单例的。
-
Session接口提供CRUD方法来操作对象,从而操作数据库。Session是线程不安全的对象,在项目中可以创建多个Session对象,每个线程就创建一个Session对象。
-
Transaction接口用于执行事务操作 。
-
Query接口用于执行HQL查询。
-
Criteria接口用于执行基于对象的查询(QBC查询)。
5.Session核心方法
- save(Object obj) ,保存对象。
- update(Object obj),更新对象。
- saveOrUpdate(Object obj),添加或修改对象。
- delete(Object obj),删除对象。
- get(Class clz,Serialize id),获取对象。
- load(Class clz,Serialize id),获取对象。和get获取对象的区别,load()延时加载,在对象使用时才从数据库查询数据。
6.hibernate主键策略
- identity,利用数据库的自增长,如Mysql的auto_increment。
- sequence,利用数据库序列生成的能力,例如Oracle的sequence。
- native,本地策略,由hibernate自动根据不同的数据选择最优策略。如Mysql选择identity;Oracle选择sequence。
- uuid,生成32位16进制的字符串,id需要是String类型。
- increment,生成数据库表递进的数值类型。会查询当前表中最大的id,select max(id) from tb_student,会有并发问题。
- assigned,由开发者在插入时填充主键。
7.对象关系映射-一对多
- 实例类。如果实体类使用@Data注解,会有循环加载的问题。
@Getter
@Setter
@ToString
public class Customer {
private int id;
private String name;
@ToString.Exclude
private Set<Order> orders = new HashSet<>();
}
@Getter
@Setter
@ToString
public class Order {
private int id;
private String orderName;
@ToString.Exclude
private Customer customer;
}
- Xxx.hbm.xml映射文件。
<hibernate-mapping>
<class name="com.my.manyToOne.Customer" table="tb_customer">
<id name="id" column="id">
<generator class="native" />
</id>
<property name="name" column="name" />
<set name="orders" cascade="delete">
<key column="customer_id" />
<one-to-many class="com.my.manyToOne.Order" />
</set>
</class>
</hibernate-mapping>
<hibernate-mapping>
<class name="com.my.manyToOne.Order" table="tb_order">
<id name="id" column="id">
<generator class="native" />
</id>
<property name="orderName" column="order_name" />
<many-to-one name="customer" class="com.my.manyToOne.Customer" column="customer_id" />
</class>
</hibernate-mapping>
- insert插入操作。
@Test
public void testManyToOneInsert() {
Customer customer = new Customer();
customer.setName("alice");
Order order01 = new Order();
order01.setOrderName("A002");
Order order02 = new Order();
order02.setOrderName("A002");
order01.setCustomer(customer);
order02.setCustomer(customer);
session.save(customer);
session.save(order01);
session.save(order02);
}
- select查询操作。
@Test
public void testManyToOneGet() {
Customer customer = session.get(Customer.class, 1);
System.out.println(customer);
// 延时加载,使用时进行数据库的查询。
System.out.println(customer.getOrders());
}
-
delete删除操作。
- 没有在Customer.hbm.xml中配置cascade="delete"。
@Test public void testManyToOneDelete() { Customer customer = session.get(Customer.class, 7); // 1 没有在Customer.hbm.xml中配置cascade="delete",不会进行级联删除, // 删除有映射关系的数据,会进行两步操作。 // 1) 将tb_order对应的customer_id设置为null。 // 2) 删除tb_customer中对应的customer_id数据,不会删除tb_order对应的数据。 session.delete(customer); }
- 在Customer.hbm.xml中配置cascade="delete"。
@Test public void testManyToOneDelete() { Customer customer = session.get(Customer.class, 7); // 2 在Customer.hbm.xml的Set中配置cascade="delete"。 // 1) 先查询到tb_custom关联的tb_order数据。 // 2) 将tb_order的customer_id设置为null。 // 3) 将tb_order对应的customer_id这条数据删除。 // 4) 将删除tb_customer中的数据。 session.delete(customer); }
- 在Customer.hbm.xml中配置cascade="delete" inverse="true"。
@Test public void testManyToOneDelete() { Customer customer = session.get(Customer.class, 7); // 3 在Customer.hbm.xml的Set中配置cascade="delete" inverse="true",Customer放弃 // 维护关系。 // 1) 先查询到tb_custom关联的tb_order数据。 // 2) 将tb_order对应的customer_id这条数据删除。 // 3) 将删除tb_customer中的数据。 session.delete(customer); }
8.cascade和inverse配置详解
- cascade,级联操作。级联保存,save-update;级联删除,delete;级联保存与删除:,all。
- inverse, 是否把关联关系的维护权反转。默认inverse=false。如果设置inverse=true,即当前方放弃关联关系的维护。通常在一对多的关联配置中,多方无法放弃关系维护权,建议放弃1方的维护权,在1方加上inverse=true配置。
9.对象关系映射-多对多
- 实体类。
@Getter
@Setter
@ToString
public class Person {
private int id;
private String name;
private Set<Role> roles = new HashSet<>();
}
@Getter
@Setter
@ToString
public class Role {
private int id;
private String name;
// 多对多映射在一方,排除toString()方法,防止循环查询。
@ToString.Exclude
private Set<Person> persons = new HashSet<>();
}
- xml配置文件。
<hibernate-mapping package="com.my.manyToMany">
<class name="Person" table="tb_person">
<id name="id" column="id">
<generator class="native" />
</id>
<property name="name" column="name" />
<!-- 多对多的映射,table用于指定中间表 -->
<set name="roles" table="tb_person_role">
<!-- tb_person在中间表对应的外键 -->
<key column="person_id" />
<!-- tb_role对应的类和在中间表的外键。 -->
<many-to-many class="Role" column="role_id" />
</set>
</class>
</hibernate-mapping>
<hibernate-mapping>
<class name="com.my.manyToMany.Role" table="tb_role">
<id name="id" column="id">
<generator class="native" />
</id>
<property name="name" column="name" />
<!-- 多对多的映射,table用于指定中间表 -->
<set name="persons" table="tb_person_role" inverse="true">
<!-- tb_role在中间表对应的外键 -->
<key column="role_id" />
<!-- tb_person对应的类和在中间表的外键。 -->
<many-to-many class="com.my.manyToMany.Person" column="person_id" />
</set>
</class>
</hibernate-mapping>
- insert操作。
/**
* 如果tb_person和tb_role都维护关联关系,就会在tb_person_role中添加重复的记录,两种解决方法。
* 1) 代码中进行一方关系的维护,即只有一方使用Set.add()维护关系。
* 2) 在tb_role中使用inverse="true",放弃关联关系的维护。
*/
@Test
public void manyToManySave() {
Person p1 = new Person();
p1.setName("tom");
Person p2 = new Person();
p2.setName("alice");
Role role1 = new Role();
role1.setName("超级管理员");
Role role2 = new Role();
role2.setName("管理员");
// Person和Role都维护关联关系。
p1.getRoles().add(role1);
p1.getRoles().add(role2);
p2.getRoles().add(role1);
// 代码中Role放弃关联关系的维护。
//role1.getPersons().add(p1);
//role1.getPersons().add(p2);
//role2.getPersons().add(p1);
session.save(p1);
session.save(p2);
session.save(role1);
session.save(role2);
}
- select操作。
@Test
public void manyToManySelect() {
Person person = session.get(Person.class, 1);
System.out.println(person.getRoles());
}
- delete操作。
@Test
public void manyToManyDelete() {
Person person = new Person();
person.setId(1);
// tb_person中配置cascade="all",级联删除,会进行两步操作。
// 1) 删除中间表tb_person_role的记录。
// 2) 删除tb_person中的数据,不会删除tb_role中的数据。
session.delete(person);
}
10.对象关系映射-一对一
-
一对一的两种实现方式。
- 外键关联映射,给外键添加唯一约束,用于一对一的映射,会有一个单独的列最为外键进行唯一映射。
- 主键关联映射。使用id列映射另一个表的id列。
-
外键关联映射。
- 实体类。
@Getter @Setter @ToString public class Student { private int id; private String name; private Card card; } @Getter @Setter public class Card { private int id; private String cardNo; @ToString.Exclude private Student student; }
- xml映射关系。
<hibernate-mapping package="com.my.ontToOne"> <class name="Student" table="tb_student"> <id name="id" column="id"> <generator class="native" /> </id> <property name="name" column="name" /> <one-to-one name="card" class="Card" /> </class> </hibernate-mapping> <hibernate-mapping package="com.my.ontToOne"> <class name="Card" table="tb_card"> <id name="id" column="id"> <generator class="native" /> </id> <property name="cardNo" column="card_no" /> <!-- 外键映射,配置unique="true"后,这个外键就是唯一的。 --> <many-to-one name="student" column="student_id" class="Student" unique="true" /> </class> </hibernate-mapping>操作。
- insert操作。
@Test public void oneToOneSave() { Student student = new Student(); student.setName("alice"); Card card = new Card(); card.setCardNo("0002"); card.setStudent(student); session.save(student); session.save(card); }
-
主键关联映射,只需要修改Card的xml配置文件。
<hibernate-mapping package="com.my.ontToOne">
<class name="Card" table="tb_card">
<id name="id" column="id">
<generator class="native" />
</id>
<property name="cardNo" column="card_no" />
<!-- 主键关联映射,constrained="true",表示主键关联映射,
tb_card的id会使用tb_student的id,从而进行主键关联。 -->
<one-to-one name="student" class="Student" constrained="true" />
</class>
</hibernate-mapping>
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异