现在的位置: 首页 > 综合 > 正文

所有hibernate知识

2018年05月17日 ⁄ 综合 ⁄ 共 23126字 ⁄ 字号 评论关闭

课程内容

1.        HelloWorld

a)        xml

b)       annotation

2.        Hibernate原理模拟– 什么是O/RMapping以及为什么要有O/RMapping

3.        常见的O/R框架(了解)

4.        hibernate基础配置(重点)

5.        ID生成策略(重点掌握AUTO)

6.        Hibernate核心开发接口介绍(重点)

7.        对象的三种状态(了解)

8.        关系映射(重点)

9.        Hibernate查询(HQL)

10.     在Struts基础上继续完善BBS2009

11.     性能优化(重点)

12.     补充话题

风格

1.        先脉络,后细节

2.        先操作,后原理

3.        重Annotation,轻xml配置文件

a)        JPA

b)       hibernate - extension

资源

1.        http://www.hibernate.org

2.        hibernate zh_CN文档

3.        hibernate annotation references

环境准备

1.        下载hibernate3.3.2

2.        下载hibernate3.4.0

3.        注意阅读hibernatecompatibility matrix(hibernate网站,download)

4.        下载slf4j1.5.8

Hibernate HelloWorld

1.        建立新的java项目,名为:hibernate_0100_HelloWorld

2.        学习建立User-library– hibernate,并加入相应的jar包

a)        项目右键-buildpath-configure build path-add library

b)       选择User-library,在其中新建libraray,命名为hibernate

c)        在该library中加入hibernate所需jar包

                       i.             hibernate core

                     ii.             /required

                   iii.             slf-nop jar

3.        引入mysql的JDBC驱动包

4.        在mysql中建立对应的数据库以及表

a)        create database hibernate;

b)       use hibernate;

c)        create table Student (id intprimary key, name varchar(20), age int);

5.        建立hibernate配置文件hibernate.cfg.xml

a)        从参考文档中copy

b)       修改对应的数据库连接

c)        注释掉暂时用不上的内容

6.        建立Student类

7.        建立Student映射文件Student.hbm.xml

a)        参考文档

8.        将映射文件加入到hibernate.cfg.xml

a)        参考文档

9.        写测试类Main,在Main中对Student对象进行直接的存储测试

a)        参考文档

10.     FAQ:

a)        要调用newConfiguration().configure().buildSessionFactory(),而不是省略configure,否则会出hibernatedialect must be set的异常

11.     Note:

a)        请务必建立自己动手查文档的能力

b)       重要的是:

                       i.             要建立自己动手查一手文档的信心

                     ii.             还有建立自己动手查一手文档的习惯!

                   iii.             主动学习,放弃被动接受灌输的习惯!

12.     建立能力:

a)        错误读完整

b)       读出错误的关键行

c)        排除法

d)       比较法

e)        google老师

建立Annotation版本的HelloWorld

1.        创建teacher表,create table teacher (id int primary key, name varhcar(20), titlevarchar(10));

2.        创建Teacher类

3.        在hibernate lib中加入annotation的jar包

a)        hibernate annotaion jar

b)       ejb3 persistence jar

c)        hibernate common annotationsjar

d)       注意文档中没有提到hibernate-common-annotations.jar文件

4.        参考Annotaion文档建立对应的注解

5.        在hibernate.cfg.xml中建立映射<mapping class=…/>

6.        参考文档进行测试(注意文档中缺少configure()的小bug

7.        FAQ: @不给提示

a)        content assist – activation – 加上@

What is and Why O/R Mapping

1.        JDBC操作数据库很繁琐

2.        Sql语句编写并不是面向对象的

3.        可以在对象和关系表之间建立关联来简化编程

4.        O/R Mapping简化编程

5.        O/R Mapping跨越数据库平台

6.        Hibernate_0200_OR_Mapping_Simulation

O/R Mapping Frameworks

1.        hibernate

2.        toplink

3.        jdo

4.        JPA

a)        意愿统一天下

Hibernate基础配置

1.        对应项目:Hibernate_0300_BasicConfiguration

2.        介绍MySQL的图形化客户端

3.        hibernate.cfg.xml:hbm2ddl.auto   hibernatemapping ddl为hibernate映射建表语句。

这个有四个取值:create(如果没有表会自动创建表,如果选择它每次都会重建表,覆盖以前的表),update会增加没有的列值,validate(在往表里面插入之前会验证数据类型是不是符合),create-drop

