1.Hibernate简述
Hibernate是一个对象关系映射框架,对JDBC进行轻量级的对象封装。其将POJO与数据库建立yin映射关系,是一个全自动的orm框架。Hibernate应用再任何使用JDBC的场合,既可以在java的客户端程序使用,也可以在Servlet/Jsp的web应用中使用。
1.1 orm框架
orm框架全称为Object-relative-mapping,即将对象和关系型的数据库通过映射的配置文件关联起来,则可达到操作该对象来操作数据库的目的( 利用对象编程来操作数据库)。
(1) O:面向对象领域的Object (JavaBean对象)
(2) R: 关系数据库领域的Relational (表的结构)
(3) M: 映射Mapping(Xml的配置)
1.2 Hibernate优点
(1)对JDBC访问数据库的代码做了封装,大大简化了数据访问层繁琐的重复性代码
(2)轻量级的框架,支持大多数关系型数据库。
1.3 Hibernate的常用jar包
常用jar包 | |
---|---|
hibernate-jpa-2.1-api-1.0.0.Final.jar | Hibernate的标准jar包 |
hibernate-core-5.2.9.Final.jar | Hibernate的核心jar包 |
hibernate-commons-annotations-5.0.1.Final.jar | Hibernate的注解jar包 |
2. Hibernate的配置
2.1 Hibernate的配置文件
Hibernate的映射配置文件:
代码如下:
<?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="当前类的全路径" table="对应的表名">
<!--配置id-->
<id name="JavaBean的属性" column="表结构的字段">
<!--主键的生成策略,native表示采取本地的自增策略-->
<generator class="native"/>
</id>
<property name="JavaBean的属性" colume="表结构字段" length="字段的数据长度,若不写则为默认" type="数据类型,例如java.lang.String。可不写">
</property>
<property name="JavaBean的属性" colume="表结构字段">
</property>
...
</class>
</hibernate-mapping>
Hibernate的核心配置文件:
?xml version="1.0" encoding="GBK"?>
<!-- 指定Hibernate配置文件的DTD信息 -->
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<!--配置SessionFactory标签,一个数据库只对应一个SessionFactory>
<session-factory>
<!--配置Mysql数据库-->
<!-- 指定连接数据库所用的驱动 -->
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<!-- 指定连接数据库的url,hibernate连接的数据库名 -->
<property name="connection.url">jdbc:mysql://localhost/数据库名</property>
<!-- 指定连接数据库的用户名 -->
<property name="connection.username">数据库名</property>
<!-- 指定连接数据库的密码 -->
<property name="connection.password">数据库密码</property>
<!-- 数据库Mysql方言 -->
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
<!--可选的配置-->
<!--控制台显示sql语句-->
<property name="hibernate.show_sql">true/false</property>
<!--控制台显示格式化后的sql语句-->
<property name="hibernate.format_sql">true/false</property>
<!--生成数据库的表结构,主要作为测试功能-->
<property name="hibernate.hbm2ddl.auto">create</property>
<!---->
<!-- 导入映射配置文件 注意路径 “/” -->
<mapping resource="包路径/mapper配置文件名">
</session-factory>
</hibernate-configuration>
2.2 Hibernate核心类和接口简述
Hibernate的API一共有6个,分别为:Session、SessionFactory、Transaction、Query、Criteria和Configuration。通过这些接口,可以对持久化对象进行存取、事务控制。
2.2.1SessionFactory
SessionFactory接口负责初始化Hibernate。它充当数据存储源的代理,并负责创建Session对象。这里用到了工厂模式。其里面缓存了增删改查的sql语句。
注:
(1)一个项目通常只需要一个SessionFactory就够,当需要操作多个数据库时,可以为每个数据库指定一个SessionFactory。
(2)SessionFactory是线程安全的
SessionFactory的内部组成图
SessionFactory特点
(1) 由Configuration通过加载配置文件创建该对象。
(2) SessionFactory对象中保存了当前的数据库配置信息和所有映射关系以及预定义的SQL语句。同时,SessionFactory还负责维护Hibernate的二级缓存。
(3)一个SessionFactory实例对应一个数据库,应用从该对象中获得Session实例。
(4)SessionFactory是线程安全的,意味着它的一个实例可以被应用的多个线程共享。
(5) SessionFactory是重量级的,意味着不能随意创建或销毁它的实例。如果只访问一个数据库,只需要创建一个SessionFactory实例,且在应用初始化的时候完成。
2.2.2 Session
Session接口负责执行被持久化对象的CRUD操作(CRUD即为增删改查SQL语句)。但需要注意的是Session对象是非线程安全的。同时,Hibernate的session不同于JSP应用中的HttpSession。HttpSession对象称为用户session。
简而言之,Hibernate的Session对数据库进行增删改查的。Session共享一个SessionFactory。因为Session是线程不安全的,最好一次请求一个Session。
常用方法 | 用法 |
---|---|
save(obj) | 插入数据 |
delete(obj) | 删除数据 |
get(Class,id) | 通过主键来查询,查询对应的一条数据。第一个参数为JeanBean的class对象,第二个参数为主键值 |
update(obj) | 更新数据 |
saveOrUpdate(obj) | 保存或者修改(如果没有数据,保存数据。如果有,修改数据) |
createQuery() | HQL语句的查询的方式 |
注:
除了查询操作,增删改都需要加事务。在修改和删除时,先对其进行查询再修改或删除。
2.2.3 Transaction接口
Transaction 接口是对实际事务实现的一个抽象,这些实现包括JDBC的事务、JTA 中的UserTransaction、甚至可以是CORBA 事务。
常用方法 | 用法 |
---|---|
commit() | 提交事务 |
rollback() | 回滚事务 |
Transaction特点
(1)Hibernate框架默认情况下事务不自动提交.需要手动提交事务
(2)如果没有开启事务,那么每个Session的操作,都相当于一个独立的事务
2.2.4 底层实现
// 先加载配置文件
Configuration config = new Configuration();
// 默认加载src目录下的配置文件
config.configure();
// 创建SessionFactory对象
SessionFactory factory = config.buildSessionFactory();
// 创建session对象
Session session = factory.openSession();
// 开启事务
Transaction tr = session.beginTransaction();
// 编写保存代码
Customer c = new Customer();
// 保存客户
session.save(c);
// 提交事务
tr.commit();
// 释放资源
session.close();
factory.close();
3. Hibernate的持久化
3.1 持久化编写规则
- 提供一个无参数 public访问控制符的构造器。原因是:底层需要进行反射。
- 提供一个标识属性,映射数据表主键字段。唯一标识OID。数据库中通过主键,Java对象通过地址确定对象;持久化类通过唯一标识OID确定记录。
- 所有属性提供public访问控制符的 set或者get 方法
- 标识属性应尽量使用基本数据类型的包装类型
3.2 自然主键与代理主键的区别
自然主键
对象本身的一个属性,创建一个人员表,每个人都有一个身份证号(唯一的)使用身份证号作为表的主键.。(开发中不会使用这种方式)
代理主键
不是对象本身的一个属性.创建一个人员表,为每个人员单独创建一个字段.用这个字段作为主键.代理主键.(开发中推荐使用这种方式)
3.3 主键的生成策略
increment
适用于short,int,long作为主键.不是使用的数据库自动增长机制.
注: Hibernate中提供的一种增长机制。不建议使用,并发时容易出问题。
底层原理是:先进行查询 :select max(id) from user,再进行插入:获得最大值+1作为新的记录的主键。
identity
适用于short,int,long作为主键。但是这个必须使用在有自动增长数据库中,采用的是数据库底层的自动增长机制。
注:底层使用的是数据库的自动增长(auto_increment).像Oracle数据库没有自动增长。
sequence
适用于short,int,long作为主键.底层使用的是序列的增长方式。
注:Oracle数据库底层没有自动增长,想自动增长需要使用序列。
uuid
适用于char,varchar类型的作为主键。
注:使用随机的字符串作为主键
native
本地策略.根据底层的数据库不同,自动选择适用于该种数据库的生成策略.(short,int,long)
注:如果底层使用的MySQL数据库:相当于identity;如果底层使用Oracle数据库:相当于sequence。
assigned
主键的生成不用Hibernate管理了.必须手动设置主键。
4持久化对象
4.1 状态
Hibernate为了管理持久化类:将持久化类分成了三个状态。
(1) 瞬时态:Transient Object
(2) 持久态:Persistent Object
(3) 脱管态:Detached Object
状态 | 有无持久化标识 | 有无被session管理 |
---|---|---|
瞬时态 | 无 | 无 |
持久态 | 有 | 有 |
脱管态 | 有 | 无 |
4.2 状态转换
注:持久态的对象,有自动更新数据库的能力。
原因:Session的快照机制。
4.3 Session的一级缓存
Session接口中,有一系列的java的集合,这些java集合构成了Session级别的缓存(一级缓存).将对象存入到一级缓存中,session没有结束生命周期,那么对象在session中存放着。
注:内存中包含Session实例 --> Session的缓存(一些集合) --> 集合中包含的是缓存对象。
缓存内存储的是对象的引用。
4.4 绑定本地Session
JavaWEB的事务的时候,需要在业务层使用Connection来开启事务。一种是通过参数的方式传递下去,另一种是把Connection绑定到ThreadLocal对象中。
Hibernate框架中,使用session对象开启事务,所以需要来传递session对象,框架提供了ThreadLocal的方式。
4.4.1 绑定本地Session的配置
在业务层开事务步骤如下:
1.需要在hibernate.xml的配置文件中提供配置
<!--开启绑定本地的session-->
<property name="hibernate.current_session_context_class">thread</property>
2.使用SessionFactory的getCurrentSession()方法,获取当前的Session对象。并且该Session对象不用手动关闭,线程结束了,会自动关闭。
public static Session getCurrentSession(){
return factory.getCurrentSession();
}
注:想使用getCurrentSession()方法,必须要先配置才能使用。
4.4.2 业务逻辑层+事务的原因
若事务注解@Transactional加在dao层,那么只要与数据库做增删改,就要提交一次事务,事务的特性就发挥不出来.尤其是事务的一致性,当出现并发问题是,用户从数据库查到的数据都会有所偏差。
将事务设置在业务逻辑上,只要一个业务逻辑出错或异常,则该事务就会回滚(所有的业务都会回到最初始的状态)。同时,一个事务则可参与多个业务的提交。
5.Hibernate框架查询方式
HQL语句
框架Hibernate独有的操作数据库数据的语言。
格式:
1.所有数据查询
session.createQuery("from Users ", Users.class).list();
2.条件查询(常用的)
session.createQuery("from Users where username=:username", Users.class).setParameter("username", username);
3.条件查询
Query query = session.createQuery("from Customer where name = ?");
query.setString(0, "李健");
List<Customer> list = query.list();
System.out.println(list);
注:
(1)第一个参数为HQL语句,第二参数为JavaBean的class对象
Criteria查询接口(条件查询)
1.查询所有记录
Criteria criteria = session.createCriteria(Users.class);
List<Users> list = criteria.list();
System.out.println(list);
2.条件查询
Criteria criteria = session.createCriteria(Customer.class);
criteria.add(Restrictions.eq("name", "李健"));
List<Customer> list = criteria.list();
System.out.println(list);
3.条件查询
Criteria criteria = session.createCriteria(Customer.class);
criteria.add(Restrictions.eq("name", "李健"));
criteria.add(Restrictions.eq("age", 38));
List<Customer> list = criteria.list();
System.out.println(list);
5.配置一对多关系
多方的配置
<set name="多方的数据库表名">
<key column="多方的外键"/>
<one-to-many class="多方的JavaBean的全路径名"/>
</set>
一方的配置
<many-to-one name="一方的数据库表" class="一方对应的JavaBean的全路径名" column="多方的外键名"/>