您的位置:首页 > 其它

hibernate--初识

2017-11-22 00:00 204 查看
摘要: 自用总结

配置文件的详解
映射文件
名称:自定义 格式为xml 建议: 类名.hbm.xml
路径:自定义 建议放在domain下
导入约束
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
内容:
类和表的映射关系
class标签
name属性:类的全限定名
table属性:表名(若表名和类名一样的话,table属性可以省略不写)
属性和主键字段的映射关系
id标签
name属性:属性名称
column属性:主键字段名称(若列名和属性名一致的话,column属性可以省略不写)
主键生成策略:目前使用native
属性和普通字段的映射关系
property标签
name属性:
column属性:
/////////////////////////////////////////////////
核心配置文件
名称: 建议使用 hibernate.cfg.xml 也可以使用hibernate.properties(不建议)
路径: 建议放在 src目录下
导入约束:
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
配置内容:
数据库连接4个基本信息 : 参考\project\etc\hibernate.properties property标签

hibernate的属性配置 方言,是否显示sql,是否格式化sql... property标签
<!--
是否由hibernate来生成表的定义语句及如何生成
常见值:
update:使用表的使用,先判断表是否存在,若不存在自动创建表.
若存在,
再判断配置文件和表是否对应上,
若对应不上,更新表结构
若对应上,直接使用表

了解值:
create:每次使用表的时候,都重新创建一张表,若之前表存在则删除
create-drop:每次使用表的时候,都重新创建一张表,若之前表存在则删除,当这次执行彻底完成的时候,删除此表.
validate:每次使用表的时候,需要校验表和映射文件中的配置是否一样,若一致则使用,若不一样呢则抛异常
-->
<property name="hibernate.hbm2ddl.auto">validate</property>
映射文件的路径 mapping标签
<mapping resource="cn/itcast/domain/Customer.hbm.xml"/>
==================================
api的详解
Configuration:类 配置对象
作用:
★1.加载核心配置文件
(了解)new Configuration():默认加载src目录下的名称为 hibernate.properties的配置文件(不能配置映射文件的路径)
★new Configuration().configure():默认加载src目录下的名称为 hibernate.cfg.xml的配置文件

