基础
一、Hibernate简单案例实现
1、Hirbernate项目及四要素**
实体类(POJO类):持久化javaBean类
对象-关系映射文件(*_hbm.xml)
主配置文件(hibernate.cfg.xml)
编写Hibernate提供的API执行程序
实现过程
(1)创建应用工程
1)下载Hibernate5的jar包:点击获取
随便选一个安装包下载
2)导入jar包
注意:此处的项目为普通的java项目
手动创建lib文件夹(lib是导入jar 包的存放位置)
具体jar包:(还有Mysql的驱动jar包)
hibernate项目成功的目录
(2)、编写*.hbm.xml对象关系映射文件(重点)
1)在src下新建实体类(POJO,javaBean,unity,domain等)
Animal.java(com.test.domain)
package com.test.domain;
public class Animal {
private Integer aid;
private String aname;
private Integer age;
public Integer getAid() {
return aid;
}
public void setAid(Integer aid) {
this.aid = aid;
}
public String getAname() {
return aname;
}
public void setAname(String aname) {
this.aname = aname;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
// TODO Auto-generated method stub
return "animal message:"+aid+aname+age;
}
}
2)编写*.hbm.xml对象关系映射文件
进入Animal.hbm.xml修改
(3)、编写hibernate.cfg.xml文件
建议放在src目录下
一路next
注意:最后可能因为版本兼容问题,finish不了,建议更换版本尝试。
修改hibernate.cfg.xml配置
hibernate.cfg.xml添加
<mapping resource="com/test/domain/Animal.hbm.xml"/>
(4)、编写Hibernate测试代码
1)创建一个SessionFactory工厂类
2)通过工厂开启Session对象
3)开始事务
4)执行数据库的操作
5)提交事务
6)关闭Session
7)关闭工厂类
HibernateTest.java
具体代码:
package com.test.domain;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.junit.Test;
public class HibernateTest {
@Test
public void test() {
Animal animal = new Animal();
animal.setAid(1);
animal.setAname("猴子");
animal.setAge(12);
// 创建Configuration实例,读取默认hibernate配置文件
Configuration cfg = new Configuration().configure();
// 通过cfg创建一个SessionFactory工厂类,维护着2级缓存,不需要关闭
SessionFactory sessionFactory = cfg.buildSessionFactory();
// 通过工厂类开启Session对象
Session session = sessionFactory.openSession();
// 开始事务
Transaction transaction = session.beginTransaction();
// 执行数据库操作,session维护着1级缓存
session.save(animal);
// 提交事务
transaction.commit();
// 回滚,以免产生脏数据
// transaction.rollback();
// 关闭Session
session.close();
// 关闭工厂类,在web程序中不用关闭,整个应用程序对应一个sessionFactory
// sessionFactory.close();
}
}
(5)运行测试类
2、简单案例分析
(1)hibernate.cfg.xml
hibernate.dialect:数据库方言
hibernate.show_sql:控制台打印输出sql
hibernate.format_sql:格式化sql
hibernate.hbm2ddl.auto
create:
每次创建sessionFactory时都会删除以前的数据库表,重新
创建,不推荐使用。
create-drop:
每次关闭sessionFactory时都会删除所有的表。
update:
常用,第一次加载会自动创建,以后创建都会根据POJO更新表
结构,不会删除数据和表。
validate:每次加载时会验证数据库的表结构,如果POJO和数
据库结构不匹配则会报错,不会创建新表。
(2)POJP
javaBean对象
(3)映射文件 POJO.hbm.xml
该文件充当Hibernate框架与数据库持久化桥梁的作用
一个class描述一个类和一个表的对应关系
id:主键设置,generator标记主键的生成策略,一般采用native,方便数据库移植
property:描述属性和数据库关系
若column不写,则和name相同
3、主键策略
4、常用API解析
(1)Configuration读取配置文件
configuration类负责管理Hibernate的配置信息,包括核心配置和.hbm.xml配置
(2)、SessionFactory工厂类
1)由Configuration对象创建
2)SessionFactory保存着当前数据库配置信息和所有映射关系预定义的SQL语句,同时还负责Hibernate的二级缓存,一个SessionFactory实例对应一个数据库,应用从该对象中获得Session实例
3)SessionFactory是重量级的,意味着不能随意创建和销毁它的实例。如果只访问一个数据库,只需要创建一个SessionFactory实例,且在应用初始化的时候完成。
4)SessionFactory需要一个较大的缓存,用来存放预定义的SQL语句及实体的映射信息。另外可以配置一个缓存插件,这个插件被称为Hibernate的二级缓存,被多线程所共享。
(3)Session对象
Session是在Hibernate中使用最频繁的接口。也被称为持久化管理器。它提供了和持久化有关的操作。比如添加、修改、删除、加载和查询实体对象。
不是线程安全的,应避免多个线程使用同一个Session实例,Session是轻量级的,它的创建和销毁不会消耗太多资源,成为每次客户请求分配的Session实例,Session有一个缓存,被称为Hibernate的一级缓存,每个Session实例都有自己的缓存。
(4)开始事务
Transaction代表一次原子操作,它具有数据库事务的概念,所有持久化都应该在事务管理器下进行,即使是只读操作。如果没有开启事务,那么每一个Session的操作,都相当于一个独立的事务。
(5)执行数据库的操作
(6)事务提交和回滚
(7)关闭资源
5、简单的CRUD操作
save
update
saveOrUpdate
delete
load
get
目录
Person.java
package com.hliedu.domain;
/*POJO类,javabean,Domain,Enity*/
public class Person {
private Integer pid;
private String pname;
private Integer age;
public Integer getPid() {
return pid;
}
public void setPid(Integer pid) {
this.pid = pid;
}
public String getPname() {
return pname;
}
public void setPname(String pname) {
this.pname = pname;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
// TODO Auto-generated method stub
return pid+" "+pname+":"+age;
}
}
HibernateTest1.java测试类
package com.hliedu.domain;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
public class HibernateTest1 {
// 新增和修改
@Test
public void save() {
Person person = new Person();
person.setPname("张三");
person.setAge(18);
Session session = HibernateUtil.getSessionFactory().openSession();
Transaction transaction = session.beginTransaction();
session.save(person);
transaction.commit();
session.close();
}
@Test
public void update() {
Person person = new Person();
person.setPid(1);
// 更新时没有传入ID org.hibernate.TransientObjectException: The given object has a null
// identifier: com.hliedu.domain.Person
// 更新时没有传入对应的ID Row was updated or deleted by another transaction (or
// unsaved-value mapping was incorrect) : [com.hliedu.domain.Person#4]
person.setPname("李四");
person.setAge(30);
Session session = HibernateUtil.getSessionFactory().openSession();
Transaction transaction = session.beginTransaction();
session.update(person);
transaction.commit();
session.close();
}
@Test
public void saveOrUpdate() {
Person person = new Person();
person.setPid(1);
person.setPname("王五");
person.setAge(24);
Session session = HibernateUtil.getSessionFactory().openSession();
Transaction transaction = session.beginTransaction();
session.saveOrUpdate(person);
transaction.commit();
session.close();
}
// 删除
@Test
public void delete() {
Person person = new Person();
person.setPid(1);
// 删除时没有匹配到删除的数据 No tests found matching Method
// delete(com.hliedu.domain.HibernateTest) from
// org.junit.vintage.engine.descriptor.RunnerRequest@527740a2
Session session = HibernateUtil.getSessionFactory().openSession();
Transaction transaction = session.beginTransaction();
session.delete(person);
transaction.commit();
session.close();
}
// 查询
// 1、 别名查询
@Test
public void get() {
Session session = HibernateUtil.getSessionFactory().openSession();
Transaction transaction = session.beginTransaction();
Person person = session.get(Person.class, 1);
// 当没有匹配到数据 返回null
System.out.println(person);
transaction.commit();
session.close();
}
// 2
@Test
public void load() {
Session session = HibernateUtil.getSessionFactory().openSession();
Transaction transaction = session.beginTransaction();
Person person = session.load(Person.class, 1);
// 当没有匹配到数据 No row with the given identifier exists:
// [com.hliedu.domain.Person#2]
System.out.println(person);
transaction.commit();
session.close();
}
}
Person.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 2020-3-28 22:01:30 by Hibernate Tools 3.5.0.Final 对象关系映射文件,映射数据库和实体类之间的关系 -->
<hibernate-mapping default-lazy="false">
<class name="com.hliedu.domain.Person" table="PERSON">
<!-- 主键 -->
<id name="pid" type="java.lang.Integer">
<column name="PID" />
<generator class="native" />
<!-- 将ID生成规则交由数据库完成 -->
</id>
<property generated="never" lazy="false" name="pname"
type="java.lang.String">
<column name="PNAME" />
</property>
<property generated="never" lazy="false" name="age"
type="java.lang.Integer">
<column name="AGE" />
</property>
</class>
</hibernate-mapping>
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 name="">
<!-- 数据库连接配置 -->
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/hibernate5</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">admin</property>
<!-- 数据库方言 ,limit是mysql独有的,top是sqlserve独有的 -->
<property name="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property>
<!-- 附属配置,ddl是数据库定义语言 -->
<property name="hibernate.show_sql">true</property>
<property name="hibernate.format_sql">true</property>
<property name="hibernate.hbm2ddl.auto">update</property>
<mapping resource="com/hliedu/domain/Person.hbm.xml" />
</session-factory>
</hibernate-configuration>
6、测试类代码优化
(1)简单封装(提高复用率)
HibernateUtil.java
(包装Configuration配置和SessionFactory工程类)
package com.hliedu.domain;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
/*Hibernate调用程序*/
public class HibernateUtil {
// Junit测试,单元测试
private static Configuration cfg = null;
private static SessionFactory sessionFactory = null;
static {
// 创建Configuration实例,读取默认hibernate配置文件
cfg = new Configuration().configure();
// 通过cfg创建一个SessionFactory工厂类,维护着2级缓存,不需要关闭
sessionFactory = cfg.buildSessionFactory();
}
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
}
HibernateTest2.java
(内含多个错误异常说明)
顺序:
@Before
测试方法
@After
package com.hliedu.domain;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
public class HibernateTest2 {
Configuration cfg = null;
SessionFactory sessionFactory = null;
Session session = null;
Transaction transaction = null;
@Before
public void init() {
// TODO Auto-generated method stub
System.out.println("初始化加载");
cfg = new Configuration().configure();
sessionFactory = cfg.buildSessionFactory();
session = sessionFactory.openSession();
transaction = session.beginTransaction();
}
@After
public void after() {// 销毁
// TODO Auto-generated method stub
transaction.commit();
session.close();
sessionFactory.close();
}
// 新增和修改
@Test
public void save() {
Person person = new Person();
person.setPname("张三");
person.setAge(18);
session.save(person);
}
@Test
public void update() {
Person person = new Person();
person.setPid(1);
// 更新时没有传入ID org.hibernate.TransientObjectException: The given object has a null
// identifier: com.hliedu.domain.Person
// 更新时没有传入对应的ID Row was updated or deleted by another transaction (or
// unsaved-value mapping was incorrect) : [com.hliedu.domain.Person#4]
person.setPname("李四");
person.setAge(30);
session.update(person);
}
@Test
public void saveOrUpdate() {
Person person = new Person();
person.setPid(1);
person.setPname("王五");
person.setAge(24);
session.saveOrUpdate(person);
}
// 删除
@Test
public void delete() {
Person person = new Person();
person.setPid(1);
// 删除时没有匹配到删除的数据 No tests found matching Method
// delete(com.hliedu.domain.HibernateTest) from
// org.junit.vintage.engine.descriptor.RunnerRequest@527740a2
session.delete(person);
}
// 查询
// 1、 别名查询
@Test
public void get() {
Person person = session.get(Person.class, 1);
// 当没有匹配到数据 返回null
System.out.println(person);
}
// 2
@Test
public void load() {
Person person = session.load(Person.class, 1);
// 当没有匹配到数据 No row with the given identifier exists:
// [com.hliedu.domain.Person#2]
System.out.println(person);
}
}
基础加深
一、Session一级缓存操作
DefaultLoadEventListener 444行从缓存中取出已经存在的对象id
由get()方法效果可以得出以下结论:
Session中存在缓存,这种缓存我们称为一级缓存,存在哪个Session的生命周期中,缓存里的对象,不会随着引用变量消失而清空,只要缓存中存在该对象,在查询的时候Hibernate优先从缓存中取出数据,而不会再次访问数据库,只有缓存中不存在的数据,才会发起SQL语句查询数据库,所以缓存极大减少了访问数据库的频率。
Session缓存的作用:
1)减少访问数据库的频率
2)保证缓存中的数据与数据库保持同步,当缓存的对象改变后,session不会立即执行sql,而是将多个sql语句合并成一条sql进行执行,提高效率。
如果对于一个属性修改了多次,其实Hibernate的session缓存并不是执行多个update语句,而是以最后一个更新为准发送一条更新的sql。
二、缓存相关方法
Hibernate提供了一下2个方法来保证缓存中的数据与数据库记录保持一致。
1、flush
强制让数据库中的记录与session中的对象数据保持一致,不一致则发起update这条sql修改数据让其一致。
注意:
事务的commit()中已经自动调用了flush方法,所以若存在commit()可以省略flush方法,若缓存数据发生变化,flush()会执行update语句,但是最终不会提交事务,提交事务意味着持久化到数据库。
2、refresh
强制发出select语句,保证session缓存中的数据与数据库的记录是一致的,如果发现不一致它会修改缓存中的对象让其一致。
clear
清理session缓存,会重新发起sql语句。
三、sanHibernate对象状态
1、状态分类
Hibernate为了管理持久化类:将持久化类分成了三个状态。
瞬时态:Transient Object,没有持久化标识OID,没有纳入到Session对象的管理。
持久态:Persient Object
有持久化标识OID,已经纳入到Session对象的管理。
脱管态(游离态):Detached Object
有持久化标识OID,没有纳入Session对象的管理。
2、详细描述
瞬时态:对象由new操作符创建,且尚未与Hibernate Session关联的对象被认为处于瞬态,瞬态对象不会被持久化到数据库中,也不会被赋予持久化标识,如果程序失去了瞬态对象的引用,瞬态对象将被垃圾回收机制销毁,使用Hibernate Session可以将其变为持久态状态。
持久态:持久化实例在数据库中有对应的记录,并拥有一个持久化标识(identifer)。持久化的实例可以是刚刚保存的,也可以是被加载的,无论哪一种,持久化对象都必须与指定的Hibernate Session关联。Hibernate会检测到处持久化状态对象的改动,在当前操作完成时将对象数据写回数据库。
脱管态:某个实例曾经处于持久化状态,但随着与之关联Session被关闭,该对象就变成了脱管状态,脱管状态的引用依然有效,对象可继续被修改。如果重新让脱管对象与某个Session关联,这个脱管对象会重新转换为持久化对象。
3、三种形态代码解析
1)对象瞬时态解析
(1)
(2)
(3)
(4)
2)对象持久态解析
(1)
(2)
3)游离态解析
(1)
(2)
4、Session中的核心方法
概念1
代码解析:
概念2
代码解析:
save()
persist()
update()
概念3
代码解析
saveOrUpdate()
delete()
evict()
dowork()(代码漏了@Test)
四、Hibernate连接池C3P0配置
C3P0支持的jar包:(解压Hibernate jar包后)
hibernate-release-5.3.16.Final\hibernate-release-5.3.16.Final\lib\optional\c3p0
配置过程:
测试配置是否成功:
成功
配置文档: