Hibernate(二)——持久化

2018-02-12  本文已影响94人  贾里

1.OID和主键生成策略


1.1.主键(Primary key):

在数据库表中能够唯一识别每一行记录的一个字段或者多个字段的组合.

主键特点:
非空且唯一,简单.一般的使用一个列来表示主键.

主键分类:

名称 区别
自然主键 主键具有业务含义,比如身份证号码,必须要收到输入.
代理主键 主键没有业务含义,仅仅起唯一标识,一般由数据库服务器自动生成.
单字段主键 在一张表中使用某一列作为主键.
复合主键 在一张表中使用多列一起,联合作为主键.

1.2.OID

自然主键:assigned,在保存之前必须手动设置值,assigned只针对于自然主键


image.png

保存改对象的时候,必须手动输入该值.

1.3.代理主键的生成方式(让数据库生成或让hibernate生成):

//可以通过sequence参数来指定表对应的序列生成器的名字
<generator class="sequence">
   <param name="sequence">IDDOMAIN_SEQ</param>
</generator>
<generator class="org.hibernate.id.enhanced.TableGenerator">
     <param name="segment_value">IDDOMAIN_SEQ</param>
</generator>

1.4.选择:

1,自然主键还是代理主键;
2,使用数据库来生成主键还是使用hibernate来生成主键(应用是否需要移植数据库)
是否在集群环境中使用
3,性能问题
4,一般来说,使用native就可以了.

image.png

2.Session中的方法


常用方法(已学):

Transaction beginTransaction():开启一个事务
Transaction getTransaction():获取一个事务
Serializable save(Object o):保存一个对象
void update(Object o):修改一个对象
void delete(Object o):删除一个对象
Object get(Class type,Serializable id):根据主键查询指定类型的对象
Query createQuery(String hql):根据hql创建一个查询对象
void close():关闭Session
void clear():清除一级缓存所有对象
void evict(Object o):清除一级缓存中制定的对象

按照方法的功能,把session的方法分为:

2.1.事务相关:

Transactionsession.beginTransaction():标记打开当前session绑定的事务对象。
Transactionsession.getTransaction():得到和当前session绑定的事务对象。

2.2.一级缓存相关:

session.clear():清除一级缓存中所有的对象。
boolean contains(Object entity):判断一级缓存中是否有给定的对象。
session.evict(Object entity):从一级缓存中清除指定的对象。
session.flush():把一级缓存中的脏数据同步到数据库中。
session.refresh(Objectentity):强制重新查询对象,相当于把数据库中的数据同步到一级缓存中。

2.3.持久化操作相关:

session.delete(Objectentity):从数据库中删除一个对象
session.update(Objectentity):更新一个对象
session.get(ClassentityType,Serializableid):根据主键查询一个对象
session.load(ClassentityType,Serializableid):根据主键加载一个对象

1.load方法是一个延迟加载(lazy-load)的方法;把对象的获取(SQL)延迟到了真正使用这个对象的时候才发送;
2.真正使用?当使用一个非主键属性的时候;
3.load实现原理?使用动态代理,为load的domain动态创建了一个子类,在这个子类中,复写所有非主键调用方法,在这些方法中,去发送.

session.save(Objectentity):保存一个对象

1.同步JPA的接口方法;
2.和save的区别:在没有事务环境下,save方法会发送INSERT SQL,persist不会;)

session.saveOrUpdate(Objectentity):如果对象没有保存到数据库,则保存,如果已经保存过,则更新。
session.merge(Objectentity):等同于saveOrUpdate方法。

1.同步JPA的接口方法;
2.和saveOrUpdate的区别:在没有事务环境下,saveOrUpdate方法会发送INSERT SQL,merge不会;

2.4.其他:

session.close():关闭session,相当于关闭了和session关联的connection对象。关闭session之后,就不能再使用这个session完成持久化相关的操作。
session.doWork(Workwork):Hibernate提供给程序员直接使用JDBC的一个途径。
session.doReturningWork(ReturningWork):Hibernate提供给程序员直接使用JDBC的一种途径。
Serializablesession.getIdentifier(Objectentity):得到一个对象的主键值