(了解)new Configuration().configure(String 配置文件的路径):加载指定路径下的配置文件
new Configuration().configure("config/a.xml"):加载src目录下config目录下的a.xml
★2.创建sessionFactory
buildSessionFactory()
(了解)3.加载映射文件
addResource(string );
-----------------------------------
SessionFactory:接口 session工厂
SessionFactory并不是轻量级的,因为一般情况下,一个项目通常只需要一个SessionFactory就够
作用:
1.初始化Hibernate。
2.它充当数据存储源的代理(底层维护了一个连接池)
★3.并负责创建Session对象
openSession();
---------------------
抽取一个工具类
HibernateUtils
提供一个获取session的方法
---------------------
整合c3p0
步骤:
1.导入jar包 hibernate解压目录下/lib/optional/c3p0/*.jar
2.在核心配置文件中配置c3p0提供商
<property name="hibernate.connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property>
Session:接口,相当于连接
Session对象是有生命周期的,它以Transaction对象的事务开始和结束边界
线程不安全,轻量级,session不要作为成员变量.
★作用:
1.开启事务
beginTransaction()
2.和数据库进行交互
Serializable save(Object obj); 返回值为此记录的id
update(Object ob);
delete(Object ob);

OID查询
T get(Class<T> clazz,Serializable id);通过id获取一个记录,转成相应的对象
T load(Class<T> clazz,Serializable id);通过id获取一个记录,转成相应的对象
区别:
(★)get:立即发送sql语句,返回值为对象本身
load:不会立即发送sql语句,当使用该对象的非oid属性的时候才发送sql.返回的是代理对象
延迟加载:使用的时候才发送sql.
Transaction:接口 管理事务
commit();
rollback();

*-*-*-*-*-*-*-*-*-*-*-**-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-

持久化类
javabean+映射文件
规范:
这个类必须是一个公共的具体的类(public class)
字段私有,必须提供公共的访问方法
必须提供一个无参构造器
必须提供一个属性(OID)和主键对应
尽量使用包装类修饰属性
尽量不要使用final修饰持久化类(若使用final修饰了load和get方法一样了)
///////////////////////////////////////
主键的生成策略
主键的分类:
代理主键:给对象额外添加一个字段,没有具体的业务,只是作为主键存在.推荐使用
自然主键:使用对象本身一个具有业务意义的字段作为主键(例如:身份证号)
hibernate中的主键生成策略
常见的值:
increment:使用的是hibernate的自增,有问题,数据类型必须为 int short long,不推荐使用
★identity:使用的数据库底层的自增策略,数据类型必须为 int short long,代表:mysql
★sequence:使用的数据库底层的序列策略,数据类型必须为 int short long,代表:oracle
★★native:使用的数据库本身的策略,可以简单认为判断数据库支持自增还是序列.
★uuid:使用的随机的字符串
assigned:放弃hibernate维护主键,我们自己维护.

持久化对象三种状态(持久态★)
瞬时态:对象没有oid值,也没有和session关联
持久态★:对象有oid值,也和session关联
脱管态:对象有oid值,但是没有和session关联

注意:
持久态:可以自动更新数据库
为何持久态对象能自动更新数据库?底层依赖的是hibernate的一级缓存.

一级缓存
缓存:
介于程序和硬件之间的一种介质.
作用:
读取数据的时候,先从缓存中查询一下,若缓存中有,直接返回数据.若缓存中没有,再去硬件中查询;
hibernate是对jdbc进行的封装.效率其实并不高,于是hibernate提供了一系列的优化策略(例如:缓存,延迟加载,抓取策略...)来提供hibernate的运行效率.
hibernate中的缓存:
*一级缓存:是hibernate自带的,必须使用的.不能卸载.它的生命周期和session一样.所以有人也称之为session级别的缓存.
(了解)二级缓存:不是hibernate自带的,要想使用必须先导入jar包,在编写配置文件才可以使用(ehcache).一般使用redis替代.
它的生命周期和sessionFactory一样,所以有人也称之为sessionFactory级别的缓存
hibernate中的一级缓存工作原理:
底层就是一系列的java集合.
读取数据的时候,优先从缓存中查询,若缓存中有直接用;若缓存中没有,在去数据库中查询,且会将查询的结果放入缓存中一份
保存或者更新数据,同样也会讲保存或者更新过的数据放入缓存中一份.

其实将一级缓存分成了两块区域(缓存区和快照区)
将数据放入了缓存区一份和快照区中一份.我们修改数据的时候,只修改缓存区中的数据
当事务提交的时候,判断缓存区和快照区中的数据是否一致;
若一致:啥也不干
若不一致:发送sql语句,更新数据库

先来证明一下一级缓存的存在.
1.对一条记录查询两次
2.先保存一条记录在查询这条记录.

事务
事务的概念
事务的特性:
ACID
原子性
一致性
隔离性
持久性
若不考虑隔离性会产生那些读问题:
脏读
不可重复读
虚读
通过设置数据库的隔离级别就可以避免上面的一些问题
1 read uncommitted
2 read committed (oracle)
4 repeatable read (mysql)
8 serializable
java中应该在service层进行事务控制
如何保证service和dao使用的是同一个事务?
只需要保证他们使用的是同一个连接
如何保证service和dao使用的是同一个连接?
方式1:向下传递连接
*方式2:ThreadLocal

hibernate中的设置隔离级别:
只需要在核心配置文件中配置 hibernate.connection.isolation 属性
<!-- 设置事务的隔离级别 -->
<property name="hibernate.connection.isolation">4</property>

*hibernate其实对ThreadLocal进行封装了
步骤:
1.先在核心配置文件中配置 hibernate.current_session_context_class 属性 值为:thread
<!-- 开启与线程绑定的session -->
<property name="hibernate.current_session_context_class">thread</property>
2.获取session的时候,通过factory.getCurrentSession();
注意:
若使用getCurrentSession()获取的session,不需要我们手动关闭了
////////////////////////////////////
查询的api(*)
hibernate中提供了5中常见的查询方式
oid查询(get和load)
对象导航查询(明天讲)
sql查询(直接写sql语句)
hql查询
qbc查询(条件查询的)
/////////////////////
hql查询
先获取Query对象
session.createQuery(String hql语句)
hql语句,几乎和sql语句一样.是一个面向对象的查询语句.
hql语句需要讲sql中的表名和字段名使用类名和属性名替代.
查询所有
hql:
from Customer
方法:
list()
uniqueResult() :返回唯一值
排序查询
hql:
from Customer order by ....
统计查询
hql:
select count(*) from Customer ....
分页查询
不要在hql中体现分页信息
方法:
setFirstResult(int 开始的索引)
setMaxResults(int 每页显示的大小)
条件查询
hql:
from Customer where 属性1 = ? and 属性2 = ?
方法:
setParameter(int 问号索引,Object 值);
投影查询(查询部分属性)
返回的是 Object[]

//投影查询(部分属性) 将查询的结果封装到对象中
/**
* 1.需要在持久化类中提供相应的构造器
* 2.改写hql语句
* select new 类名(属性1,属性2) from 类
*/
//////////////////////////
qbc查询
query by criteria:更加面向对象的查询方式.全是api
先获取查询对象 Criteria
session.createCrieria(Class clazz)
查询所有
list()
uniqueResult()
排序查询
addOrder(Order.asc|desc(属性名称))
分页查询
setFirstResult(int 开始的索引)
setMaxResults(int 每页显示的大小)
统计查询
setProjection(Projections.sum|min|max|avg|count("属性名"))
setProjection(Projections.rowCount())

