Hibernate的介绍及使用
一、什么是hibernate
- hibernate是一个轻量级javaEE持久层框架,是一个ORM框架(对象关系映射,所以这类框架都有个对象关系映射文件xxx.hbm.xml)
在web项目中对数据库的操作流程是–application–>hibernate–>database,hibernate在里面就是连接请求与数据库的桥梁,核心配置文件xxx.hbm.xml用于连接application,hibernate.cfg.xml用于连接database - ORM 表示 Object-Relational Mapping (ORM)
O:object:对象
R:Relational:关系
M:mapping:映射
二、hibernate的属性
a、configuration
- 读取hibernate.cfg.xml
- 管理对象关系映射文件xxx.hbm.xml
- 加载hibernate的配置信息 创建对象Configuration config=new Configuration().configure();
b、SessionFactory
- 缓存sql语句,数据(一级缓存,session级缓存)
- 在应用程序初始化的时候创建,重量级类,一个数据库只要有一个就可以了(为什么叫重量级的类呢,因为sessionFactory管理着连接数据库的会话,网站运行时连接时很重要的,而且存储了大量sql语句或数据,占用了大量内存)
- SessionFactory负责创建Session实例,可以通过Configuration实例构建SessionFactory
sessionFactory= new Configuration().configure().buildSessionFactory();
Session作用
- Session时hibernate数据持久化的基础,可以看作持久化管理工具,提供了很多持久化方法 ,通过这些方法,完成curd操作(save/delete/get/load/update)
- 通常一个数据库事物和一个Session事例绑定,每执行一个事物都要创建一个Session,使用后需要手动关闭
- Session时线程不同步的(不安全),所以要保证在同一线程中使用,可以 用getCurrentSession
- Session实例由SessionFactory构建–Session session=sessionFactory.openSession();)
c、openSession和getCurrentSession区别
- openSession是一个全新的Session getCurrentSession时获取一个和事务绑定的Session
- getCurrentSession在commit后自动关闭,openSession不会 getCurrentSession在hibernatecfg.xml还要配置
三、hibernate的全局配置文件
- 配置方言
<property
name="hibernate.dialect">org.hibernate.dialect.MySQL5Diale
ct</property>
四、hibernate的简单案例编写
- 编写一个员工实体类
package com.cn.lin;
import java.util.Date;
/**
* @Author Lin_Home
* @Date 2020/10/10 18:31
* @Version 1.0
*/
public class Employee {
private Integer id;
private String name;
private String email;
private Date hiredate;
public Employee() {
}
public Employee(Integer id, String name, String email, Date hiredate) {
this.id = id;
this.name = name;
this.email = email;
this.hiredate = hiredate;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Date getHiredate() {
return hiredate;
}
public void setHiredate(Date hiredate) {
this.hiredate = hiredate;
}
@Override
public String toString() {
return "Employee{" +
"id=" + id +
", name='" + name + '\'' +
", email='" + email + '\'' +
", hiredate=" + hiredate +
'}';
}
}
- 编写一个工具类
package com.cn.lin;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
/**
* @Author Lin_Home
* @Date 2020/10/10 18:56
* @Version 1.0
*/
public class HibernateUtils {
//编写hibernate的工具类
private static SessionFactory sessionFactory;
static {
//创建配置对象
Configuration configuration = new Configuration().configure();
//建立sessionFactory对象
sessionFactory = configuration.buildSessionFactory();
}
public static Session openSession(){
//建立会话
return sessionFactory.openSession();
}
}
- 编写一个测试类
package com.cn.lin;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.query.Query;
import org.junit.jupiter.api.Test;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
/**
* @Author Lin_Home
* @Date 2020/10/10 18:38
* @Version 1.0
*/
public class MainTest {
/**
* 实现添加数据
* */
public static void main(String[] args) {
//创建配置对象,他会读取hibernate.cfg.xml文件
Configuration configuration = new Configuration().configure();
//创建一个会话 SessionFactory对象
SessionFactory sessionFactory = configuration.buildSessionFactory();
//连接会话
Session session =sessionFactory.openSession();
//开启事务
Transaction transaction = session.beginTransaction();
Employee employee = new Employee();
employee.setEmail("1415318251@qq.com");
employee.setName("Yee");
long timeMillis = System.currentTimeMillis();
Date date = new Date(timeMillis);
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
simpleDateFormat.format(date);
employee.setHiredate(date);
session.save(employee);
transaction.commit();
//关闭会话
session.close();
}
//删除
@Test
public void deleteByIdTest() {
Session session = HibernateUtils.openSession();
// 4.开启事务
Transaction transaction = session.beginTransaction();
// 5.执行持久化操作
Employee user = session.get(Employee.class, 1);
session.delete(user);
// 6.提交事务
transaction.commit();
// 7.关闭资源
session.close();
}
//修改
@Test
public void UpdateTest(){
Session session = HibernateUtils.openSession();
//开启事务
Transaction transaction = session.beginTransaction();
Employee employee = new Employee();
employee.setId(2);
employee.setEmail("141551@qq.com");
employee.setName("Woo");
long timeMillis = System.currentTimeMillis();
Date date = new Date(timeMillis);
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
simpleDateFormat.format(date);
employee.setHiredate(date);
session.update(employee);
transaction.commit();
//关闭会话
session.close();
}
/**
* 单查询根据id
* */
@Test
public void QueryById(){
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction();
Employee user = session.get(Employee.class, 2);
System.out.println(user);
transaction.commit();
session.close();
}
//全查询 from 对应的是实体类命名
@Test
public void QueryTest(){
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction();
Query query = session.createQuery("from Employee ");
//2、使用Query对象的list方法得到数据集合
List<Employee> list = query.list();
for(Employee employee:list){
System.out.println(employee.getId()+" "+ employee.getName()+" "+employee.getEmail()+" "+employee.getHiredate());
}
transaction.commit();
session.close();
}
//条件查询
@Test
public void QueryByCondition(){
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction();
Query query = session.createQuery("from Employee where name = :name");
query.setParameter("name","Yee");
//2、使用Query对象的list方法得到数据集合
List<Employee> list = query.list();
for(Employee employee:list){
System.out.println(employee.getId()+" "+ employee.getName()+" "+employee.getEmail()+" "+employee.getHiredate());
}
transaction.commit();
session.close();
}
}
- 实体类的配置文件
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.cn.lin">
<class name="com.cn.lin.Employee" table="employee">
<id name="id">
<!-- 数据库的主键交给数据库本地管理-->
<generator class="native"></generator>
<!-- 主键实现自增长-->
<!-- <generator class="identity"></generator>-->
<!-- 自增主键,由Hibernate维护,插入数据前,先从数据库中读取主键最大值+1作为本次主键-->
<!-- <generator class="increment"></generator>-->
<!-- 使用的是String 类型,并且是32位的,自动生成id-->
<!-- <generator class="uuid"></generator>-->
<!-- Oracle数据库中主键生成策略-->
<!-- <generator class="sequence"></generator>-->
</id>
<property name="name" column="name"/>
<property name="email" column="email"></property>
<property name="hiredate" column="hiredate"></property>
</class>
</hibernate-mapping>
- hibernate的生成文件配置
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="connection.url">jdbc:mysql://localhost:3306/hello</property>
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="connection.username">账号</property>
<property name="connection.password">密码</property>
<!-- 导入配置文件的路径 -->
<mapping resource="Employee.hbm.xml"></mapping>
</session-factory>
</hibernate-configuration>
五、Hibernate的主键生成策略
- 开发中尽量使用代理主键,这样可以在主键发生变化的时候不用修改源代码,也满足OCP原则。
- ocp原则介绍:https://blog.csdn.net/benbenxiongyuan/article/details/24021039
a、increment
- hibernate中提供的自动增长机制,适用于short、int、long类型的主键。仅单线程程序中使用。原理:首先发送一条语句:select MAX(id) from 表;然后将id+1作为下一条记录的主键。
b、identity
- 使用数据库底层的自动增长机制,适用于short、long、int。适用于有自动增长机制的数据库(MySQL、MSSQL)。 注意:Oracle是没有自动增长的。
c、 sequence
- 采用序列机制,适用于short、int、long。适用于序列机制的数据库(Oracle)
d、uuid
- uuid 适用于字符串类型主键。使用hibernate中随机方式生成字符串主键。 它会生成唯一的32位的16进制的字符串
e、native
- 本地策略。可以在identity和sequence间进行自动切换。
f、assigned
- hibernate放弃外键管理。需要通过手动编写程序或用户自己设置。
g、foreign
- 外部的。会在一对一的关联映射下使用。
六、hibernate一对多关系用法
-- 客户表
CREATE TABLE t_customer(
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(20),
gender CHAR(1)
);
-- 订单表
CREATE TABLE t_order(
id INT PRIMARY KEY AUTO_INCREMENT,
orderno VARCHAR(20),
product_name VARCHAR(20),
cust_id INT,
CONSTRAINT order_customer_fk FOREIGN KEY(cust_id) REFERENCES
t_customer(id)
);
- 编写一的实体类
package com.lin.cn;
import java.util.Set;
/**
* @Author Lin_Home
* @Date 2020/10/11 14:38
* @Version 1.0
*/
public class Customer {
//id
private Integer id;
//用户名
private String name;
//性别
private String gender;
//客户对应的多个订单号
private Set<Order> order;
public Customer() {
}
public Customer(Integer id, String name, String gender, Set<Order> order) {
this.id = id;
this.name = name;
this.gender = gender;
this.order = order;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public Set<Order> getOrder() {
return order;
}
public void setOrder(Set<Order> order) {
this.order = order;
}
@Override
public String toString() {
return "Customer{" +
"id=" + id +
", name='" + name + '\'' +
", gender='" + gender + '\'' +
", order=" + order +
'}';
}
}
- 编写多的实体类
package com.lin.cn;
/**
* @Author Lin_Home
* @Date 2020/10/11 14:41
* @Version 1.0
*/
public class Order {
//订单id
private Integer id;
//订单编号
private String orderno;
//产品名
private String productName;
//体现一个订单所属一个客户(one)
private Customer customer;
public Order() {
}
public Order(Integer id, String orderno, String productName, Customer customer) {
this.id = id;
this.orderno = orderno;
this.productName = productName;
this.customer = customer;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getOrderno() {
return orderno;
}
public void setOrderno(String orderno) {
this.orderno = orderno;
}
public String getProductName() {
return productName;
}
public void setProductName(String productName) {
this.productName = productName;
}
public Customer getCustomer() {
return customer;
}
public void setCustomer(Customer customer) {
this.customer = customer;
}
@Override
public String toString() {
return "Order{" +
"id=" + id +
", orderno='" + orderno + '\'' +
", productName='" + productName + '\'' +
", customer=" + customer +
'}';
}
}
- 测试类
package com.lin.cn;
import com.sun.org.apache.xpath.internal.operations.Or;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.jupiter.api.Test;
import java.util.HashSet;
import java.util.Set;
/**
* @Author Lin_Home
* @Date 2020/10/11 14:56
* @Version 1.0
*/
public class MainTest {
@Test
public void insertTest(){
//建立会话
Session session = HibernateUtils.openSession();
//建立事务
Transaction transaction = session.beginTransaction();
//开始实体类的赋值
Customer customer = new Customer();
customer.setName("苍井空");
customer.setGender("女");
Order order = new Order();
order.setOrderno("订单一号");
order.setProductName("剧情片场");
Order order2 = new Order();
order2.setOrderno("订单二号");
order2.setProductName("上门片场");
Set<Order> orderSet = new HashSet<>();
orderSet.add(order);
orderSet.add(order2);
order.setCustomer(customer);
order2.setCustomer(customer);
customer.setOrder(orderSet);
//建立持久会话
session.save(customer);
// session.save(order);
// session.save(order2);
transaction.commit();
}
//全部查询
@Test
public void queryAllTest(){
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction();
}
//查询客户
@Test
public void queryCustomer() {
Session session=HibernateUtils.openSession();
Customer customer=session.get(Customer.class,1);
System.out.println("客户名="+customer.getName());
for (Order order : customer.getOrder()) {
System.out.println("订单名 ="+order.getProductName() +"-----订单编号"+order.getOrderno());
}
}
//查询订单
@Test
public void queryOrder() {
Session session=HibernateUtils.openSession();
Order order=session.get(Order.class,1);
System.out.println("订单名="+order.getProductName());
System.out.println("订单所属的客户 ="+order.getCustomer().getName() +"-------订单编号"+order.getOrderno());
}
//数据修改
@Test
public void delete(){
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction();
Customer customer = session.get(Customer.class, 1);
session.delete(customer);
transaction.commit();
session.close();
}
}
- 配置文件
customer 的配置文件
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.lin.cn">
<class name="com.lin.cn.Customer" table="t_customer">
<id name="id">
<!-- 数据库的主键交给数据库本地管理-->
<generator class="native"></generator>
</id>
<property name="name" column="name"/>
<property name="gender" column="gender"></property>
<!-- 对应的是集合 name对应的是集合的变量名 key对应的是数据库中关联表的外键名 class值的是对表中的那个类名-->
<!-- cascade实现级联操作 这个是 实现 添加修改-->
<set name="order" cascade="save-update,delete">
<key column="cust_id"/>
<one-to-many class="Order" />
</set>
</class>
</hibernate-mapping>
- order的配置文件
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.lin.cn">
<class name="com.lin.cn.Order" table="t_order">
<id name="id">
<!-- 数据库的主键交给数据库本地管理-->
<generator class="native"></generator>
</id>
<property name="orderno" column="orderno"/>
<property name="productName" column="product_name"></property>
<!--对应的是集合 name对应的是集合的变量名的主键 column对应的是数据库中关联表的外键名 这边的class指的是映射one表 -->
<many-to-one name="customer" column="cust_id" class="Customer"/>
</class>
</hibernate-mapping>
- 生成的映射文件
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="connection.url">jdbc:mysql://localhost:3306/hello</property>
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="connection.username">root</property>
<property name="connection.password">123456</property>
<property name="hibernate.show_sql">true</property><!-- 配置显示sql语句 -->
<!-- <property name="format_sql">true</property><!– 让输出的sql语句格式化 –>-->
<mapping resource="Customer.hbm.xml"></mapping>
<mapping resource="Order.hbm.xml"/>
</session-factory>
</hibernate-configuration>
a、级联操作
- 只要与此添加的对象相关的对象,它会连同持久化处理(添加或者修改)
<set name="orderSet" cascade="save-update">
<key column="cust_id" />
<one-to-many class="Order"/>
- 删除此对象,连同此对象的相关对象也删除( 要小心配置 )删除
<set name="orderSet" cascade="save-update,delete">
<key column="cust_id" />
<one-to-many class="Order"/>
</set>
b、inverse用法
1、作用
如果inverse为true,则放弃外键控制
如果inverse为false,则不放弃外键关系控制
2、用法
针对一方配置,多方inverse配置不起作用,不管inverse如何配置,多方它都会维护外键处理
用法
在一方配置inverse属性
输出sql语句,发现update语句不见了
<set name="orderSet" inverse="true">
<key column="cust_id" />
<one-to-many class="Order"/>
七、多对多关联问题
1、什么是多对多
- 举例以用户表与角色表为例
- 一个用户可以所属多个角色
- 一个角色里面可以有多个用户
2、多对多表关系实现
- 多对多的关联表的实现要依赖于中间表
- 中间表的user_id的字段其实就是用户表的主键
- 中间表的role_id的字段其实就是角色表的主键
3、编写实体对象
-
编写用户对象
- 注意定义一个Set集合属性,存储一个用户对应多个角色
package com.gec.domain; import java.util.Set; /* * 定义用户类 * */ public class User { private Integer id; private String name; public User() { } public User(Integer id, String name) { this.id = id; this.name = name; } //体现多角色,使用Set集合存储 private Set<Role> roleSet; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Set<Role> getRoleSet() { return roleSet; } public void setRoleSet(Set<Role> roleSet) { this.roleSet = roleSet; } @Override public String toString() { return "User{" + "id=" + id + ", name='" + name + '\'' + '}'; } }
-
编写角色对象
- 注意一个角色可以配置多个用户,因此定义Set集合userSet属性
package com.gec.domain; import java.util.Set; /* * 角色类 * */ public class Role { private Integer roleId; private String roleName; //一个角色可以有多个用户 private Set<User> userSet; public Role() { } public Role(Integer roleId, String roleName) { this.roleId = roleId; this.roleName = roleName; } public Integer getRoleId() { return roleId; } public void setRoleId(Integer roleId) { this.roleId = roleId; } public String getRoleName() { return roleName; } public void setRoleName(String roleName) { this.roleName = roleName; } public Set<User> getUserSet() { return userSet; } public void setUserSet(Set<User> userSet) { this.userSet = userSet; } }
4、编写映射文件
-
用户的映射文件(User.hbm.xml)
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="com.gec.domain"> <class name="User" table="t_user"> <id name="id" column="id"> <generator class="identity" /> </id> <property name="name" column="name"> </property> <!--Set集合映射,映射(一个用户所属多个角色) table:描述多对多所依赖的中间表表名 --> <set name="roleSet" table="t_user_role"> <!---此key的字段就是配置中间表的外键,它指向用户表的主键--> <key column="fk_user_id"></key> <!---此column的字段就是配置中间表的外键,它指向角色表的主键--> <many-to-many class="Role" column="fk_role_id"/> </set> </class> </hibernate-mapping>
-
角色的映射文件(Role.hbm.xml)
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="com.gec.domain"> <class name="Role" table="t_role"> <id name="roleId" column="roleId"> <generator class="identity" /> </id> <property name="roleName" column="roleName"> </property> <!--Set集合映射,映射(一个用户所属多个角色) table:描述多对多所依赖的中间表表名 --> <set name="userSet" table="t_user_role"> <!---此key的字段就是配置中间表的外键,它指向角色表的主键--> <key column="fk_role_id"></key> <!---此column的字段就是配置中间表的外键,它指向用户表的主键--> <many-to-many class="User" column="fk_user_id"/> </set> </class> </hibernate-mapping>
5、编写全局配置文件
-
编写hibernate.cfg.xml
<?xml version='1.0' encoding='utf-8'?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD//EN" "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory> <!--jdbc驱动类名--> <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property> <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/hibernate_db</property> <property name="hibernate.connection.username">root</property> <property name="hibernate.connection.password">1111</property> <!--配置数据库的方言--> <property name="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</property> <!--是否显示sql语句--> <property name="hibernate.show_sql">true</property> <!--hibernate自构建数据库表--> <property name="hibernate.hbm2ddl.auto">create</property> <!--指明映射文件的路径--> <mapping resource="com/gec/domain/User.hbm.xml"/> <mapping resource="com/gec/domain/Role.hbm.xml"/> </session-factory> </hibernate-configuration>
6、操作数据的主类
package com.gec.test;
import com.gec.dbtuils.HibernateUtils;
import com.gec.domain.Role;
import com.gec.domain.User;
import org.hibernate.Session;
import org.hibernate.Transaction;
import java.util.HashSet;
import java.util.Set;
public class MainTest {
public static void main(String[] args) {
// insert();
queryUser();
}
public static void insert(){
//创建用户对象
User user01=new User();
user01.setName("小苍");
User user02=new User();
user02.setName("小罗");
//创建角色对象
Role role01=new Role();
role01.setRoleName("超级管理员");
Role role02=new Role();
role02.setRoleName("普通管理员");
//创建一个角色集合,将此角色添加到小苍用户
Set<Role> roleSet=new HashSet<>();
roleSet.add(role01);
roleSet.add(role02);
user01.setRoleSet(roleSet);
Set<Role> roleSet2=new HashSet<>();
roleSet2.add(role02);
user02.setRoleSet(roleSet2);
//相互关联操作
//定义集合,存储用户对象
Set<User> userSet=new HashSet<>();
userSet.add(user01);
//role01.setUserSet(userSet);
Set<User> userSet2=new HashSet<>();
userSet2.add(user01);
userSet2.add(user02);
//role02.setUserSet(userSet2);
Session session= HibernateUtils.openSession();
Transaction tr=session.beginTransaction();
//针对对象作持久化处理
session.save(user01);
session.save(user02);
session.save(role01);
session.save(role02);
tr.commit();
session.close();
}
//实现查询
public static void queryUser(){
Session session=HibernateUtils.openSession();
User user=session.get(User.class,1);
System.out.println("此用户名="+user.getName());
for (Role role : user.getRoleSet()) {
System.out.println("此用户所属的角色="+role.getRoleName());
}
}
}
八、实现一对一关系
1、什么是一对一关系?
-
两个元素之间它们是
唯一
匹配的关系-
举例
-
公民都有唯一的身份证
公民------->身份证 身份证------>公民
-
-
2、如何设计一对一的数据表关系
-
如何设计数据表
-
方案一:
-
唯一外键关联
- 特点
- 针对外键作唯一的约束
- 特点
-
-
方案二:
-
主键关联
- 特点
- 此字段既是主键,也是外键
- 特点
-
-
3、如何实现唯一的外键关联
a、对象的设计
-
公民的实体类对象
package com.gec.domain; public class Person { private Integer id; private String personName; //以对象方式描述用户所分配的身份证 private Card card; public Person() { } public Person(Integer id, String personName) { this.id = id; this.personName = personName; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getPersonName() { return personName; } public void setPersonName(String personName) { this.personName = personName; } public Card getCard() { return card; } public void setCard(Card card) { this.card = card; } @Override public String toString() { return "Person{" + "id=" + id + ", personName='" + personName + '\'' + '}'; } }
-
身份证的实体类对象
package com.gec.domain; public class Card { private Integer id; private String cardNo; //以对象方式描述身份证所属唯一的公民 private Person person; public Card() { } public Card(Integer id, String cardNo) { this.id = id; this.cardNo = cardNo; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getCardNo() { return cardNo; } public void setCardNo(String cardNo) { this.cardNo = cardNo; } public Person getPerson() { return person; } public void setPerson(Person person) { this.person = person; } @Override public String toString() { return "Card{" + "id=" + id + ", cardNo='" + cardNo + '\'' + '}'; } }
b、映射文件的配置
-
针对Person实体类的映射配置文件
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="com.gec.domain"> <class name="Person" table="t_person"> <id name="id" column="id"> <generator class="identity" /> </id> <property name="personName" column="person_name"> </property> <!--针对身份证对象属性映射处理--> <!-- 一对一的配置 --> <one-to-one name="card" class="Card"/> </class> </hibernate-mapping>
-
针对身份证的实体类映射文件
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="com.gec.domain"> <class name="Card" table="t_card"> <id name="id" column="id"> <generator class="identity" /> </id> <property name="cardNo" column="cardNo"> </property> <!-- 配置多对一,但外键受唯一约束,其实就是一对一 --> <many-to-one name="person" column="person_id" unique="true"/> </class> </hibernate-mapping>
c、全局配置文件
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!--jdbc驱动类名-->
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/hibernate_db</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">1111</property>
<!--配置数据库的方言-->
<property name="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</property>
<!--是否显示sql语句-->
<property name="hibernate.show_sql">true</property>
<property name="hibernate.hbm2ddl.auto">update</property>
<mapping resource="com/gec/domain/Person.hbm.xml" />
<mapping resource="com/gec/domain/Card.hbm.xml" />
</session-factory>
</hibernate-configuration>
d、实现主类
package com.gec.test;
import com.gec.dbutils.HibernateUtils;
import com.gec.domain.Card;
import com.gec.domain.Person;
import org.hibernate.Session;
import org.hibernate.Transaction;
public class MainTest {
public static void main(String[] args) {
//insert();
findPerson();
}
public static void insert(){
//创建Person对象
Person p=new Person();
p.setPersonName("小苍");
//创建身份证对象
Card c=new Card();
c.setCardNo("sn001");
//相互关联
p.setCard(c);
c.setPerson(p);
Session session=HibernateUtils.openSession();
Transaction tr=session.beginTransaction();
//针对公民及身份证作对象的持久化处理
session.save(p);
session.save(c);
tr.commit();
session.close();
}
public static void findPerson(){
Session session=HibernateUtils.openSession();
Transaction transaction=session.beginTransaction();
Person p=session.get(Person.class,1);
System.out.println("用户名="+p.getPersonName());
System.out.println("对应的身份证="+p.getCard().getCardNo());
transaction.commit();
session.close();
}
}
4、主键关联
a、简介
- 表的字段既是主键,又是外键
b、对象实现
- 对象实现如上述一致
c、映射配置文件实现
-
主要修改card.hbm.xml文件
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="com.gec.domain"> <class name="Card" table="t_card"> <id name="id" column="id"> <generator class="identity" /> </id> <property name="cardNo" column="cardNo"> </property> <!-- 主键关联 constrained属性:使用主键作为外键关联 --> <!--<many-to-one name="person" column="person_id" unique="true"/>--> <one-to-one name="person" class="Person" constrained="true"/> </class> </hibernate-mapping>
九、查询功能
-
HQL 查询
-
QBC查询
-
支持sql查询
https://www.cnblogs.com/yizhichenfen/p/11319681.html对应的使用方式
十、对象状态问题
1、状态类别
- 临时态
- 此对象没有OID值,并且不受session对象所管理
- OID:object的ID值,
- 此对象没有OID值,并且不受session对象所管理
- 持久态
- 此对象有 OID值,并且受session所管理
- 游离态
- 此对象有OID值,已经脱离了session所管理
2、举例
-
临时态----》持久态----》游离态
package com.gec.test; import com.gec.domain.Employee; import com.gec.utils.HibernateUtils; import org.hibernate.Session; import org.hibernate.Transaction; public class MainTest { public static void main(String[] args) { objectstatus(); } public static void objectstatus() { //创建一个Employee对象,此对象处于临时状态 Employee employee=new Employee(); employee.setEmpName("周杰伦"); employee.setJob("C++开发"); employee.setSalary(100000.00); employee.setHiredate(new java.util.Date()); Session session= HibernateUtils.openSession(); Transaction transaction=session.beginTransaction(); //从临时态----->持久态 /* * 持久态的特点: * 1、OID有值 * 2、受session所管理 * */ session.save(employee); System.out.println("处于持久态的id值="+employee.getId()); transaction.commit(); session.close(); //employe它就会处于游离态 System.out.println("处于游离态的id值="+employee.getId()); } }
-
状态转换
十一、缓存详解
- 减少访问数据库的次数,提高访问数据的效率
2、验证一级缓存是否存在
-
举例
//测试缓存是否启作用 public static void testCache() { Session session= HibernateUtils.openSession(); Transaction transaction=session.beginTransaction(); //获取id=5的对象 //employee此对象处于持久态 Employee employee=session.get(Employee.class,5); System.out.println(employee.getEmpName()); //此处是使用缓存获取对象数据 Employee employee2=session.get(Employee.class,5); System.out.println(employee2.getEmpName()); transaction.commit(); session.close(); }
3、如何清除一级缓存对象
-
只需要调用以下方法即可
session.evict(employee); session.clear();
-
一级缓存其实它的作用域就是session对象,一级缓存hibernate是默认启动
-
二级缓存它的作用域就是SessionFactory,二级缓存默认是不启动
4、如何配置二级缓存
a、导入encache库
- 导入第三方缓存工具:EhCache
b、配置hibernate.cfg.xml
-
启动二级缓存
-
配置encache
-
需要哪个类使用二级缓存
<!-- 开启 Hibernate 的二级缓存 --> <property name="hibernate.cache.use_second_level_cache">true</property> <!-- 引入 EhCache 的工具 --> <property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property> <class-cache class="实体类路径" usage="read-only" />
c、编写主类,测试二级缓存
Session session= HibernateUtils.openSession();
Transaction transaction=session.beginTransaction();
//获取id=5的对象
//employee此对象处于持久态
Employee employee=session.get(Employee.class,5);
System.out.println(employee.getEmpName());
transaction.commit();
session.close();
Session session2=HibernateUtils.openSession();
//此处是使用缓存获取对象数据
Employee employee2=session2.get(Employee.class,5);
System.out.println(employee2.getEmpName());
session2.close();
十二、延时加载
-
get 和 load的区别
-
load :是存在延时加载(当调用到load 返回来的数据时,才显示sql语句,当是没有执行的时候是存在延时加载)[QueryById]方法
-
get:不存在延时加载,只要调用了get这个方法,直接执行hql 语句**【QueryById2】**
@Test
public void QueryById(){
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction();
Employee user = session.load(Employee.class, 2);
// System.out.println(user);
transaction.commit();
session.close();
}
@Test
public void QueryById2(){
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction();
Employee user = session.get(Employee.class, 2);
// System.out.println(user);
transaction.commit();
session.close();
}
- 配置文件下 设置:lazy=“false”:放弃延时加载 true 是开启延时
1、类延时加载
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.gec.domain">
<class name="Employee" table="t_employee" lazy="false">
<id name="id" column="id">
<generator class="native" />
</id>
<property name="empName" column="emp_name">
</property>
<property name="salary" column="salary" type="java.lang.Double">
</property>
<property name="job" column="job" type="java.lang.String">
</property>
<property name="hiredate" column="hiredate" type="java.util.Date">
</property>
</class>
</hibernate-mapping>
2、类属性延时
-
与表关联的延时加载问题,以一对多为例讲解
-
可以针对一方,设置lazy=true,则支持延时加载,否则放弃延时加载
-
配置一方的延时加载实现
<set name="orderSet" lazy="true"> <!--设置外键字段--> <key column="cust_id" /> <!--指明多方的类名--> <one-to-many class="Order"/> </set>
- 配置lazy=true(默认),则支持延时加载 ,当查询客户对象,只要没有用于order属性对象,,是不会生成sql语句,查询order表内容
- 配置layz=false,不管客户是否使用order属性,都会生成查询订单的sql语句,执行sql
-
配置多方的延时加载实现
<!--映射one的对象--> <many-to-one name="customer" column="cust_id" class="Customer" lazy="false"/>
- 配置lazy=true(默认),则支持延时加载 ,当查询订单对象,只要没有用到客户对象属性,则不会生成查询客户对象的sql语句
-
十三、抓包策略
- hibernate有如下四种原生态的Hibernate抓取策略,分别是:select fetching ,join fetching,subselect fetching,Batch fetching。
-
配置fetch属性
-
select(默认)
生成n条sql 第一条sql:select * from customer where c.id=1; 第二条sql: select * from order where o.cust_id=1;
-
join
-
生成多表关联查询
它只会生成一条sql:select c.*,o.* from customer c left join order o on c.id=o.cust_id where c.id=1
-
-
subselect(针对createQuery起作用)
-
生成子查询
select * from order o where o.cust_id in (select c.id from customer c)
-
-
十四、Threadlocal管理session
1、为什么要使用ThreadLocal管理session
- session是线程不安全的,因此在多线程环境下,session对象不能为共享对象
- 每次运行都要打开及关闭session对象,导致性能受影响
- 如果直接调用sessionfactory.openSession方法,获取session对象,则无法在业务层获取实现事务管理
2、如何配置session受threadlocal管理
a、写法一:
-
自定义session受Threadlocal管理的实现
/* * 定义hibernate的工具类 * 受ThreadLocal管理session * */ public class HibernateUtils { private static SessionFactory sf=null; // 使用线程局部模式 //它其实就是一个map集合 /* * key:就是线程id * value:Session对象 * */ private static ThreadLocal<Session> threadLocal = new ThreadLocal<Session>(); //静态初始化块只加载一次 static { //创建配置对象,它会默认读取hibernate.cfg.xml文件 Configuration configuration=new Configuration().configure(); //创建一个SessionFactory对象 sf=configuration.buildSessionFactory(); } public static Session getCurrentSession() { //先判断threadlocal是否已经存在当前线程的session,如果不存在,才创建session对象 Session session = threadLocal.get(); if(session==null) { session=sf.openSession(); threadLocal.set(session); } return session; } }
b、写法二:
-
通过配置实现
-
配置hibernate.cfg.xml文件
<property name="hibernate.current_session_context_class">thread</property>
-
修改Hibernate工具类代码
public static Session openSession() { return sf.getCurrentSession(); }
-