hibernate.hbm2ddl.auto参数的作用主要用于:自动创建|更新|验证数据库表结构。如果不是此方面的需求建议setvalue="none" 
create 
每次加载hibernate时都会删除上一次的生成的表,然后根据你的model类再重新来生成新表,哪怕两次没有任何改变也要这样执行,这就是导致数据库表数据丢失的一个重要原因。 
create-drop  
每次加载hibernate时根据model类生成表,但是sessionFactory一关闭,表就自动删除。 
update 
常用的属性,第一次加载hibernate时根据model类会自动建立起表的结构(前提是先建立好数据库),以后加载hibernate时根据
model
类自动更新表结构,即使表结构改变了但表中的行仍然存在不会删除以前的行。要注意的是当部署到服务器后,表结构是不会被马上建立起来的,是要等应用第一次运行起来后才会。 
validate  
每次加载hibernate时,验证创建数据库表结构,只会和数据库中的表进行比较,不会创建新表,但是会插入新值。

a)        先建表还是先建实体类

4.        搭建日志环境并配置显示DDL语句

a)        slf4j与log4j的关系:slf4j像是一个大管家,可以管理许多的日志框架,log4j是其中之一

b)       加入sl4j-log4j.jar,加入log4j的jar包,去掉slf4j-nop-jar

c)        从hibernate/project/etc目录copy log4j.properties

d)       查询hibernate文档,日志部分,调整日志的输出策略

e)         

5.        搭建JUnit环境

a)        需要注意JUnit的Bug

6.        hibernate.cfg.xml:show_sql

7.        hibernate.cfg.xml:format_sql//是经过格式化的,更加易读。

8.        表名和类名不同,对表名进行配置

使用annotation是省略了类名.hbm.xml而是直接用注释来完成这个类的映射。

@Entity这个是实体类,代表这个类就是与数据库中想映射的类,它的类型为

Javax.persisten.Entity。如果出现实体类与数据库中的表名不一致的情况,那么还要加上@Table也要是Javax.persisten.Table

@Table(name="_Teacher")这个就是说,它不会去寻找数据库中叫Teacher这个表,而是会去寻找叫_Teacher的表。因为我们hbm2ddl.auto选择的是create所以它会自动创建这个表。所以此时会有teacher_teacher两个表。

 

a)        Annotation:@Table

b)       xml:自己查询

9.        字段名和属性相同

所有没有定义注解的属性等价于在其上面添加了@Basic注解

也就是说如果类中与数据库中的列名一样就什么也不用写。

如果不对应则用@Column(name="_name"),它就会寻找叫_name的这个列.同上,那个理由,则会新建一个叫_name的列.

a)        默认为@Basic  //

b)       xml中不用写column

那么如果要xml不一样的话怎么办呢?加个column=name即可.

10.     字段名和属性名不同

a)        Annotation: @Column

b)       xml:自己查询

11.     不需要psersistence的字段

a)        Annotation:@Transient

b)       xml不写就行了.

如果在某个属性段的get方面上面加了@Transient这个注释那么在生成表时间就不会建立这列.它是透明的.存储时不要存储它.

 

12.     映射日期与时间类型,指定时间精度

a)        Annotation:@Temporal

b)       xml:指定type

@Temporal(TemporalType.DATE)

它会记录时期,默认是即记录日期又记录时间.

13.     映射枚举类型

a)        @Enumerated

b)       xml:麻烦

14.     字段映射的位置(field或者get方法)

a)        best practice:保持field和get set方法的一致

写在方法上,因为我们让它是private就是不想让别人知道,所以我们只让他们的get方法让别人调用

15.     @Lob

16.     课外:CLOB BLOB类型的数据存取

17.     课外:Hibernate自定义数据类型

18.     hibernate类型

 

type它是数据类型,在程序里java是强数据类型,有八种基本类型和别的,Hibernate也有它自己的数据类型,你可以去看一下。数据库也有它自己的数据类型比如Oracle的数据类型,Hibernate要把程序和数据库的数据进行交换,就必须进行类型匹配。比如java里面的String
Oracle里面没有,Oracle里面只有varchar/varchar2等,Hibernate起到桥梁的作用,把String
varchar/varchar2都转换成它自己的类型,然后进行数据传递。

 

type指定的是Java语言中的类型
而数据表在建立时每个字段也是有其自己的类型的
Hibernate
在存储时要将Java类型转换成数据库类型,反之亦然。.

 

 

根据下表知道,java、数据库,hibernate都有自己各自的数据类型。而type指的是java中的属性值要以哪种类型去转换,指定后,它会先匹配hibernate中的数据类型(即映射类型)然后再由映射类型转换为标准的sql类型。绝大时间可以不指定,因为java类里面是什么样的类型,它就默认是什么样的类型,但是一些复杂的如enum类型。