条件查询
add(Restrictions.like|eq|lt|gt(属性名,值...))

离线查询(多条件+分页)
脱离session使用的查询方式.
获取离线对象的方式
DetachedCriteria dc = DetachedCriteria.forClass(Class clazz);
他的api几乎和criteria的api一致

我们在web层使用离线查询对象,
用它来判断参数和封装参数

我们最后需要在dao获取一个可以执行的查询对象即可
Criertia cc = dc.getExecutableCriteria(session);
sql查询
SqlQuery ss = session.createSqlQuery(String sql语句);

方法:
list
uniqueResult

setFirstResult
setMaxResults

setParameter
返回值都是:
object[]

若想要将结果封装成某个对象
addEnity(Class clazz)

*-*-*--*-*--*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*

多表操作:
常见的关系:
一对多
多对多

实体之间的关系:
一对多:用户和订单,分类和商品,订单和订单项,客户和联系人
多对多:学生和选课,订单和商品,角色和用户
一对一:公司和注册地,合法夫妻,居民和身份证号
数据库中表的设计:
一对多:根据需要在多表中添加一个外键,指向一表的键(一般是主键)
多对多:引入一张中间表,里面需要存放两位两张表的主键.
一对一:
解决的方案:
1.合二为一
2.唯一外键对应(就是把他们看成是一个特殊的一对多,在其中的一张表中添加外键,且给这个外键提供唯一约束)
3.主键对应
java中的实体设计:
一对多:
客户和联系人
根据需要
在一的一方添加多的一方的集合
在多的一方添加一个一方的对象
多对多:
放入一个对方的集合即可
一对一:
放入一个对方的对象即可
案例1:一对多
客户和联系人
1.创建数据库

2.创建对应的类
根据需要
在一的一方添加多的一方的集合
在多的一方添加一个一方的对象
3.创建映射文件
在多的一方配置many-to-one标签
name属性:一的一方在多的一方中的对象属性名称
class属性:一的一方的全限定名
column属性:外键的字段名称
在一的一方配置set标签
name属性:多的一方在一的一方中集合的属性名称
key标签:
column属性:外键的字段名称
one-to-many标签
class属性:多的一方的全限定名

别忘记去核心配置文件中加载两个映射文件
4.测试代码
设计两个客户:大雄 老金
设计三个联系人:
大雄:熊大和熊二
老金:金三胖
有一个小小的问题:
保存的时候还发送几条update语句?(一会讲)

没有添加任何配置,能不能只保存客户,将他关联的联系人也进行保存呢?瞬时对象异常