session 上面所有的方法都在促使对象的状态发生改变.

2.5.Hibernate中对象保存的方法:

persist和方法save方法都表示保存一个对象,但是persist方法必须运行在事务空间内.

save(e);   //没有事务环境,也会发送INSERT INTO语句
persist(e);//没有事务环境,不会发送INSERT INTO语句.

Hibernate实现了JPA的规范,就得提供JPA中的方法,而在JPA中持久化操作的方法就叫做:persist.
建议使用persist方法.

2.6.保存或更新操作方法:

session.saveOrUpdate(Objectentity):如果对象没有保存到数据库,则保存,如果已经保存过,则更新。

merge方法相当于saveOrUpdate方法.必须运行在事务空间内,是JPA规范的方法.

2.7.加载或查询指定类型和IOD的一个对象:

Object obj = session.load(Classs type,Serializable id)
Object obj = session.get(Classs type,Serializable id)

如果对象没有被加载过,则发送一条SELECT语句,去加载对象,再返回属性值.
load方法返回的对象永远不可能为空,所以不能使用ifnull来判断,如果load了一个不存在的id的对象,在使用的时候报错;
load方法返回的对象是持久化对象;
load方法也会从一级缓存中获取数据

load原理:

如果在session关闭之前没有去实例化延迟加载对象,报错:
LazyInitializationException: could not initialize proxy - no Session.

LoadEventListener$LoadType类
一般的,load方法是Hibernate内部使用的,我们就使用get方法即可.

image.png

3.持久化对象的状态


3.1.通过三个问题,引出对象状态.

结论:
通过上述三个测试,我们发现Session中的方法和SQL的执行没有任何关系.
问题:那到底SQL的执行和什么有关系呢?有什么关系呢? ---->和对象的状态有关系.

3.2.持久化对象的状态有哪一些,怎么划分的?

划分的规则:
1):当前对象是否有OID(该对象在表中对应有一个id值.)
2):对象是否被Session所管理(对象是否在一级缓存中).

状态 - 特点
临时状态/瞬时态(transient) 刚刚用new语句创建,没有被持久化,不处于session中。 没有oid,不在session当中.
持久化状态(persistent) 已经被持久化,加入到session的缓存中。 有oid,在session当中
脱管态/游离状态(detached) 已经被持久化,但不处于session中。 有oid,不在session当中
删除状态(removed) 对象有关联的ID,并且在Session管理下,但是已经计划被删除。 有oid,在session当中,最终的效果是被删除.

判断规则:
对象是否有OID,判断对象是否与Session关联(被Hibernate管理)

3.3.状态的之间的转换:

临时状态是没有ID的,测试可以打印该对象的ID,发现存在ID.
--->设置hibernate.cfg.xml的属性:hibernate.use_identifier_rollback=true

image.png

3.4.总结:

Session中的方法仅仅只是改变对象的状态,不负责发送SQL/默认情况下事务提交的时候发送SQL.

User u = new User();  //临时状态
u.setName("XX");

session.save(u);---->SELECT max(id) //持久化状态

//持久化状态可以被删除.
 User  u = session.get(User.class,1L);
 session.delete(u);

 User u = new User();
 u.setId(1L);//游离状态
-----------------------------------

image.png

4.集合映射


之前对象中的属性:都是简单数据类型(一个类型对应一个值.String,Integer,Date)
属性是集合类型:

案例:根据一个用户有一个邮箱地址,分析表结构的设计.
因为此时:一个用户最多只有一个邮件地址,可以直接邮件作为用户表的一列.
如何一个用户有多个邮箱地址,分析表结构的设计.

image.png
image.png

存储多个数据,此时只能使用集合.
Set/List/Map.
Set:不记录添加顺序,元素不能重复.
List:记录添加的顺序,元素运行重复.
Map:存储键值对,每次存储都要存储key和value.
在开发中灵活选用,根据各自的特点和具体的需求.

