Hibernate框架
什么是Hibernate
Hibernate是一个持久层的ORM(对象关系映射)框架。
下载Hibernate的开发环境
- documentation:Hibernate开发文档
- lib:Hibernate开发包
- required:Hibernate开发的必须依赖包
- optional:Hibernate开发的可选jar包
- project:Hibernate测试项目
创建JAVAEE项目,搭建Hibernate环境
导入jar包
- 数据库驱动包
mysql-connector-java-6.0.6.jar - Hibernate开发必须的jar包
- 引入日志记录包
创建项目
-
创建表
-
创建实体类(对应表格)
-
创建类与表的映射配置(实体类名.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.pojo.Customer" table="cst_customer"> <!--建立类中的属性与表中的主键对应--> <id name="cust_id" column="cust_id"> <generator class="native" /> </id> <!--建立类中普通的属性和表的字段的对应--> <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_mobile" column="cust_mobile"></property> <property name="cust_name" column="cust_name"></property> <property name="cust_phone" column="cust_phone"></property> </class> </hibernate-mapping>
映射约束从导入的jar包hibernate-core-5.0.7.Final.jar!\org\hibernate\hibernate-mapping-3.0.dtd中复制
-
创建Hibernate的核心配置文件hibernate.cfg.xml
配置数据库连接参数
配置打印sql语句
配置hibernate的方言
配置映射文件<?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> <!--连接数据库的基本参数--> <property name="hibernate.connection.driver_class">com.mysql.cj.jdbc.Driver</property> <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/hibernate_day01?serverTimezone=Asia/Shanghai&characterEncoding=UTF-8</property> <property name="hibernate.connection.username">root</property> <property name="hibernate.connection.password">cqrjxk39</property> <!--打印sql--> <property name="hibernate.show_sql">true</property> <!--格式化sql--> <property name="hibernate.format_sql">true</property> <!--配置hibernate的方言--> <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property> <mapping resource="com/hibernate/pojo/Customer.hbm.xml"></mapping> </session-factory> </hibernate-configuration>
-
测试
- 加载Hibernate核心配置文件
- 创建SessionFactory对象:类似JDBC连接池
- 通过SessionFactory获取session对象:类似JDBC中的Connection
- 开启事务
- 编写代码
- 事务提交
- 资源释放
public void test1(){ //1. 加载Hibernate核心配置文件 Configuration configure = new Configuration().configure(); //2. 创建SessionFactory对象:类似于JDBC连接池 SessionFactory sessionFactory = configure.buildSessionFactory(); //3. 通过SessionFactory获取Session对象:类似JDBC中的Connection Session session = sessionFactory.openSession(); //4. 开启事务 Transaction transaction = session.beginTransaction(); //5. 编写代码 Customer customer = new Customer(); customer.setCust_name("张三"); session.save(customer); //6. 事务提交 transaction.commit(); //7. 资源释放 session.close(); }
总结映射的配置
- class标签的配置:
- 标签用来建立类与表的映射关系
- 属性:
- name: 类的全路径
- table: 表名(类名与表名一致,table可以省略)
- catalog: 数据库名
- id标签的配置:
- 标签用来建立类中的属性与表中主键的对应关系
- 属性:
- name:类中的属性名
- column:表中的字段名(类中的属性名与表名一致,colume可以省略)
- length:长度
- property标签的配置:
- 标签用来建立类中的属性与表中普通字段的对应关系
- 属性:
- name:类中的属性名
- column:表中的字段名
- length:长度
- not-null:设置非空
- unique:设置唯一
注意: Hibernate是可以根据映射关系自动创建表的,只需要在Hibernate的核心配置文件hibernate.cfg.xml中配置如下语句即可:
<property name="hibernate.hbm2ddl.auto">update</property>
总结核心配置
- 必须配置:
- 连接数据库的基本参数:
- 驱动类
- ul路径
- 用户名
- 密码
- 方言
- 连接数据库的基本参数:
- 可选配置:
- 显示SQL:hibernate.show_sql
- 格式化SQL:hibernate.format_sql
- 自动建表:hibernate.hbm2ddl.auto
- none:不使用hibernate的自动建表
- create:如果数据库中已经有表,删除原有表,重新建表(测试使用)
- create-drop:如果数据库中已经有表,删除原有表,重新建表,表格使用完后删除该表(测试使用)
- update:如果数据库中有表使用原有表,如果数据库中没有表则创建表,可以更新表结构
- validate:如果没有表,不会创建表,只会使用数据库中原有的表(会自动校验映射与表结构,不匹配会报错)
- 映射文件的引入:
- 通过mapping标签引入映射文件的位置
总结测试时需要的几个对象
Hibernate的核心配置文件既可以使用属性文件进行配置,也可以使用xml文件进行配置,但是属性文件配置时不能引入映射文件,需要手动加载映射文件。
- Configuration:
- 作用:
- 加载核心配置文件
- hibernate.properties
- Configuration cfg = new Configuration();
- 加载映射配置文件:cfg.addResource("com/hibernate/pojo/Customer.hbm.xml");
- hibernate.cfg.xml
- Configuration cfg = new Configuration().configure();
- 作用:
- SessionFactory:
- 作用:
- 维护了Hibernate的连接池,线程安全的,一个项目只需要创建一个即可,所以一般将其抽取为Hibernate的工具类
- 作用:
Hibernate的工具类:
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class HibernateUtil {
private static final Configuration cfg;
private static final SessionFactory sf;
static {
cfg = new Configuration().configure();
sf = cfg.buildSessionFactory();
}
public static Session getSession(){
return sf.openSession();
}
}
- Session:Hibernate与数据库的连接对象,是Hibernate与数据库交互的桥梁,线程不安全,所以不能定义为全局变量,只能定义为局部变量
- Session中常用的方法:
- 保存方法,返回Serializable类型的主键:
- Serializable save(Object obj)
- 查询方法:
- T get(Class clazz,Serializable id)
- T load(Class clazz,Serializable id)
- get和load的区别:
- get采用的是立即加载,当执行get方法时,立即发送SQL语句,load采用的是懒加载,当执行load方法时不会发送SQL语句,而是在使用其查询对象的时候才会发送SQL
- get方法返回的是真实对象本身,load返回的是代理对象,利用javassit.jar产生的代理
- get方法查询时数据库中找不到时,会返回空,load会抛出异常ObjectNotFoundException
- 修改方法:(推荐使用先查询再修改)
- void update(Object obj)
- 删除方法:(推荐使用先查询再删除)--级联删除
- void delete(Object obj)
- 保存或更新:(不常用)
- void saveOrUpdate(Object obj)
- 查询所有:
- Query query = session.createQuery("from 类名");
List<类名> list = query.list(); - SQLQuery query = session.createSQLQuery("select * from 表名");
List<数组类型> list = query.list();
- Query query = session.createQuery("from 类名");
- 保存方法,返回Serializable类型的主键:
例如:
//根据id查询
Customer customer = session.get(Customer.class, 1L);
System.out.println(customer);
Customer customer1 = session.load(Customer.class, 1L);
System.out.println(customer1);
//修改
Customer customer = session.get(Customer.class, 1L);
session.update(customer);
//删除
Customer customer = session.get(Customer.class, 1L);
session.delete(customer);
//查询所有
Query query = session.createQuery("from Customer");
List<Customer> list = query.list();
SQLQuery sqlQuery = session.createSQLQuery("select * from cst_customer");
List<Object[]> list1 = sqlQuery.list();
持久化类
什么是持久化类
持久化:将内存中的一个对象持久化到数据库中的过程
持久化类:一个Java对象与数据库的表建立了映射关系,那么这个类就称为持久化类
持久化类的编写规则
- 必须提供一个无参构造方法,因为Hibernate底层需要使用反射生成实例
- 属性需要私有,并提供公有的get和set方法
- 对持久化类提供一个唯一的标识OID与数据库的主键相对应
- 持久类的属性尽量使用引用类型,因为引用类型默认值是null
- 持久化类尽量不要使用final修饰,因为Hibernate有一个懒加载的优化手段,返回的时代里对象,代理对象是继承这个类进行代理的
主键生成策略
主键的分类
自然主键
自然主键指的是主键本身是表中的一个字段
例如:创建一个人员表,人员都会有一个身份证号(唯一不重复),使用身份证号作为主键,这种主键称为自然主键
代理主键
代理主键指的是主键本身不是表中必须要有的字段
例如:创建一个人员表,给每一个人编一个号pno(唯一不重复),使用编号作为主键,这种主键称为代理主键
实际开发
实际开发中,尽量使用代理主键,一旦主键参与到业务逻辑中去,后期有可能要修改源代码,好的程序应该满足ocp原则,对程序扩展是open的,对修改源代码是close的
Hibernate的主键生成策略
在实际开发中一般允许用户手动设置主键,一般将主键交给数据库,手动编写程序进行设置。在Hibernate中为了减少编程,提供了多种主键生成策略。
- increment : Hibernate中提供的增长机制,适用于short,int,long类型的主键,在单线程中使用
- identity:适用于Int,short,long类型的主键,使用的是数据库底层的自动增长机制,适用于有自动增长机制的数据库(MySQL,oracle不支持)
- sequence:适用于short,int,long类型的主键,采用的是序列的方式(Oracle支持序列,MySQL不支持)
- uuid:使用于字符串类型的主键,使用Hibernate中的随机方式自动生成字符串主键
- native:本地策略,可以在identity和sequence之间自动切换
- assigned:Hibernate放弃主键管理,需要自己手动编写程序
例如
<id name="cust_id" column="cust_id">
<generator class="native" />
</id>
持久化类的三种状态
瞬时态
这种对象没有唯一的标识OID,没有被session管理
持久态
这种对象有唯一标识OID,被session管理
脱管态
这种对象有唯一标识OID,没有被session管理
区分三种状态对象
例如:
public void test1(){
Session session = HibernateUtil.getSession();
Transaction transaction = session.beginTransaction();
Customer customer = new Customer();//瞬时态对象
customer.setCust_name("李四");
Serializable id = session.save(customer);
Customer customer1 = session.get(Customer.class, id);//持久态
transaction.commit();
session.close();
System.out.println("客户名称:"+customer.getCust_name());//脱管态对象
}
- 瞬时态对象:
- 获得:
- Customer cutomer = new Customer();
- 状态转换:
- 瞬时 → 持久:
- save(Object obj);
- saveOrUpdate(Object obj);
- 瞬时 → 脱管:
- customer.setCust_id(1L);
- 瞬时 → 持久:
- 获得:
- 持久态对象:
- 获得:
- get();
- load();
- find();
- iterate();
- 状态转换:
- 持久 → 瞬时:
- delete();
- 持久 → 脱管:
- close();
- clear();
- evict(Object obj);
- 持久 → 瞬时:
- 获得:
- 脱管态对象:
- 获得:
- Customer customer() = new Customer(); customer.setCust_id(1L);
- 状态转换:
- 脱管 → 持久:
- update();
- saveIrUpdate();
- 脱管 → 瞬时:
- customer.setCust_id(null);
- 脱管 → 持久:
- 获得:
持久态的重要特点
持久态可以自动更新数据库(由Hibernate的一级缓存实现)
例如:
public void test1(){
Session session = HibernateUtil.getSession();
Transaction transaction = session.beginTransaction();
Customer customer = session.get(Customer.class, 6L);
customer.setCust_name("王五");
transaction.commit();
session.close();
}
上面的程序并有使用update方法,但是因为customer是持久态对象,所以也会更新数据库的内容为王五
Hibernate的缓存
什么是缓存
缓存是一种优化机制,可以将数据存入内存中,使用时直接从缓存中获取,不用通过存储源
Hibernate的一级缓存
Hibernate的一级缓存,又称session级别的缓存,一级缓存的生命周期与session一致,一级缓存是Hibernate自带的,不可卸载的。
特点:
- 当应用程序调用session接口的save(),update(),saveOrUpdate()时,如果session缓存中没有相应的对象,Hibernate会自动从数据库中查询相应的对象信息到一级缓存中
- 当应用程序调用session接口的load(),get()方法,以及query接口的list(),iterator()方法时,会判断缓存中是否存在该对象,有则返回,没有就会查询数据库,并将其添加到一级缓存中
- 当应用程序调用session的close()方法时,session缓存会被清空
例如:
public void test1(){
Session session = HibernateUtil.getSession();
Transaction transaction = session.beginTransaction();
Customer customer = session.get(Customer.class, 6L);
Customer customer1 = session.get(Customer.class, 6L);
System.out.println(customer == customer1);
transaction.commit();
session.close();
}
运行结果:
通过控制台打印的数据我们可以发现,程序的两次查询只发送了一次sql语句,并且查询得到的对象是一个对象,证明Hibernate是有一级缓存的
Query的简单使用
query接口用于接收HQL,查询多个对象
-
查询所有:
String hql = "from Customer"; Query query = session.createQuery(hql); List<Customer> list = query.list(); for (Customer customer:list){ System.out.println(customer); }
-
查询某些(带条件查询)
String hql = "from Customer where cust_name like ?"; Query query = session.createQuery(hql); //从0开始 query.setParameter(0,"王%"); List<Customer> list = query.list(); for (Customer customer:list){ System.out.println(customer); }
-
分页查询
String hql = "from Customer"; Query query = session.createQuery(hql); //设置起始页 query.setFirstResult(0); //设置每页的记录数 query.setMaxResults(3); List<Customer> list = query.list(); for (Customer customer:list){ System.out.println(customer); }
Criteria
更加面向对象的查询,完全看不到查询语句
-
查询所有:
Criteria criteria = session.createCriteria(Customer.class); List<Customer> list = criteria.list(); for (Customer customer:list){ System.out.println(customer); }
-
查询某些
Criteria criteria = session.createCriteria(Customer.class); criteria.add(Restrictions.like("cust_name","王%")); List<Customer> list = criteria.list(); for (Customer customer:list){ System.out.println(customer); }
-
分页查询
Criteria criteria = session.createCriteria(Customer.class); criteria.setFirstResult(0); criteria.setMaxResults(3); List<Customer> list = criteria.list(); for (Customer customer:list){ System.out.println(customer); }
SQLQuery
SQLQuery用于接收sql语句,特别复杂的请况下使用。