--------------------------
级联操作:
级联:操作主体的时候,将其关联的对象也进行相同的操作.
级联具有方向性
级联保存更新操作:
★保存客户,将他关联的联系人也进行保存
客户是主体,就需要在主体的一方配置级联保存更新,在映射文件中set标签上配置 cascade属性 值为:save-update
保存联系人,将他关联的客户也进行保存
联系人是主体,就需要在主体的一方配置级联保存更新,在映射文件中many-to-one标签上配置 cascade属性 值为:save-update
级联删除操作:
★删除客户的时候,将他关联的联系人也进行删除
客户是主体,就需要在主体的一方配置级联删除,在映射文件中set标签上配置 cascade属性 值为:delete 若还有其他的级联操作,用","隔开
删除联系人的时候,将他关联的客户也进行删除
联系人是主体,就需要在主体的一方配置级联删除,在映射文件中many-to-one标签上配置 cascade属性 值为:delete 若还有其他的级联操作,用","隔开
-------------------------
★默认删除
删除一的一方的时候:(必须先查询再删除)
若我们使用web阶段的只是直接删一的一方的会报错;
hibernate中会先将从表中的对应数据的外键置为null,然后再删除主表中的数据.

冗余sql(多余sql)
我们保存数据的时候 先保存了客户,然后保存了联系人,发现除了insert语句之外,还发送几条update语句
这个操作不影响结果
原因:
双方都维护外键 且 双方进行了关联操作
解决方案:
方案1:让其中的一方放弃外键维护
方案2:单向关联
我们在开发中使用让其中的一方放弃外键维护,谁放弃呢?
必须是一的一方放弃.
只需要在一的一方的映射文件中set标签上配置 inverse="true"

cascade决定的是 操作主体的时候 是否 也操作关联方
inverse决定的是 保存一的一方的的时候 多表中是否有外键
开发中:
一般都会在一的一方添加inverse 且设置cascade=save-update

案例2:多对多
用户和角色

1.创建实体类
放入一个对方的集合
2.创建映射文件
set标签
name属性:对方在自己中的集合属性名称
table属性:中间表表名
key标签
column属性:自己在中间表的外键信息
many-to-many标签
class属性:对方的全限定名
column属性:对方在中间表中的外键信息

在核心配置文件中加载映射文件

3.测试代码
让其中的一方放弃外键维护
开发中 一般让被动方放弃

级联保存或更新(了解中理解)
保存用户的时候,将其关联的角色也进行相同的操作
用户是主体,需要在用户的映射文件中配置级联保存更新 set标签上配置

级联删除:(了解中的了解)
删除用户的时候,将其关联的角色也进行相同的操作
用户是主体,需要在用户的映射文件中配置级联删除 set标签上配置

★默认删除:(★)
先删除中间表中的相应的记录,然后再删除对应表中的记录.

其他的操作:
例如:
给一个用户添加角色
查询用户
查询某个角色
给用户的roles中添加角色即可
给一个用户删除角色
给一个用户切换角色

注意:
hibernate是一个orm框架.查询到的数据都是持久态数据.

扩展:
一对一:(使用唯一外键对应)
放入对方的对象
映射文件
使用one-to-one标签 且在外键上添加一个 constrained

延迟加载和对象导航查询

需求:
想知道客户1的联系人个数
Customer c = session.get(Customer.class,1L);
c.getLinkmans().size();

想知道联系人1的客户名称
Linkman l = session.get(Linkman.class,1L);
l.getCustomer().getCust_name();

延迟加载:
使用的时候采取发送sql查询
客户1的联系人个数
由一的一方查询多的一方默认使用的延迟加载.(开发中我们也是这样做的)

能不能查询客户的时候立马把联系人也查询出来.(了解)
在客户的映射文件中的set标签上设置一个属性(lazy属性) 值为false即可
联系人1的客户名称
有多的一方查询一的一方的时候默认使用的也是延迟加载
开发中我们通过多的一方查询一的一方一般使用的是立即加载. (★)
在联系人的映射文件中 many-to-one标签,上设置一个属性(lazy属性) 值为false即可

在set标签上lazy属性的常见值有
true:使用延迟加载 (默认值) ★
false:使用立即加载

在many-to-one标签上lazy属性的常用值为 false
*-*-*-*-*-*-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-

注解方式(JPA)
jpa是规范(接口),hibernate是其中的一套实现类而已

JPA:
单表操作:
环境搭建:
1.导入jar包
若是纯jpa操作.需要在之前包的基础之上额外导入一个 entitymanager.jar jar报目录:解压目录/lib/jpa/hibernate-entitymanager-5.0.7.Final.jar
2.编写核心配置文件(和之前hibernate.cfg.xml中内容大致相同)
名称:persistence.xml
路径:src/META-INF
导入约束:
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd" version="2.0">
</persistence>
内容:
数据库的单元
规范的实现提供商.(省略)
注解类的路径(省略)