Set set = new HashSet();
List list = new ArrayList();
Map map  = new HashMap();

集合属性只能以接口声明(当持久化某个实例时, Hibernate 会自动把程序中的集合实现类替换成 Hibernate 自己的集合实现类),

image.png

集合属性只能以接口声明(当持久化某个实例时, Hibernate 会自动把程序中的集合实现类替换成 Hibernate 自己的集合实现类
---->PersistentSet
---->PersistentList


image.png

选择:
如果集合类型使用Set,则使用<set>元素.
如果集合类型使用List,则使用<bag>元素.

Hibernate对集合账号的原生支持两种排序方式(了解):

排序属性 <set> <bag> <list> <map>
sort属性 支持 不支持 不支持 支持
order-by属性 支持 支持 不支持 支持

需求:根据邮件的地址逆序排序.

<!-- 映射Collection/List集合 -->
<bag name="emailBag" table="user_emails_bag" order-by="address DESC">
    <key column="user_id" />
    <element column="address" type="string" />
</bag>

order-by="address DESC":
注意:address表示数据库表的列名.

5.对象之间的关系(写少量代码):


5.1.依赖关系:

如果A对象离开了B对象,A对象就不能正常编译,则A对象依赖B对象.
在A类使用到了B(调用了B的方法,调用了B的字段).

//依赖关系:
class B1{}
class B2{}
class A{
   B2 b2;//A依赖B2
   void doWork(){
      B1 b1 = new B1();//A依赖于B1
   }
}

5.2.关联关系:

A对象依赖B对象,并且把B对象作为A对象的一个字段,则A和B是关联关系.

class B{}
class A{
   B b;//关联关系
}
class Deparment{
  //一对多
  List<Employee> employees = new ...;
}
class Employee{
}

Deparment d = new ...();
Employee e1 = new ....();
Employee e2 = new ....();
Employee e3 = new ....();

d.getEmployess().add(e1);
d.getEmployess().add(e2);
d.getEmployess().add(e3);

class Deparment{}
class Employee{
   //多对一
   Department dept;
}
Deparment d = new ...();

Employee e1 = new ....();
Employee e2 = new ....();
Employee e3 = new ....();

e1.setDept(d);
e2.setDept(d);
e2.setDept(d);

按照多重性分:

关联关系 解释 例子
1).一对一 : 一个A对象属于一个B对象;
一个B对象属于一个A对象.
QQ号码对应一个QQ空间.
2).一对多: 一个A对象包含多个B对象. 一个部门包含多个员工对象,
此时我们使用集合来封装B对象.
3).多对一: 多个A对象同属于一个B对象,
并且每个A对象只能属于一个B对象.
设计表的时候:外键在many这一方
在开发设计中:添加一个many方对象的时候,
往往通过下拉列表去选择one方.
多个员工对象属于同一个部门.
4).多对多 一个A对象属于多个B对象,一个B对象属于多个A对象.
通过中间表来表示关系.
一个老师可以有多个学生,
一个学生可以有多个老师.

按照导航性分:
如果通过A对象中的某一个属性可以访问该属性对应的B对象,则说A可以导航到B.

- -
1).单向: 只能从A通过属性导航到B,B不能导航到A.
2).双向: A可以通过属性导航到B,B也可以通过属性导航到A.

判断方法:
1,判断都是从对象的实例上面来看的;
2,判断关系必须确定一对属性;
3,判断关系必须确定具体需求;

5.3.聚合关系:

表示整体和部分的关系,整体和部分之间可以相互独立存在,一定是有两个模块来分别管理整体和部分.
整体和部分可以分开.

5.4.组合关系:

强聚合关系,但是整体和部分不能独立存在,一定是在一个模块中同时管理整体和部分,生命周期必须相同.
单据和单据明显/购物车

5.5.泛化关系

:其实就是继承关系.

上一篇 下一篇

猜你喜欢

热点阅读