如:@Enumerated(value=EnumType.ORDINAL).它的意思就是指定java中这个字段索引类型,那么会匹配相应的映射类型,如果指定@Enumerated(value=EnumType.STRING)那么java的类型就是String那么它肯定会匹配映射类型的string类型。然后去转换为相应的sql类型。

a)        

ID生成策略

1.        对应项目:hibernate_0400_ID

2.        注意:

a)        我们观察hibernate生成表的结构并不是为了将来就用它生成,(可能还有自己的扩展,比如index等)而是为了明白我们应该建立什么样的表和实体类映射

3.        xml生成id()

非常重要,annotationhbm.xml不能同时使用,且记。所以会在hibernate.cfg.xml中会出现

        <mapping
resource="com/bjsxt/hibernate/model/Student.hbm.xml"/>这个是对XML形式的映射。

       <mapping
class="com.bjsxt.hibernate.model.Teacher"/>

这个是对annotation形式的映射。

一个类里面绝对不能同时有这两种映射

a)        generator

b)       常用四个:native identity sequence uuid

使用时uuid:这个id字段必须为string

如果使用native它的属性仍为id

\hibernate-distribution-3.3.2.GA-dist\hibernate-distribution-3.3.2.GA\project\etc

这个目录下面有很多重要的东西,好好看看。

4.        @GeneratedValue

a)        自定义ID

b)       AUTO它默认相当于XML中的native

                       i.             默认:对MySQL,使用auto_increment

                     ii.             对Oracle使用hibernate_sequence(名称固定)

c)        IDENTITY

d)       SEQUENCE

                       i.             @SequenceGenerator

e)        TABLE (可以忘记)

                       i.             @TableGenerator

映射主键属性

使用@Id注解可以将实体bean中的某个属性定义为标识符(identifier).
该属性的值可以通过应用自身进行设置,
也可以通过Hiberante生成(推荐).
使用 @GeneratedValue注解可以定义该标识符的生成策略:

·        AUTO -
可以是identity column类型,或者sequence类型或者table类型,取决于不同的底层数据库.

·        TABLE -
使用表保存id

·        IDENTITY - identitycolumn(只能用在mysqlsqlserver中)

·        SEQUENCE - sequence

 

5.        FAQ:

a)        用Junit测试时Hibernate SessionFactory 初始化异常不提示。疑似一个bug

b)       用main来做测试L

6.        联合主键

a)        xml: composite-id

                       i.             为什么要重写equals和hashCode

只要用联合主键,就要重写这两个方法。数据库中存在的一个一个对象如何区别?是通过id来实现的,而在内存中也应该这样所以要重写这两个方法。

                     ii.             为什么要实现serializable

equals/hashcode 查看JDK文档,大致是用于你可以自己定义两个对象何时相等(equals)。例如你可以定义身份证相同的两个Person对象是相等的。重载equals同时,必须重写hashCode 

Serializable 接口是表明这个对象可以序列化,或者说可以把对象从内存中写入文件,或者通过网络传输。这是EJB规范的要求,保证可以这些对象在网络传输,进行远程调用     
Annotation

                   iii.             @Embeddable @Id

                    iv.             @EmbeddedID(*)

                      v.             @Id @IdClass(*)

核心开发接口介绍

1.        hibernate_0500_CoreAPI

2.        HibernateAPI文档需要单独下载

3.        Configuration

a)        AnnotationConfiguration

b)       进行配置信息的管理

c)        用来产生SessionFactory

d)       可以在configure方法中指定hibernate配置文件

e)        只需关注一个方法即:buildSessionFactory()

4.        SessoinFactory

a)        用来产生和管理Session

b)       通常情况下每个应用只需要一个SessionFactory

c)        除非要访问多个数据库的情况

d)       关注两个方法即:openSessiongetCurrentSession

 

 

                       i.             opensession每次都是新的,需要close

                     ii.             getCurrentSession从上下文找,如果有,用旧的,如果没有,建新的

1.        用途:界定事务边界,它一commit就关闭了这个session.

2.        事务提交自动close

3.        current-session_context_class(jta thread) (java transaction api)

a)       thread
直接使用connection来管理事务,如果异常就会回滚等等。。

上下文是在配置文件里面指定的。

<property name="current_session_context_class">thread</property>

也就是说从当前线程中寻找有没有session,也就是getCurrentSession所说的上下文。一旦提交就关闭了这个session就要再建一个。

openSessiongetCurrentSession是不能混用的。

http://shaqiang32.iteye.com/blog/201918

使用getCurrentSessionSession session = sf.getCurrentSession();

SessionFactory.getCurrentSessionopenSession的区别

SessionFactory.getCurrentSessionopenSession的区别
    1. 
