自学了Hibernate之后印象不深,自我总结好好琢磨琢磨。
1.Hibernate框架简述
1.1 ORM框架
Hibernate是一个数据持久化层的ORM框架.
Object:对象,java对象,此处特指JavaBean
Relational:关系,二维表,数据库中的表。
映射|映射元数据:对象中属性,与表的字段,存在对应关系。
1.2Hibernate的体系结构
1.2.1Hibernate的核心组件
在基于MVC设计模式的JAVA WEB应用中,Hibernate可以作为模型层/数据访问层。它通过配置文件(hibernate.properties或hibernate.cfg.xml)和映射文件(*.hbm.xml)把JAVA对象或PO(Persistent Object,持久化对象)映射到数据库中的数据库,然后通过操作PO,对数据表中的数据进行增,删,改,查等操作。
a ) PO:persistent object ,用于与数据库交互数据。–dao层 (JavaBean + hbm )
b ) BO:Business object 业务数据对象。–service层
c ) VO:Value Object 值对象。–web层
1.2.2hibernate 核心配置文件种类
a) hibernate.cfg.xml=
通常使用xml配置文件,可以配置内容更丰富。(经常用)
b) hibernate.properties 用于配置key/value 形式的内容,key不能重复的。配置有很多的局限性。(一般不用)
c)xxx.hbm.xml
映射文件由节点定义映射内容并指定所对应的JavaBean的位置(也可以不在该节点中用package属性指定对应的JavaBean位置,而在该节点下的class节点中的name属性中指定), 是Hibernate与数据库进行持久化的桥梁
除配置文件,映射文件和持久化类外,Hibernate的核心组件包括以下几部分:
a)Configuration
类:用来读取Hibernate配置文件,并生成SessionFactory对象。
b)SessionFactory
接口:产生Session实例工厂。
c)Session
接口:用来操作PO。它有get(),load(),save(),update()和delete()等方法用来对PO进行加载,保存,更新及删除等操作。它是Hibernate的核心接口。
d)Query
接口:用来对PO进行查询操。它可以从Session的createQuery()方法生成。
e)Transaction
接口:用来管理Hibernate事务,它主要方法有commit()和rollback(),可以从Session的beginTrancation()方法生成。
1.2.3Persistent Object
持久化对象可以是普通的Javabeans,惟一特殊的是它们与(仅一个)Session相关联。JavaBeans在Hibernate中存在三种状态:
- 临时状态(transient):当一个JavaBean对象在内存中孤立存在,不与数据库中的数据有任何关联关系时,那么这个JavaBeans对象就称为临时对象(Transient
Object)。 - 持久化状态(persistent):当一个JavaBean对象与一个Session相关联时,就变成持久化对象(Persistent
Object) - 脱管状态(或者叫游离状态(detached):在这个Session被关闭的同时,这个对象也会脱离持久化状态,就变成脱管状态(Detached Object),可以被应用程序的任何层自由使用,例如可以做与表示层打交道的数据舆对象(Data Transfer Object)。
1.2.4Hibernate的运行过程
Hibernate的运行过程如下:
应用程序先调用Configration类,该类读取Hibernate的配置文件及映射文件中的信息,并用这些信息生成一个SessionFactory对象。
然后从SessionFactory对象生成一个Session对象,并用Session对象生成Transaction对象;可通过Session对象的get(),load(),save(),update(),delete()和saveOrUpdate()等方法对PO进行加载,保存,更新,删除等操作;在查询的情况下,可通过Session对象生成一个Query对象,然后利用Query对象执行查询操作;如果没有异常,Transaction对象将提交这些操作结果到数据库中
2.入门案例
2.1编写流程
1. 创建数据库和表
2. 导入jar包
3. 编写核心配置文件(hibernate.cfg.xml)–> 配置获得链接等参数
4. 编写映射文件 hibernate mapping(*.hbm.xml)
5 使用api测试
2.2创建数据库和表
create database hibernate;
use hibernate;
create table t_user(
id int auto_increment primary key,
username varchar(50),
password varchar(30)
);
2.3导入jar包
2.4. 编写JavaBean+映射文件
a)文件位置:javabean同包
b)文件名称:javabean同名
c)扩展名:*.hbm.xm l
User
public class User {
private int id;
private String name;
private String password;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
User.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.User" table="t_user">
<id name="id" column="id">
<generator class="native"></generator>
</id>
<property name="name" column="name"></property>
<property name="password" column="password"></property>
</class>
</hibernate-mapping>
2.5 编写核心配置文件
a)位置:类路径(classpath、src)–>WEB-INF/classes
b)名称:hibernate.cfg.xml
c)内容:添加约束
<?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.jdbc.Driver</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">tracydzf</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/hibernate</property>
<property name="show_sql">true</property>
<property name="format_sql">true</property>
<property name="hbm2ddl.auto">update</property>
<property name="hibernate.connection.autocommit">true</property>
<property name="hibernate.current_session_context_class">thread</property>
<mapping resource="com/User.hbm.xml"/>
</session-factory>
</hibernate-configuration>
2.6测试
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.classic.Session;
import org.junit.Test;
public class test1 {
@Test
public void fun() {
// 1读取配置文件
Configuration conf = new Configuration().configure();
// 2根据配置创建factory
SessionFactory sf = conf.buildSessionFactory();
// 3获得session
Session session = sf.openSession();
// 4操作数据库
User u = new User();
u.setName("tom");
u.setPassword("1234");
session.save(u);
// 5关闭资源
session.close();
sf.close();
}
}
3.API详解
3.1 Configuration 配置对象
- hibernate.cfg.xml 通常使用xml配置文件,可以配置内容更丰富。
- hibernate.properties 用于配置key/value 形式的内容,key不能重复的。配置有很多的局限性。一般不用。
3.1.1 加载核心配置文件
加载hibernate.properties时:Configuration configuration = new Configuration();
加载hibernate.cfg.xml时:Configuration configuration = new Configuration().configure();
3.1.2 加载映射文件(不过,一般映射文件都配置在核心配置文件中,该方法用少)
// 手动加载指定的配置文件
config.addResource("com/itheima/a_hello/User.hbm.xml");
// 手动加载指定类,对应的映射文件 User--> User.hbm.xml
config.addClass(User.class);
3.1.3常见异常
- 开发中:将hbm.xml映射 配置 hibernate.cfg.xml
- 学习中:可以使用 addClass 或 addResource
3.2 SessionFactory工厂
- SessionFactory负责管理Session,管理连接池,管理Hibernate二级缓存。是一个重量级的, 线程安全的对象.
- SessionFactory 相当于java web连接池,用于管理所有session
- 获得方式:
config.buildSessionFactory();
- sessionFactory hibernate缓存配置信息 (数据库配置信息、映射文件,预定义HQL语句 等)
- SessionFactory线程安全,可以是成员变量,多个线程同时访问时,不会出现线程并发访问问题。
//打开一个新的会话 session
factory.openSession();
//获得当前线程中绑定的会话session
factory.getCurrentSession();
hibernate支持,将创建的session绑定到本地线程中,底层使用ThreadLocal,在程序之间共享session。
- 1.必须在hibernate.cfg.xml 配置
<!-- 2 与本地线程绑定 -->
<property name="hibernate.current_session_context_class">thread</property>
- 2.如果提交或回滚事务,底层将自动关闭session
3.3 Session 会话
Session是Hibernate程序与数据库之间的桥梁。完成CRUD的操作。Session是一个单线程的对象,内部维护了Hibernate的一级缓存。
- hibernate的一级缓存—>session级别的缓存
一级缓存是session级别的缓存, 同session的声明周期一直. 一级缓存实际上是由session中的一组集合构成的.
一级缓存的主要作用: 减少对数据库的访问次数
执行原理: 在session中执行查询操作时,首先会从缓存中获取结果, 如果缓存中没有, 则去数据库中查询,
并将查询结果往缓存中存放一份; 如果缓存中有, 则直接从缓存中获取.一级缓存快照区: 在存放在缓存中的数据会在session一级缓存的快照区存放一份, 当数据发生变更时, 缓存中的数据会被修改,而快照区的数据还是原来的数据, 在事务提交时, 会对比一级缓存和快照区, 如果数据不一致, 则会发送sql语句更改数据库中数据;如果数据一致, 则不对数据库进行更新操作. 因此, 对于持久态的对象, 即使没有显示的添加update语句, 如果数据发生变化,在提交事务时, 会自动更新数据库
session保存一个对象:
session.save(entity);
session修改对象:
session.update(entity);
session删除对象
session.delete(entity);
session查询对象:
session.get()和session.load();
获得Query对象:createQuery("hql")
获得Criteria对象 :createCriteria(Class)
get()方法和load()方法的区别:
相同点:
- 都是通过id进行查询
不同点:
加载机制不同. get方法采用的是立即加载,执行到代码的时候,立即发送SQL语句进行查询;
而load方法采用的延迟加载(Lazy)机制, 执行该代码的 时候不会马上发送SQL语句,只有真正使用该对象的时候才会发送SQL语句查询查询结果不同. get方法查询得到的是对象本生, 而load方法查询返回的一个代理对象;
查询没有找到时的处理应答不同, get方法返回的是null; 而load方法则会抛出异常ObjectNotFoundException;
3.4 Transaction 事务
- 开启事务
beginTransaction()
- 获得事务
getTransaction()
- 提交事务:
commit()
- 回滚事务:
rollback()
try{
//开启
//session操作
//提交
} catch(e){
//回滚
}
//扩展:不需要手动的管理事务,之后所有的事务管理都交予spring。
3.5 Query 对象
hibernate执行hql语句
hql语句:hibernate提供面向对象查询语句,使用对象(类)和属性进行查询。区分大小写。
获得
session.createQuery("hql")
方法:
-list()
查询所有
-uniqueResult()
获得一个结果。如果没有查询到返回null,如果查询多条抛异常。-
setFirstResult(int)
分页,开始索引数startIndex
-setMaxResults(int)
分页,每页显示个数 pageSize
4.Hibernate中HibernateUtil工具类
首先我们需要知道为什么咱们要创建Hibernate工具类?
一些固定而且经常使用的步骤我们期望做成一个工具类,以后再需要重复步骤时咱们仅需要引用此工具类就可以,从而避免了一直创建重复代码。比如加载数据库的驱动等,这里Hibernate中我们每个主程序都需要加载hibernate.cfg.xml文件、创建SessionFactory对象、创建Session对象、关闭session。这些都是固定化的步骤,因此我们将它们写在工具类HibernateUtil中,以后咱们直接引用此文件创建各对象即可,大大减少了代码量,提高了代码复用性。
最佳版本:
/**
* 该工具类提供了一个属性:SessionFactory sessionFactory
* 并创建了sessionFactory 将它设置成static 这样其他程序就可以直接通过此工具类引用
* 提供了二个方法:
* 1:通过线程创建Session-->currentSession()
* 2:关闭Session-->closeSession()
* 需要在主类中手动关闭sessionFactory
*/
public class HibernateUtil
{
public static final SessionFactory sessionFactory;
//创建sessionFactory
static
{
try
{
// 采用默认的hibernate.cfg.xml来启动一个Configuration的实例
Configuration cfg = new Configuration()
.configure();
// 以Configuration实例来创建SessionFactory实例
ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder()
.applySettings(cfg.getProperties()).build();
sessionFactory = cfg.buildSessionFactory(serviceRegistry);
}
catch (Throwable ex)
{
System.err.println("Initial SessionFactory creation failed." + ex);
throw new ExceptionInInitializerError(ex);
}
}
// ThreadLocal可以隔离多个线程的数据共享,因此不再需要对线程同步
public static final ThreadLocal<Session> session
= new ThreadLocal<Session>();
//创建Session
public static Session currentSession()
throws HibernateException
{
//通过线程对象.get()方法安全创建Session
Session s = session.get();
// 如果该线程还没有Session,则创建一个新的Session
if (s == null)
{
s = sessionFactory.openSession();
// 将获得的Session变量存储在ThreadLocal变量session里
session.set(s);
}
return s;
}
//关闭Session
public static void closeSession()
throws HibernateException
{
Session s = session.get();
if (s != null)
s.close();
session.set(null);
}
}
我的版本
public class H3Utils {
// 会话工厂,整个程序只有一份。
private static SessionFactory factory;
static{
//1 加载配置
Configuration config = new Configuration().configure();
//2 获得工厂
factory = config.buildSessionFactory();
//3 关闭虚拟机时,释放SessionFactory
Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
@Override
public void run() {
System.out.println("虚拟机关闭!释放资源");
sf.close();
}
}));
}
/**
* 获得一个新的session
* @return
*/
public static Session openSession(){
return factory.openSession();
}
/**
* 获得当前线程中绑定session
* * 注意:必须配置
* @return
*/
public static Session getCurrentSession(){
return factory.getCurrentSession();
}
}
5.核心配置文件详解
Hibernate核心配置文件hibernate.cfg.xml主要由以下四部分组成:
- (1)数据库连接信息,包括驱动程序类名、连接URL、用户名和密码。
- (2)Hibernate相关特性,包括dialect(方言)、show_sql(输出SQL语句到控制台)、format_sql(格式化SQL语句)
- (3)连接池相关信息。
- (4)实体类映射文件,实体类与数据库表之间的逻辑映射
<!-- SessionFactory,相当于之前学习连接池配置 -->
<session-factory>
<!-- 1 基本4项 -->
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql:///hibernate</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">tracydzf</property>
<!-- 2 与本地线程绑定 -->
<property name="hibernate.current_session_context_class">thread</property>
<!-- 3 方言:为不同的数据库,不同的版本,生成sql语句(DQL查询语句)提供依据
* mysql 字符串 varchar
* orcale 字符串 varchar2
-->
<property name="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</property>
<!-- 4 sql语句 -->
<!-- 显示sql语句 -->
<property name="hibernate.show_sql">true</property>
<property name="hibernate.format_sql">true</property>
<!-- 5 自动创建表(了解) ,学习中使用,开发不使用的。
* 开发中DBA 先创建表,之后根据表生产 PO类
* 取值:
update:【】
如果表不存在,将创建表。
如果表已经存在,通过hbm映射文件更新表(添加)。(映射文件必须是数据库对应)
表中的列可以多,不负责删除。
create :如果表存在,先删除,再创建。程序结束时,之前创建的表不删除。【】
create-drop:与create几乎一样。如果factory.close()执行,将在JVM关闭同时,将创建的表删除了。(测试)
validate:校验 hbm映射文件 和 表的列是否对应,如果对应正常执行,如果不对应抛出异常。(测试)
-->
<property name="hibernate.hbm2ddl.auto">update</property>
<!-- 6 java web 6.0 存放一个问题
* BeanFactory 空指针异常
异常提示:org.hibernate.HibernateException: Unable to get the default Bean Validation factory
* 解决方案:取消bean校验
-->
<property name="javax.persistence.validation.mode">none</property>
<!-- 7连接池的配置 -->
<property name="hibernate.connection.provider_class">
org.hibernate.service.jdbc.connections.internal.C3P0ConnectionProvider
</property>
<!-- 8C3P0随机准备好的最少的JDBC连接数量 -->
<property name="hibernate.c3p0.min_size">5</property>
<!-- 9连接池的最大JDBC连接数量 -->
<property name="hibernate.c3p0.max_size">20</property>
<!--10 配置超时周期,在他之后,休闲连接将从连接池中移除 -->
<property name="hibernate.c3p0.timeout">300</property>
<!-- 11注册ORM添加映射文件
<mapping >添加映射文件
resource 设置 xml配置文件 (addResource(xml))
class 配置类 (addClass(User.class)) 配置的是全限定类名
-->
<mapping resource="com/itheima/a_hello/User.hbm.xml"/>
</session-factory>
参考:
https://www.cnblogs.com/rodge-run/archive/2017/02/19/6415594.html
https://www.jianshu.com/p/50964e92c5fb
https://blog.csdn.net/vipmao/article/details/51340525
http://www.cnblogs.com/zhangzongle/p/5738786.html