数据库的连接信息.
hibernate的配置
导入c3p0配置

不用导入(隔离级别,事务session绑定线程配置)
注意:
最后修改一下 transaction-type="RESOURCE_LOCAL" 使用数据库本地事务

3.抽取工具类(类似于之前的hibernateUtils) JPAUtils
之前提供了一个私有的静态sessionfactory对象,今天提供一个 entityManagerFactory
之前还提供了一个获取session的方法,今天提供一个获取 EntityManager的方法
4.创建持久化类
类上的注解
@Entity //声明自己是一个持久化类
@Table(name="cst_customer") //声明对应的表
oid属性上的注解
@Id //声明它是oid
@Column(name="cust_id")//声明对应的字段名称 若字段名称属性名称一致的话name可以省略不写 或者Column注解直接不写
@GeneratedValue(strategy=GenerationType.IDENTITY)//声明主键生成策略
普通属性上的注解
@Column(name="cust_name")//声明对应的字段名称 若字段名称属性名称一致的话name可以省略不写 或者Column注解直接不写
5.入门代码
//开启事务
EntityTransaction tx = em.getTransaction();
tx.begin();

//保存
persist(obj);

常用的api
保存: persist(Object obj)
查询:
find(Class clazz,Object id); 立即查询
getReference(Class clazz,Object id); 延迟加载

更新:
方式1:快照方式
方式2:强制更新,将脱管态数据强制更新到数据库中 merge(Object obj)
删除:
remove();

查询的api:
jpql查询:Java持久化查询语言
获取查询对象
em.createQuery(jpql语句)
查询所有
getResultList()
getSingleResult()
分页查询
一样
排序查询
语句 + order by
统计查询
一样
条件查询
问号占位符
api
setParameter(int 第几个问号,Object obj)
投影查询
一样

多表的操作:
一对多
注意:属性名称尽量使用驼峰式 尽量不要出现"_"

1.创建持久化类
多的一方
/**
* 配置多对一 @ManyToOne
* targetEntity属性:一的一方的字节码对象,若在对方中已经配置过,可以省略不写.
*
* 配置外键字段信息@JoinColumn
* name属性:外键的字段名称
* referencedColumnName属性:指向的主表的键名称(一般是主键,若是主键的话可以省略不写的)
*
* 注意:
* @JoinColumn 和 mappedBy 互斥
*/
@ManyToOne(targetEntity=Customer.class)
@JoinColumn(name="lkm_cust_id",referencedColumnName="cust_id")
private Customer customer;
一的一方
/**
* @OneToMany 配置一对多
* targetEntity属性:多的一方的字节码对象
* mappedBy属性:自己在多的一方中的属性名称(相当于放弃外键维护权)
* 若是双方都配置映射关系的话必须在放弃的一方使用.
*/
@OneToMany(targetEntity=Linkman.class,mappedBy="customer")
private Set<Linkman> linkmans = new HashSet<Linkman>();
2.测试保存

---------------
级联操作
在@OneToMany或者@ManyToOne标签上配置 cascade={CasCadeType.Persist | merge | all | remove}

默认删除:
就会报错.
我们可以模拟一下模拟删除,具体情况看代码.
///////////////////////
多对多
创建持久化类
被动方
@ManyToMany
targetEntity属性:对方的字节码对象
mappedBy属性:自己在对方中的属性名称,放弃外键维护权
例如:
@ManyToMany(targetEntity=User.class,mappedBy="roles")
private Set<User> users = new HashSet<User>();
主动方
@ManyToMany
targetEntity属性:对方的字节码对象

@JoinTable :添加一张中间表
name属性:中间表表名
JoinColumns属性:自己在中间表中的外键信息 使用@JoinColumn
InverseJoinColumns属性:对方在中间表中的外键信息

例如:
@ManyToMany
@JoinTable(name="sys_user_role",
joinColumns={
@JoinColumn(name="user_num",referencedColumnName="user_id")
},
inverseJoinColumns={
@JoinColumn(name="role_num",referencedColumnName="role_id")
}
)
private Set<Role> roles=new HashSet<Role>();
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Hibernate