如果使用的是getCurrentSession来创建session的话,在commit后,session就自动被关闭了,
        
也就是不用再session.close()了。但是如果使用的是openSession方法创建的session的话,
        
那么必须显示的关闭session,也就是调用session.close()方法。这样commit后,session并没有关闭
 2. getCurrentSession
的使用可以参见hibernate\hibernate-3.2\doc\tutorial\src项目
 3. 
使用SessionFactory.getCurrentSession()需要在hibernate.cfg.xml中如下配置:
  *
如果采用jdbc独立引用程序配置如下:
    <propertyname="hibernate.current_session_context_class">thread</property>

  * 如果采用了JTA事务配置如下  
    <property name="hibernate.current_session_context_class">jta</property>

 

5.        Session

a)       管理一个数据库的任务单元就是用来管理GRUD的操作。

b)       方法(CRUD)

                       i.             save()---

                     ii.             delete

                   iii.             load:从数据库取一条记录,放到内存中去,把记录转换为相应的对象。

                    iv.             get

getload都可以数据库中取出一条记录放到内存中,然后把记录转为相应的对象,从控制台可以看到,其实就是发出的Select语句。。但它们之间有重要的区别,如下:

                      v.             get与load的区别

1.        不存在对应记录时表现不一样

2.        load返回的是代理对象,等到真正用到对象的内容时才发出sql语句正如控制台所发出的信息一样,你不调用t.getName();load是不会发出select语句的。

Load生成的是一个代理类的对象而不是teacher对象。

3.        get直接从数据库加载,不会延迟,你只要用了get这个方法它就会发出Select语句。

                    vi.             update

1.        用来更新detached对象,更新完成后转为persistent状态

2.        更新transient对象会报错,因为它是刚刚new出的对象还没有往数据库里面存放你这样做肯定会错的。

3.        但是,更新自己设定idtransient对象可以(数据库有对应记录,它必须有记录如果没有记录我们去更新transient状态的东西时,肯定不行。因为这个状态下的数据还没有存到数据库中。)

4.        persistent状态的对象只要设定一个不同字段就会部发生更新

5.        更新部分更改的字段

a)        xml 设定property标签的update属性, annotation设定@Column的updatable属性,不过这种方式很少用,因为不灵活

b)       使用xml中的dynamic-update ,JPA1.0Annotation没有对应的属性,hibernate扩展?<class属性中加上dynamic-update=true>

                                                                 i.             同一个session可以,跨session不行,不过可以用merge() (不重要

c)        使用HQL(EJBQL) (建议)

其实多更新几个字段又如何呢?那也没有什么。

                  vii.             saveOrUpdate():也就是有时做save有时做update

                viii.             clear方法

1.        无论是load还是get,都会首先查找session缓存(一级缓存),如果没有,才会去数据库查找,调用clear()方法可以强制清除session缓存

Grud这几个方法的执行时间是在commit()时间。

flush()方法

2.        可以强制进行从内存到数据库的同步!默认是在commit时间同步的。

3.        FlushMode

                    ix.             find方法已经过时!

6.        SchemaExport:控制建表语句,不在

<property name="hbm2ddl.auto">update</property>
这是在配置文件中

7.        Query接口

a)        参考Hibernate查询(HQL EJBQL)的内容

8.        Note:

a)        Hibernate中涉及很多非常非常细节的区别,但在实际应用中用得极少,请大家先享受写项目的乐趣,再来探讨这些细节问题

                       i.             比如savepersist的区别

                     ii.             mergeevict等方法

                   iii.             比如refreshlock

b)       建议的学习方法,动手实验

c)        细节问题参考补充视频

三种对象状态

1.        上一个project

2.        三种状态的区分关键在于

a)       有没有ID,没有id一定是transient状态。

b)       ID在数据库中有没有

c)        在内存中有没有(session缓存)

Session是内存中的一个对象,这个对象里边保留一个map,map里面有keyvalue

Key记录一个idvalue会记录一个记录对象的引用,此时Save后会保存在数据中,session缓存中也有,这个时间就是persistent.

3.        三种状态:

a)        transient : 内存中一个对象,没ID缓存中也没有//只是new出来一个对象。

b)       persistent: 内存中有,缓存中有, 数据库有(ID)

c)        detached: 内存有,session缓存没有, 数据库有, ID。也就是内存中与数据库中不能通过session缓存连接起来所以叫脱离的状态。想这三个状态时心里要有个图。

此刻内存和数据库中均有,只是没有与session连接。它已经存入了数据库中它什么都有。只是没有与session连接。

4.        对这三种状态需要关注的问题是在该状态下如果进行数据库的操作会发生什么结果,比如改变属性的值会不会发出update语句?

