多对多双向关联
关系举例:老师ßà学生,老师需要知道自己教了哪些学生,学生也知道自己有哪些老师.
数据库:中间表
Annotation:@ManyToMany
XML:<many-to-many>
多对多单向配置只需要在一端进行配置就可以了.
关系模型(Teache多对多Student)
Teacher(id,name,students)多
Student(id,name,teachers)多
Set<Student> students=new HashSet<Student>()
Set<Teacher> teachers = new HashSet<Teacher>();
Annotation配置
在Teacher这一端的students上配置
@ManyToMany
@JoinTable(name="t_s",
joinColumns={@JoinColumn(name="teacher_id")},
inverseJoinColumns={@JoinColumn(name="student_id")}
)
在Student一端的teachers只需要配置
@ManyToMany(mappedBy="students")
XML配置方式:两端配置一样,注意表名和生成的中间表的字段属性名要一致
Teacher那一端配置
<set name="students" table="t_s">
<key column="teacher_id"/>
<many-to-many class="com.xxx.Student" column="student_id"/>
</set>
在Student那一端配置
<set name="teachers" table="t_s">
<key column="student_id"></key>
<many-to-many class="com.xxx.Teacher" column="teacher_id"/>
</set>
生成的数据库表和上面是一样的.
树状结构的设计(重要)
设计思想:数据库模型,面向对象模式,关系映射,CRUD
数据库模型:表(id,name,pid)
实体模型:父结点ß一对多à子结点,一对多/多对一双向关联映射,一个子结点只有一个父结点,一个父结点有多个子结点.
Class Org
private int id;
private String name;
private Set<Org> children = new HashSet<Org>();
private Org parent;
关系映射:在同一个类中使用@ManyToOne和@OneToMany
在父结点parent上
@ManyToOne
@JoinColumn(name="parent_id")
public Org getParent() {
return parent;
}
在子结点children上
@OneToMany(cascade=CascadeType.ALL, mappedBy="parent")
public Set<Org> getChildren() {
return children;
}
基本关联关系对象的CRUD
1 想删除或者更新,先做load,除非精确知道ID.
2 Cascade属性(是一个数组)管理CUD,只是为了编程的方便,不要把它的功能看得太大.
cascade={CascadeType.ALL}
CascadeType取值
ALL Cascade all operations所有情况
MERGE Cascade merge operation合并(merge=save+update)
PERSIST Cascade persist operation存储 persist()
REFRESH Cascade refresh operation刷新
REMOVE Cascade remove operation删除
规律,双向关系要是程序中设定双向关联.还要设置mappedBy
3 Fetch属性,读取,管理R(Retrieve查询)
fetch = FetchType.LAZY|EAGER
Hibernate Annotation的默认的FetchType在ManyToOne是EAGER的,在OneToMany上默认的是LAZY.
如果指定OneToOne的fetch=FetchType.LAZY,会延迟对关联对象的加载,不管是load还是get.
在XML中,在外键属性上设置inverse=”true|false”进行设置.
4 如果想消除关联关系,先设定关系为NULL就可以打破关联关系,再删除对应记录.如果不删除相关的记录,该记录就成为垃圾数据.
5 O/R Mapping编程模型
A 映射模型(映射数据库)
1 JPA ANNOTATION
2 hibernate annotation extension
3 hibernate xml
4 jpa xml
B 编程接口(增删改查)
1 jpa
2 hibernate
C 数据库查询语言
1 HQL
2 EJBQL (JPQL)
6
集合映射(不太重要)
Set
List
@OrderBy(“属性名 ASC|DESC”)
Map
@MapKey(name=”字段名”)
private Map<Integer, User> users = new HashMap<Integer, User>();
继承映射(不太重要)
三种模式:TABLE_PER_CLASS| JOINED| SINGLE_TABLE
strategy=InheritanceType.XXX
关系模式就是一种方式,在数据库的表有三种表现形式.
SINGLE_TABLE模式
Person, Student和Teacher继承Person
Person(id,name)
Student(score)
Teacher(title)
在Student实体中
@Entity
@DiscriminatorValue("student")
在Teacher中
@Entity
@DiscriminatorValue("teacher")
在Person中
@Entity
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name="discriminator",discriminatorType=
DiscriminatorType.STRING)
@DiscriminatorValue("person")
生成的表为
create table Person (
discriminator varchar(31) not null,
id integer not null auto_increment,
name varchar(255),
score integer,
title varchar(255),
primary key (id)
)
TABLE_PER_CLASS模式
这种方式也比较麻烦,注意id生成策略.
Person, Student和Teacher继承Person
Person(id,name)
Student(score)
Teacher(title)
在Person中
@Entity
@Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)
@TableGenerator(//ID生成策略采用表生成策略
name="t_gen",
table="t_gen_table",
pkColumnName="t_pk",
valueColumnName="t_value",
pkColumnValue="person_pk",
initialValue=1,
allocationSize=1
)
主键映射
@Id
@GeneratedValue(generator="t_gen", strategy=GenerationType.TABLE)
生成了三张表+一张生成主键的临时表
create table Person (
id integer not null,
name varchar(255),
primary key (id)
)
create table Student (
id integer not null,
name varchar(255),
score integer not null,
primary key (id)
)
create table Teacher (
id integer not null,
name varchar(255),
title varchar(255),
primary key (id)
)
create table t_gen_table (
t_pk varchar(255),
t_value integer
)
JOINED模式
这种方式最为简单.
Person, Student和Teacher继承Person
Person(id,name)
Student(score)
Teacher(title)
在Person中
@Entity
@Inheritance(strategy=InheritanceType.JOINED)
生成的表为:
create table Person (
id integer not null auto_increment,
name varchar(255),
primary key (id)
)
create table Student (
score integer not null,
id integer not null,
primary key (id)
)
create table Teacher (
title varchar(255),
id integer not null,
primary key (id)
)
两个外键约束表Student和Teacher里面的id分别references Person(id)
Hibernate查询(HQL)
QL(Query Language)
NativeSQL>HQL>EJBQL(JP QL1.0)>QBC(Query by Criteria)>
QBE(Query by Example)
EJBQL是HQL的一个子集.
没必要把EJBQL和HQL区分得特别清楚,能够满足需求和设计.
QL和导航关系结合,共同为查询提供服务.
:占位符
Query q = session.createQuery("from Category c where c.id > :min and c.id < :max");
q.setParameter("min", 2);
q.setParameter("max", 8);
或者q.setInteger("min", 2);
q.setInteger("max", 8);
类似于JDBC里面的PreparedStatement
链式编程
Query q = session.createQuery("from Category c where c.id > :min and c.id < :max")
.setInteger("min", 2)
.setInteger("max", 8);
Query q = session.createQuery("from Category c where c.id > ? and c.id < ?");
q.setParameter(0, 2)
.setParameter(1, 8);
分页显示
Query q = session.createQuery("from Category c order by c.name desc");
q.setFirstResult(2);//设置起始记录位置.
q.setMaxResults(4);//设置每页显示的最大记录数
q.uniqueResult()//返回唯一的一条记录.
Is null
Is empty 测试集合是否为空
NamedQueries 命名查询
把查询语句集中放在一个位置中.
SQLQuery q = session.createSQLQuery("select * from category limit 2,4").addEntity(Category.class);
使用数据库本
性能优化
1 注意session.clear()的运用,尤其是不断分页循环的时候
A 在一个大集合中进行遍历,取出其中含有敏感字的对象
B 另一种形式的内存泄露.
2 1+N问题
LAZY ,BatchSize,join fetch
3list和iterator的区别
list取所有
iterator先取ID,等到要用的时候再根据ID取出对象.
session中list第二次发出,仍会到数据库中查询数据.iterator第二次首先查找session级缓存.
4一级缓存和二级缓存和查询缓存
A 缓存
B 一级缓存,session级别的缓存
C 二级缓存,SessionFactory级别的缓存,可以跨越session级别存在.
适合放二级缓存:
经常被访问,改动不大不会经常访问,数量有限.如:用户权限,组织机构
D 打开二级缓存
Hibernate.cfg.xml
<property name="cache.use_second_level_cache">true</property>
使用ehcache
JAR文件:/lib/optional ehcache-1.2.3.jar
<property name="cache.provider_class">org.hibernate.cache.EhCacheProvider</property>
使用配置文件ehcache.xml,将其复制到src目录下.
Annotation注解:@Cache
import org.hibernate.annotations.Cache;
import org.hibernate.annotations.CacheConcurrencyStrategy;
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
@Cache(
CacheConcurrencyStrategy usage(); (1)
String region() default ""; (2)
String include() default "all"; (3)
)
(1) usage: 给定缓存的并发策略(NONE, READ_ONLY, NONSTRICT_READ_WRITE, READ_WRITE, TRANSACTIONAL)
(2) region (可选的):缓存范围(默认为类的全限定类名或是集合的全限定角色名)
(3) include (可选的):值为all时包括了所有的属性(proterty), 为non-lazy时仅含非延迟属性(默认值为all)
E load默认使用二级缓存,iterator默认使用二级缓存
Flist默认向二级缓存添加数据,但是查询的时候不使用.
G 如果Query需要使用二级缓存,则打开查询缓存
<property name="cache.use_query_cache">true</property>
需要调用Query setCachable(true)方法指明使用二级缓存.
查询缓存:相同的Sql查询
缓存算法
LRU,LFU, FIFO
Least Recently Used
Least Frequently Userd
First In First Out
memoryStoreEvictionPlicy=”LRU”(ehcache)
事务
ACID
原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability)。
当事务处理系统创建事务时,将确保事务有某些特性。组件的开发者们假设事务的特性应该是一些不需要他们亲自管理的特性。这些特性称为ACID特性。
ACID就是:原子性(Atomicity )、一致性( Consistency )、隔离性( Isolation)和持久性(Durabilily)。
1. 原子性
原子性属性用于标识事务是否完全地完成,一个事务的任何更新要在系统上完全完成,如果由于某种原因出错,事务不能完成它的全部任务,系统将返回到事务开始前的状态。
让我们再看一下银行转帐的例子。如果在转帐的过程中出现错误,整个事务将会回滚。只有当事务中的所有部分都成功执行了,才将事务写入磁盘并使变化永久化。
为了提供回滚或者撤消未提交的变化的能力,许多数据源采用日志机制。例如,SQL Server使用一个预写事务日志,在将数据应用于(或提交到)实际数据页面前,先写在事务日志上。但是,其他一些数据源不是关系型数据库管理系统 (RDBMS),它们管理未提交事务的方式完全不同。只要事务回滚时,数据源可以撤消所有未提交的改变,那么这种技术应该可用于管理事务。
2. 一致性
事务在系统完整性中实施一致性,这通过保证系统的任何事务最后都处于有效状态来实现。如果事务成功地完成,那么系统中所有变化将正确地应用,系统处于有效状态。如果在事务中出现错误,那么系统中的所有变化将自动地回滚,系统返回到原始状态。因为事务开始时系统处于一致状态,所以现在系统仍然处于一致状态。
再让我们回头看一下银行转帐的例子,在帐户转换和资金转移前,帐户处于有效状态。如果事务成功地完成,并且提交事务,则帐户处于新的有效的状态。如果事务出错,终止后,帐户返回到原先的有效状态。
记住,事务不负责实施数据完整性,而仅仅负责在事务提交或终止以后确保数据返回到一致状态。理解数据完整性规则并写代码实现完整性的重任通常落在开发者肩上,他们根据业务要求进行设计。
当许多用户同时使用和修改同样的数据时,事务必须保持其数据的完整性和一致性。因此我们进一步研究A C I D特性中的下一个特性:隔离性。
3. 隔离性
在隔离状态执行事务,使它们好像是系统在给定时间内执行的唯一操作。如果有两个事务,运行在相同的时间内,执行相同的功能,事务的隔离性将确保每一事务在系统中认为只有该事务在使用系统。
这种属性有时称为串行化,为了防止事务操作间的混淆,必须串行化或序列化请求,使得在同一时间仅有一个请求用于同一数据。
重要的是,在隔离状态执行事务,系统的状态有可能是不一致的,在结束事务前,应确保系统处于一致状态。但是在每个单独的事务中,系统的状态可能会发生变化。如果事务不是在隔离状态运行,它就可能从系统中访问数据,而系统可能处于不一致状态。通过提供事
务隔离,可以阻止这类事件的发生。
在银行的示例中,这意味着在这个系统内,其他过程和事务在我们的事务完成前看不到我们的事务引起的任何变化,这对于终止的情况非常重要。如果有另一个过程根据帐户余额进行相应处理,而它在我们的事务完成前就能看到它造成的变化,那么这个过程的决策可能
建立在错误的数据之上,因为我们的事务可能终止。这就是说明了为什么事务产生的变化,直到事务完成,才对系统的其他部分可见。
隔离性不仅仅保证多个事务不能同时修改相同数据,而且能够保证事务操作产生的变化直到变化被提交或终止时才能对另一个事务可见,并发的事务彼此之间毫无影响。这就意味着所有要求修改或读取的数据已经被锁定在事务中,直到事务完成才能释放。大多数数据库,例如SQL Server以及其他的RDBMS,通过使用锁定来实现隔离,事务中涉及的各个数据项或数据集使用锁定来防止并发访问。
4. 持久性
持久性意味着一旦事务执行成功,在系统中产生的所有变化将是永久的。应该存在一些检查点防止在系统失败时丢失信息。甚至硬件本身失败,系统的状态仍能通过在日志中记录事务完成的任务进行重建。持久性的概念允许开发者认为不管系统以后发生了什么变化,完
成的事务是系统永久的部分。
在银行的例子中,资金的转移是永久的,一直保持在系统中。这听起来似乎简单,但这,依赖于将数据写入磁盘,特别需要指出的是,在事务完全完成并提交后才写入磁盘的。
所有这些事务特性,不管其内部如何关联,仅仅是保证从事务开始到事务完成,不管事务成功与否,都能正确地管理事务涉及的数据 当事务处理系统创建事务 时,将确保事务有某些特性。组件的开发者们假设事务的特性应该是一些不需要他们亲自管理的特性。这些特性称为ACID特性