一.Hibernate中Session的缓存
要使得一个pojo对象一直处在生命周期中,就必须保证至少有一个变量引用它,或将它放在一个java 的集合中,即集合中存放的就是这个对象的引用。Session接口中的实现类就是一系列的java集合,这就构成了Session的缓存,所以Session可以保存pojo对象。
Session缓存的作用:
1.减少访问数据库的频率
2.保证缓存中的对象与数据库中的相关纪录保持同步。Session并不会立即执行相关的SQL语句,它能够把几条相关的SQL语句合并为一条SQL语句,以便减少访问数据库的次数。
Session清理缓存的时机:
默然情况下,当显示调用了Session的flush()方法的时候;当调用Transaction的commit()方法的时候会先清理缓存,然后再向数据库提交事务;当调用查询方法的时候,如果缓存中没有要查找的对象,会清理缓存,然后去数据库中查找,保证查找的对象是和数据库同步的对象。
可以通过Session的setFlushMode设置清理模式,FlushMode.AUTO; FlushMode.ALWAYS; FlushMode.COMMIT; FlushMode.MANUAL;
二.Hibernate中pojo的三种状态以及转换关系:
临时状态(transient):刚刚new出来的,还没有被持久化,不处在Session的缓冲区中。(临时对象)
持久化状态(persistent):已经被持久化,加入到Session的缓存中,正在被Session所管理。(持久化对象)
游离状态(detached):已经被持久化,但不处于Session的缓存中。(游离对象)
load()方法:返回的是一个pojo类的子类对象(代理对象),该子类是由cglib.jar产生的。load()会使用延迟加载。(延迟加载:只有真正用到类的属性的时候才去数据库中去加载对象。)所以load()方法不会返回一个null,要真正得到一个对象应该调用get()方法。
get()方法:不会产生动态的子类,他会先在缓存里面找该对象,如果没有则马上到数据库中找,然后返回一个pojo对象,如果没有找到就返回null,所以get()没有延迟加载。
save()方法:用来持久化一个临时对象。
//新增
Person person = new Person();
person.setName("new person");
person.setAge(20);
session.save(person);
hibernate将执行insert语句
update()方法:使一个游离对象加入Session缓存中,使它转变为一个持久化对象。当清理缓存的时候执行一条update语句。
//修改
Person person = (Person)session.load(Person.class,2);
person.setName("new test");
hibernate将先装载Person然后执行update语句,如果再次运行则不会再执行update语句
Person person = (Person)session.load(Person.class,2);
person.setName("new test1");
person.setName("new test2");
person.setName("new test1");
只会执行一次update语句
当执行session.flush()的时候执行更新语句,如果不显示执行flush语句,在执行commit的时候会调用session.flush()方法更新语句才能真正被执行。
当开始一个新的session后
Person person = new Person();
session.save(person);这个时候session会先把该person对象存入数据库(执行insert语句)并将会管理这个Person对象。如果一个对象曾经被一个session管理过,但是该session已经被关闭,重新开一个session管理该对象时要更新该对象就要执行session.update()方法.
session = sessionFactory.openSession();
person.setName("ttt");
session.update(person);
saveOrUpdate()方法:如果传入对象是一个临时对象就调用save()方法;如果传入对象是一个游离对象就调用update()方法;如果传入对象是一个持久化对象,就直接返回。该方法是通过判断id来决定是save还是用update。
session.contains(person);用于判断session中是否有一个Person对象.
session = sessionFactory.openSession();
person.setName("ttt");
session.saveOrUpdate(person);
delete()方法:从数据库中删除与pojo对象对应的纪录。如果要删除的是一个持久化对象,Session就将执行一条delete语句;如果传入的是一个游离对象,则先使游离对象被Session关联,使它变成一个持久化对象,然后将执行一条delete语句。注意:只有在清理缓存或调用Session的close方法的时候,delete语句才能真正被执行。
//删除
Person person = (Person)session.load(Person.class,2);
session.delete(person);
hibernate将先装载Person然后执行delete语句
三.主键生成方式
sequence:在Oracle,DB2,PostgreSQL, SAP DB, McKoi中使用序列(sequence)。返回的标识符是long, short或者 int类型的。
执行sql语句:create sequence my_key;
<id name="id">
<generator class="sequence">
<param name="sequence">my_key</param>
</generator>
</id>
increment:用于为long, short或者int类型生成 唯一标识。只有在没有其他进程往同一张表中插入数据时才能使用。 在集群下不要使用。
<id name="id">
<generator class="increment"></generator>
</id>
identity:由底层数据库来负责生成标示符,它要求底层数据库把主键定义为自动增长字段类型。如:在mysql中应把主键定义为:auto_increment类型;在SQL Server中应把主键定义为identity类型。
<id name="id">
<generator class=" identity "/>
</id>
native:根据底层数据库的能力选择identity, sequence 或者hilo中的一个。适合跨数据库平台开发。
<id name="id">
<generator class=" native "/>
</id>
Hilo:使用一个高/低位算法高效的生成long, short 或者 int类型的标识符。给定一个表和字段(默认分别是 hibernate_unique_key 和next_hi)作为高位值的来源。 高/低位算法生成的标识符只在一个特定的数据库中是唯一的。
执行sql语句:
create table hi_value (
next_value number(6,0)
);
insert into hi_value values(0);
<id name="id">
<generator class="
hilo
">
<param name="table">hi_value</param>
<param name="column">next_value</param>
<param name="max_lo">100</param>
</generator>
</id>
uuid:用一个128-bit的UUID算法生成字符串类型的标识符, 这在一个网络中是唯一的(使用了IP地址)。UUID被编码为一个32位16进制数字的字符串。
package net.xiaopi.pojo;
import java.io.Serializable;
public class UUIDObject implements Serializable {
private static final long serialVersionUID = -7800543060715584111L;
private String id;
public String getId() {
return id;
}
public void setId (String id) {
this.id = id;
}
}
执行sql语句:
create table hi_UUIDObject (
id char(32) primary key
);
<class name="UUIDObject">
<id name="id">
<generator class="uuid"></generator>
</id>
</class>
l 跨平台
l UUID
l
Hilo
l 依赖数据库
l Squence
l Identity
l Native
l 其他方式
l Assigned,increment
l foreign
四.关联关系映射
1.单向many-to-one关联
<class name="Person">
<id name="id" column="personId">
<generator class="native"/>
</id>
<many-to-one name="address"
column="addressId"
not-null="true"/>
</class>
<class name="Address">
<id name="id" column="addressId">
<generator class="native"/>
</id>
</class>
Sql语句:
create table Person ( personId bigint not null primary key, addressId bigint not null )
create table Address ( addressId bigint not null primary key )
2.双向many-to-one/one-to-many关联
<class name="Person">
<id name="id" column="personId">
<generator class="native"/>
</id>
<many-to-one name="address"
column="addressId"
not-null="true"/>
</class>
<class name="Address">
<id name="id" column="addressId">
<generator class="native"/>
</id>
<set name="people" inverse="true">
<key column="addressId"/>
<one-to-many class="Person"/>
</set>
</class>
Sql语句:
create table Person ( personId bigint not null primary key, addressId bigint not null )
create table Address ( addressId bigint not null primary key )
加载"主"(即有从的主键,如Person为主,Address为从)不会立即加载"从",而是延迟加载
建立关联最好建立双向关联.
注意建立pojo的时候set属性应该马上new一个集合对象.
inverse:是否放弃维护关系.没有放弃维护关系,会执行一条update语句
比如:address 中的inverse=true;
cascade=All:看管理的集合对象是否持久化,没有持久化就持久化.
级联是级联持久化.没有负责维护关系.
cascade="save-update":级联持久化状态
如果"主"被持久化,他所管理的集合里面的"从"也会被持久化.
cascade="all",对父对象进行save/update/delete操作就会导致子对象也进行save/update/delete操作
delete-orphan:删除“孤儿”模式,此时不被任何一个父对象引用的子对象会被删除.
cascade="all-delete-orphan"
级联(cascade)通常在 <one-to-one>和<one-to-many>关系中比较有用
3.基于外键关联的单向one-to-many关联。
<class name="Person">
<id name="id" column="personId">
<generator class="native"/>
</id>
<set name="addresses">
<key column="personId"
not-null="true"/>
<one-to-many class="Address"/>
</set>
</class>
<class name="Address">
<id name="id" column="addressId">
<generator class="native"/>
</id>
</class>
SQL语句:
create table Person ( personId bigint not null primary key )
create table Address ( addressId bigint not null primary key, personId bigint not null )
基于外键关联的一对多关联是一种很少见的情况,并不推荐使用,对于这种关联关系最好使用连接表。
4.单向many-to-many关联
<class name="Person">
<id name="id" column="personId">
<generator class="native"/>
</id>
<set name="addresses" table="PersonAddress">
<key column="personId"/>
<many-to-many column="addressId"
class="Address"/>
</set>
</class>
<class name="Address">
<id name="id" column="addressId">
<generator class="native"/>
</id>
</class>
SQL语句:
create table Person ( personId bigint not null primary key )
create table PersonAddress ( personId bigint not null, addressId bigint not null, primary key (personId, addressId) )
create table Address ( addressId bigint not null primary key )
5.双向many-to-many关联
<class name="Person">
<id name="id" column="personId">
<generator class="native"/>
</id>
<set name="addresses" table="PersonAddress">
<key column="personId"/>
<many-to-many column="addressId"
class="Address"/>
</set>
</class>
<class name="Address">
<id name="id" column="addressId">
<generator class="native"/>
</id>
<set name="people" inverse="true" table="PersonAddress">
<key column="addressId"/>
<many-to-many column="personId"
class="Person"/>
</set>
</class>
SQL语句:
create table Person ( personId bigint not null primary key )
create table PersonAddress ( personId bigint not null, addressId bigint not null, primary key (personId, addressId) )
create table Address ( addressId bigint not null primary key )
作新增操作时,必须有一方放弃维护关系:inverse="true" ,否则数据库中会多增加一条相同的纪录. cascade="save-update"
6.单向one-to-one关联
a.基于外键关联的双向一对一关联
<class name="Person">
<id name="id" column="personId">
<generator class="native"/>
</id>
<many-to-one name="address"
column="addressId"
unique="true"
not-null="true"/>
</class>
<class name="Address">
<id name="id" column="addressId">
<generator class="native"/>
</id>
<one-to-one name="person"
property-ref="address"/>
</class>
SQL语句:
create table Person ( personId bigint not null primary key, addressId bigint not null unique )
create table Address ( addressId bigint not null primary key )
外键一对一:
主:
<one-to-one name="..." property-ref="">
从:
<many-to-one name="" column="" unique="true" not-null="true">
加载“主”会立即加载”从“,没有使用延迟加载
加载“从”不会立即加载“主”,使用延迟加载
加载的时候,总是加载主
可以更新,
删除时
在“主”写cascade="delete",去将从级联删除,
但在实际的工程中,有没有delete 得从业务角度考虑
b.基于主键关联的一对一关联,要使用特定的id生成器。
<class name="Person">
<id name="id" column="personId">
<generator class="native"/>
</id>
<one-to-one name="address"/>
</class>
<class name="Address">
<id name="id" column="personId">
<generator class="foreign">
<param name="property">person</param>
</generator>
</id>
<one-to-one name="person"
constrained="true"/>
</class>
SQL语句:
create table Person ( personId bigint not null primary key )
create table Address ( personId bigint not null primary key )
主键一对一:
加载"主"会立即加载"从",没有使用延迟加载.
加载"从"不会立即加载"主",使用延迟加载.
加载的时候,总是加载主就OK了.
增加时,先增加"主"还时先增加"从"都没有关系.
如果单增加"从",会自动增加"主".
如果单增加"主",不会自动增加"从",除非有cascade="save-update".
这样的特性都是因为主键生成方式的原因.
<one-to-one>永远不负责维护关系.