a)        强烈建议动手实验

b)       进行正常人的思考

c)        绝对不要去背这些东西!背过也并不代表你有多牛!

关系映射(绝对重点)

对象之间的关系

1.        这里的关系映射指的是对象之间的关系,并不是指数据库的关系,本章解决的问题是当对象之间处于下列关系之一时,数据库表该如何映射,编程上该如何对待(红色为重点)

2.        简化问题:

a)        怎么写Annotation

b)       增删改查CRUD怎么写

3.        一对一

a)        单向(主键、外键)

b)       双向(主键、外键)

c)        中间表

4.        一对多

a)        单向

b)       双向

5.        多对一

a)        单向

b)       双向

6.        多对多

a)        单向

b)       双向

7.        集合映射

a)        List

b)       Set

c)        Map

8.        继承关系(不重要)

a)        单表

b)       多表

c)        一张主表,多张子表

9.        组件映射

a)        @Embeddable

b)       @Embedded

一对一关联

1.        一对一单向外键关联

a)        项目名称:hibernate_0600_one2one_uni_fk

b)       Annotation: @One2One@JoinColumn

c)        xml: <many-to-one unique=”true”>具体参看项目。

2.    create table Husband (

3.          id integer not null auto_increment,

4.          name varchar(255),

5.         wifeId integer,

6.          primary key (id)

7.      )

8.  16:06:57,140 DEBUG SchemaExport:377 -

9.      create table Wife (

10.         id integer not null auto_increment,

11.         name varchar(255),

12.         primary key (id)

13.     )

14. 16:06:57,234 DEBUG SchemaExport:377 -

15.     alter table Husband

16.         add index FKAEEA401BFC47AC92 (wifeId),

17.         add constraint FKAEEA401BFC47AC92

18.        foreign key (wifeId)

19.              references Wife (id)

这个是Husband表中的wife字段,映射了Wife表中的id。我们只需要在Husband这个表中的这个字段上,写上@One2One,我们如果想改变它自动生成的Wife_id。我们再加上@JoinColumnname=wifeId”)即可。这就完成了一对一的外链映射。
此外我们用了SchemaExport,这时记得把配置文件中的hbm2ddl.auto关闭。

 

20.    一对一双向外键关联

 

双向映射就是指:husband中有wife的对象,wife中有husband的对象。在两边均加上@One2One.但是我们没有必要让它们让它在两个表中均进行外键关联。

我们只想在建表语句中,在一个表中进行外键关联,所以用mappedBy属性来指定只需要在一个表中建立建表语句即可。

只用以一个为主导。另外一个就是被对方设置。

加不加mappedBy,你自己试验加与不加的区别即可。

a)        项目名称:hibernate_0700_one2one_bi_fk

b)       Annotation: @One2One(mappedBy)

c)        xml: <many-to-one unique  <one-to-one property-ref

d)       规律:凡是双向关联,必设mappedBy

21.     一对一单向主键关联(不重要)

a)        项目名称:hibernate_0800_one2one_uni_pk

b)       @PrimaryKeyJoinColumn

c)        xml: <one-to-one id使用foreign class

22.     一对一双向主键关联(不重要)

a)        项目名称:hibernate_0900_one2one_bi_pk

b)       @PrimaryKeyJoinColumn

c)        xml: <one-to-one id使用foreign class 和 <one-to-oneproperty-ref

23.     联合主键

a)        项目名称:hibernate_1000_one2one_uni_fk_composite

b)       @JoinColumns

组件映射

1.        项目:hibernate_1100_component

2.        对象关系:一个对象是另外一个对象的一部分,把两张表里面的东西集成到一张表里面。

3.        数据库表:一张表

4.        annotation: @Embbedable

@Embbeded(嵌入的意思,说明这个是对象是嵌入进来的。)

5.        xml: <component

 

 

 

多对一与一对多

1.        多对一单向关联

在多的这个方向上存在一这个集合。

因为是多对一,所以在多的这一方设置。

a)        项目名称:hibernate_1200_many2one_uni

b)       数据库表设计:在多方加外键

                       i.             错误做法:在一方加冗余

perosnid

personname

dreamid

1

zhangsan

1

1

zhangsan

2

                    

dreamid

dreamdescr

1

earn money

2

eat a lot

c)        annotaion: @Many2One

d)       xml:<many-to-one

既然是多对一,那么无论是annotation还是XML都要设置在多的一方,在多的一方设置对应一个的那个属性。

例如在User里面:设置这个,告诉是多个User对应一个group

其实质是在还是在多的一个生成一个外键。

  @ManyToOne

  @JoinColumn(name="test")

  public Group getGroup() {

    returngroup;

  }

同样在XML中也是在User.hbm.xml设置属性

<many-to-one name="group" column="groupId"></many-to-one>

多对一就是在多的那一边设置,然后去对应那一个。

 

2.        一对多单向关联

在一这个方向上存在多的这个集合。

与数据库最匹配的是Set这个集合。

因为是一对多所以在一的这一方面设置。

a)        项目名称:hibernate_1300_one2many_uni

b)       类:在一的一方存在多方的集合

c)        数据库表同上

d)       annotation:@One2Many

只加@One2Many它会认为存在一张中间表,所以要加上一个@JoinColum

它生成的是多的方面的一个外键。也就是在user里面多了一个外键。

e)        xml:<set <one2many

 

以上12两点,其实质都是在多的一方面生成一个外键,多对一是在User里面写一个Group的属性,而生成的表就是在User表里面多了一个外键,其外键为groupid值。

而一对多是在Group里面写一个User的属性,生成的还是User的一个外键,指向的仍然是groupId.。所以它们的区别就是谁写对方的一个引用对象生成表的实质是一样的。

同样在XML里面也一样在哪边写了对方的属性就在哪边设置XML或者annotation.

 

小技巧:哪边把对方作为一个属性则在哪边设置annotationXML

 

 

 

3.        一对多(多对一)双向关联

只要是双方关系你就写mappedby就行了。所以单向关系中没有这个属性。

双向就是指对方均有双方的对象作为自己的属性。其实质都是在多的一方面生成一个外键

@OneToMany(mappedBy="group")是指拥有这个属性的这一方能够自动维护与Usergroup这个属性的关系。

其实双向就是两边都进行配置,而单向是只配一方即可。

 

4.        在车中持有人的引用

5.        hibernate_0900_many2one_1

6.        结论:不要设置cascade

 

1.        例如:一个人可以拥有多辆车,人中包含车的列表

2.        hibernate_0800_one2many_1

3.        @One2Many

4.        默认在集合上的fetch为LAZY

 

多对多

多对多关联:

1号老师教1号学生

1号老师都2号学生

2号老师都2号学生

则都是在T_S表中写上

1   1  

1         2

2         2

在数据库表中,多对多关联就是这样做的。

1.        单向关联:

a)        项目:hibernate_1500_many2many_uni

b)       例如:老师和学生的关系,老师需要知道自己教了哪些学生,但是学生自己不知道自己被哪些老师教,这在类中体现为Teacher中有学生的集合,学生中没有老师的引用

c)        数据库:中间表

d)       @Many2Many

e)        <many2many

我们生成的表有StudentTeacherTeacher_Student

那个中间表里面有两个属性,一个是Teacher_id,一个是Student_id,它们的外键分别对应两个表中的id

2.        双向关联:

双向是维护通常在多的那一方。

a)        项目:hibernate_1600_many2many_bi

b)       老师知道自己教了哪些学生,学生也知道教自己的有哪些老师

 

总结:

凡涉及到双向要设置mappedby.

关联关系中的CRUD_Cascade_Fetch

要加上u.setGroup(g)你要在内存中给他们设置好关联,否则这两个表还是没有关系的。

既然两个类之间有关联,那么我可不以只存一个user,那么Group对象会不会也相应存进去,结果是的会报错,报的错是不能把一个transient对象存进去。说明默认情况下它不会自动帮你保存,那么我们要在User里面设置一些值。Casecad这时你只用save(g)即可。

Casecad里面用的最多的是,all,merge,persist,remove.  
它是一个Eunm枚举类型。

All:是在所有的情况下都会产生级连。

Persist是在存储的情况下

Merge:合并时间产生

Remove:是在删除的情况下。

 

                                                                              

testSaveGroup这个方法是用来测试我们只存储group时会不会级连user。当然我们还要设置casecad.并且要在告诉hibernate
u1
对象是哪个groupid所以规律就是在多的那一方设置比较简单。

 

如果你的程序是双向的,那么要在双向都要设定双向关联,不然话容易出问题。并且在设定mappedBy.

这样不管你从哪个方向做GRUD都没有问题。

Cascade主管update,delete,修改(alert

Fetchget,load.也就是读取。

Fetcheager是把与关联的对象都从DB取出来,你什么时间调用都行,即使Sesssion关闭了,而lazy不一样,它的关联对象不会被调用出来,如果你不使用它,而你使用它也必须在session关闭之前调用它。这是常见的懒加载错误。

重点在一对多,多对一,多对多,均包含单向和双向。

学习新知识点,一定要动手试。

一般情况下:多对一设置EAGER(因为会把一的一方也取出来),一对多设置LAZY(只取一的一方。)。

我们在这里直接讲的是一对多,多对一的双向。

1.        hibernate_1700_one2many_many2one_bi_crud

2.        设定cascade可以设定在持久化时对于关联对象的操作(CUDRFetch管)

3.        cascade仅仅是帮我们省了编程的麻烦而已,不要把它的作用看的太大

a)        Cascade的属性指明做什么操作的时候关联对象是绑在一起的

b)       refresh = A 里面需要读B改过之后的数据

4.        铁律:双向关系在程序中(指在JAVA代码中,不是annotation中)要设定双向关联    
而且还要在两个bean中加cascade.

5.        铁律:双向必须要设置mappedBy

//如果你的对象是双向的,不用多想,你在程序中写的时间,要设好双向的关联即可,单向的你只用设置好一方的关联即可。不管是在JAVA代码中还是cascade

6.        fetch

a)       铁律:双向不要两边设置Eager(会有多余的查询语句发出)

b)       对多方设置fetch的时候要谨慎,结合具体应用,一般用Lazy不用eager,特殊情况(多方数量不多的时候可以考虑,提高效率的时候可以考虑)

7.        O/RMapping编程模型

a)        映射模型

                       i.             jpa annotation

                     ii.             hibernate  annotation extension

                   iii.             hibernate xml

                    iv.             jpa xml

b)       编程接口

                       i.             jpa

                     ii.             hibernate

c)        数据查询语言(EJBQL是HQL的一个子集,jpa是hibernate的一个子集。)

                       i.             HQL

                     ii.             EJBQL(JPQL)

8.        要想删除或者更新,先做load,除了精确知道ID之外

9.        如果想消除关联关系,先设定关系为null,再删除对应记录,如果不删记录,该记录就变成垃圾数据

10.     练习:多对多的CRUD

a)         

teacher

student

t1

s1

t1

s2

t2

s1

t2

s2

 

关系映射总结

1.        什么样的关系,设计什么样的表,进行什么样的映射

2.        CRUD,按照自然的理解即可(动手测试)实在不行还有HQL语言。

集合映射(不太重要)

1.        项目名称:hibernate_1800_Collections_Mapping

2.        Set

3.        List:可以对结果集进行排序

a)        @OrderBy

4.        Map

a)        @Mapkey

继承映射(不太重要)

1.        三种方式

a)        一张总表SINGLE_TABLE

                       i.             hibernate_1900_Inheritence_Mapping_Single_Table

b)       每个类分别一张表TABLE_PER_CLASS

                       i.             hibernate_2000_Inheritence_Mapping_Table_Per_Class

c)        每个子类一张表 JOINED

                       i.             hibernate_2100_Inheritence_Mapping_JOINED

作业:

树状映射

先考虑数据库结构,再考虑面向对象的设计,再考试GRUD

充分理解它们生成的表的结构,因为它实际上是把多对一和一对多写在一张表上,你在思考时间可以把它理解为两张表。关于其中的细节要想清楚。

 

 

 

1.        学生、课程、分数的设计(重要)

a)        使用联合主键@EmbeddedId

                       i.             实现Serializable接口

b)       不使用联合主键

2.        设计:

a)       实体类(表)

b)       导航(编程方便)

c)        确定了编程方式

 

3.        树状结构的设计(至关重要)

a)       在同一个类中使用One2ManyMany2One

Hibernate查询(QueryLanguage)

HQL vs EJBQL

1.        NativeSQL > HQL >EJBQL(JPQL 1.0) > QBC(Query By Criteria) > QBE(Query By Example)

2.        总结:QL应该和导航关系结合,共同为查询提供服务。

性能优化

1.        注意session.clear()的运用,尤其在不断分页循环的时候

a)        在一个大集合中进行遍历,遍历msg,取出其中的含有敏感字样的对象

b)       另外一种形式的内存泄露 //面试题:Java有内存泄漏吗?

2.        1+ N问题 //典型的面试题

a)        Lazy

b)       BatchSize

c)        join fetch

3.        list 和 iterate不同之处 (//主要为了面试)

a)        list取所有

b)       iterate先取ID,等用到的时候再根据ID来取对象

c)        session 中list第二次发出,仍会到数据库查询

d)       iterate第二次,首先找session级缓存

4.        一级缓存和二级缓存和查询缓存(面试题)

a)        什么是缓存

b)       什么是一级缓存,session级别的缓存

c)        什么是二级缓存,SessionFactory级别的缓存,可以跨越session存在

                       i.             经常被访问

                     ii.             改动不大不会经常改动

                   iii.             数量有限

d)       打开二级缓存

                       i.             hibernate.cfg.xml设定:
<propertyname="cache.use_second_level_cache">true</property>
<property name="cache.provider_class">org.hibernate.cache.EhCacheProvider</property>

                     ii.             @Cache注解

e)        load默认使用二级缓存,iterate默认使用二级缓存

f)        list默认往二级缓存加数据,但是查询的时候不使用

g)       如果要query用二级缓存,需打开查询缓存

                       i.             <propertyname="cache.use_query_cache">true</property>

                     ii.             调用Query的setCachable(true)方法指明使用二级缓存

h)       缓存算法:(纯为了面试)

                       i.             LRU、LFU、FIFO

1.        Least Recently Used

2.        Least Frequently Used(命中率高低)

3.        First In First Out

                     ii.             memoryStoreEvictionPolicy="LRU" (ehcache)

5.        事务并发处理(面试的意义更大)

a)        事务:ACID

                       i.             Atomic Consistency ItegrityDurability

b)       事务并发时可能出现的问题

                       i.             第一类丢失更新(LostUpdate)

时间

取款事务A

存款事务B

T1

开始事务

 

T2

 

开始事务

T3

查询账户余额为1000元    

 

T4

 

查询账户余额为1000元

T5

 

汇入100元把余额改为1100元

T6

 

提交事务

T7

取出100元把余额改为900元

 

T8

撤销事务

 

T9

余额恢复为1000 元

(丢失更新)

 

                     ii.             dirty read脏读

时间

取款事务A

转账事务B

T1

开始事务

 

T2

 

开始事务

T3

    

查询账户余额为1000元

T4

 

汇入100元把余额改为1100元

T5

查询账户余额为1100元
(读取脏数据)

 

T6

 

回滚

T7

取款1100

 

T8

提交事务失败

 

                   iii.             non-repeatable read不可重复读

时间

取款事务A

转账事务B

T1

开始事务

 

T2

 

开始事务

T3

查询账户余额为1000元    

 

T5

 

汇入100元把余额改为1100元

T5

 

提交事务

T6

查询帐户余额为1100元

 

T8

提交事务

 

                    iv.             second lost update problem第二类丢失更新   (不可重复读的特殊情况)

时间

转账事务A

取款事务B

T1

 

开始事务

T2

开始事务

                         

T3

               

查询账户余额为1000元    

T4

查询账户余额为1000元

                         

T5

 

取出100元把余额改为900元

T6

 

提交事务           

T7

汇入100元

 

T8

提交事务

 

T9

把余额改为1100 元
(丢失更新)

 

                      v.             phantom read幻读

时间

查询学生事务A

插入新学生事务B

T1

开始事务

 

T2

 

开始事务

T3

查询学生为10人  

 

T4

 

插入一个新学生

T5

 查询学生为11人

 

T6

 

提交事务

T7

提交事务

 

 

c)        数据库的事务隔离机制

                       i.             查看java.sql.Connection文档

                     ii.             1:read-uncommitted 2: read – committed 4:repeatable read 8:serializable

a)        0001 0010 0100 1000

b)       C      R  U   D

c)        C | U  0101

d)       0101 & 0001 == 0001

2.        只要数据库支持事务,就不可能出现第一类丢失更新

3.        read-uncommitted会出现dirty read, phantom-read,non-repeatable read问题

4.        read-commited 不会出现dirty read,因为只有另一个事务提交才会读出来结果,但仍然会出现non-repeatable read,和phantom-read

5.        repeatable read

6.        serializable解决一切问题

d)       设定hibernate的事务隔离级别

                       i.             hibernate.connection.isolation=2

                     ii.             用悲观锁解决repeatableread的问题(依赖于数据库的锁)

1.        select … for update

2.        load(xx.class, i,LockMode.Upgrade)

a)        LockMode.None 无锁的机制,Transaction结束时,切换到此模式

b)       LockMode.read 在查询的时候hibernate会自动获取锁

c)        LockMode.write insert updatehibernate会自动获取锁     

d)       以上3中锁的模式,是hibernte内部使用的

e)        LockMode.UPGRADE_NOWAIT ORACLE支持的锁的方式

e)        Hibernate(JPA)乐观锁定(ReadCommitted)

                       i.             @Version

时间

转账事务A

取款事务B

T1

 

开始事务

T2

开始事务

                         

T3

               

查询账户余额为1000元 version = 0   

T4

查询账户余额为1000元 version = 0

                         

T5

 

取出100元把余额改为900元 version = 1

T6

 

提交事务           

T7

汇入100元

 

T8

提交事务 ? version > 0

throw exception

 

T9

把余额改为1100 元
(丢失更新)

 

 

 

 

抱歉!评论已关闭.