zoukankan      html  css  js  c++  java
  • Hibernate学习笔记

    Hibernate是轻量级的JavaEE应用的持久层解决方案,Hibernate不仅管理Java类到数据库的映射(包括Java数据类型到SQL数据类型的映射),还提供数据查询和获取数据的方法,可以大幅度缩短使用JDBC处理数据持久化的时间。由于目前主流数据库依然是关系数据库,而Java语言则是面向对象的编程语言,当把二者结合在一起使用时相当麻烦,而正好Hibernate完成对对象模型和基于SQL的关系模型的映射关系。使得应用开发者可以完全采用面向对象的方式来开发应用程序。

    ORM框架作为面向对象编程语言和数据库之间的桥梁,可理解成一种规范,它把关系型数据库包装成面向对象的模型。实际上所有的ORM工具大致上都遵循相同的映射思路,基本映射使用如下映射关系。 数据表映射类,将持久化类映射到一个数据表,数据表的行映射对象,列映射对象的属性,这个过程对于开发者而言是完全透明的,开发者可将精力主要放在以面向对象的思维操作关系数据库。

    一、Hibernate入门

    Hibernate不仅仅管理Java类到数据库表的映射还提供数据查询和获取数据的方法。其使用方法也比较简单。Hibernate的开发流程如下:

    1)开发持久化类,有POJO加映射文件组成;2)获取Configuration;3)获取SessionFactory;4)获取Session,打开事务;5)用面向对象的方式操作数据库;6)关闭事务,关闭Session。

    随着PO与Session的关联关系,PO可有如下三种状态:瞬时状态(自建)、持久类(Session有联系)、脱管(与Session无联系):

    瞬时状态: 如果PO实例从未与Session关联过,我们刚刚把它建立起来,该实例处于瞬态

    持久化:如果我们通过save,commit等方法,将PO实例已经把它与Session关联起来,其已经对应到数据库记录,则该实例处于持久化状态

    脱管状态:如果实例曾与Session关联过,而Session已经被close等原因,脱离了Session的管理,这种状态被称为脱管状态。

    Hibernate通过Session管理PO,只有处于Session管理的POJO才有持久化操作能力,当应用程序对处于Session管理下的POJO实例执行操作时,Hibernate才将次操作转换为持久化操作。下图是Hibernate的体系架构:

     

    其中几个概念的含义如下:

    SessionFactory:这是Hibernate的关键对象。它是单个数据库映射关系经过编译后的内容镜像,它也是线程安全的。它是生成Session的工厂,本身需要依赖于ConnectionProvider。该对象可以在进程或集群的级别上,为那些事务之间可以重用的数据提供可选的二级缓存。

    Session:它是应用程序与持久储存层之间交互操作的一个单线程对象。它也是Hibernate持久化操作的关键对象,所有的持久化对象必须在Session管理下才可以进行持久化操作。此对象生存期很短。它底层封装了JDBC连接,它也是Transaction的工厂。Session对象持有一个必选的一级缓存,显式执行flush之前,所有持久化操作的数据都在缓存中Session对象处。

    持久化对象:系统创建了POJO实例,一旦与特定的Session关联,并对应数据表的指定记录,该对象就处于持久化状态,这一系列对象都被称为持久化对象。在程序中对持久化对象执行的修改,都将自动被转化为持久层的修改。持久化对象完全可以是普通的JavaBeans/POJO,唯一特殊的是它们正与一个Session关联。

    瞬时对象和脱管对象:系统通过new关键字创建的Java实例,没有与Session相关联,此时处于瞬态。瞬态实例可能是在被应用程序实例化后,尚未进行持久化的对象。如果一个曾经持久化的实例,但因为Session的关闭则转化为托管状态。

    事务:代表一次原子操作,它具有数据库事务的概念。Hibernate事务是对底层具体的JDBC、JTA以及CORBA事务的抽象。在某些情况下,一个Session之内可能包含多个Transaction对象。虽然事务操作是可选的,但所有持久化操作都应该在事务管理下进行,即使是只读操作。

    连接提供者:它是生成JDBC连接的工厂,它通过抽象将应用程序与底层的DataSource或者DriverManager隔离开。这个对象无须应用程序直接访问,仅在应用程序需要扩展时使用。 

    二、配置使用

     Hibernate的使用之前需要加入相关的jar包,如果要使用Annotation的话,则除了加入Hibernate的core类库,还要加入ejb3-persistence.jar,hibernate-annotation.jar,hibernate-commons-annotation.jar等到classpath中。下图是Hibernate的工作原理图:

                                     

    Hibernate进行持久化操作离不开SessionFactory对象,这个对象时真个数据库映射关系经过编译后的内存镜像,该对象的openSession方法可打开Session对象,其通过Configuration对象来产生。每个Hibernate配置文件对应一个Configuration对象,我们也可以不使用配置文件,自行创建configuration对象。如果使用了Annotation的话,则我们创建的就是AnnotationConfiguration对象如下:

    sessionFactory = new AnnotationConfiguration().configure( "hibernate.cfg.xml").buildSessionFactory();

    也可以使用hibernate.properties文件作为配置文件,Configuration实例的唯一作用就是创建SessionFactory实例,如下几种创建方法:

    Configuration cfg = new Configuration().addResouce("User.hbm.xml");

    Configuration cfg = new Configuration().addClass("com.demo.domain.user.class");

    如果将映射文件都配置在了hibernate.cfg.xml中,则可以直接创建Configuration实例就行了:

    Configuration cfg = new Configuration().configure();

    还可以通过Configuration的setProperty()方法来配置Hibernate的属性值,下面是hibernate.cfg.xml的配置实例:

     <?xml version='1.0' encoding='utf-8'?>

    <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
    <hibernate-configuration>
    <session-factory>
    <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
    <property name="connection.url">jdbc:mysql:///hibernate</property>
    <property name="connection.username">root</property>
    <property name="connection.password">root</property>
    <property name="dialect">org.hibernate.dialect.MySQLDialect</property>
    <property name="show_sql">true</property>
    <property name="format_sql">true</property>
    <property name="hbm2ddl.auto">create</property>
    <property name="cache.use_second_level_cache">true</property>
    <property name="cache.provider_class">org.hibernate.cache.EhCacheProvider</property>
    <class-cache usage="read-only" class="com.demo.domain.User"/>
    <mapping resource="com/demo/domain/User.hbm.xml" />
    <mapping resource="com/demo/domain/Department.hbm.xml" />
    <mapping resource="com/demo/domain/Employee.hbm.xml" />
    <mapping resource="com/demo/domain/Person.hbm.xml" />
    <mapping resource="com/demo/domain/IdCard.hbm.xml" />
    <mapping resource="com/demo/domain/Teacher.hbm.xml" />
    <mapping resource="com/demo/domain/Student.hbm.xml" />
    <event type="save">
    <listener class="com.demo.hibernate.SaveListener"/>
    </event>
    </session-factory>
    </hibernate-configuration>

     该配置文件可以配置几乎所有的Hibernate属性,jdbc连接属性如hibernate.connection.driver_class,hibernate.connection.url. hibernate.connection.username, hibernate.connection.password,hibernate.connection.pool_size,hibernate.dialect等,jndi数据源的连接属性如hibernate.connection.datasource, hibenate.jndi.url, hibernate.jndi.class 等,hibernate事务属性如hibernate.transaction.factory_class, jta.UserTranaction, hibernate.transaction.auto_close_session, hibernate.transaction.flush_before_completion等,二级缓存相关属性如hibernate.cache.provider_class, hibernate.cache.use_minimal_puts, hibernate.cache.use_query_cache等,还有一些其他常用的配置属性如hibernate.show_sql,hibernate.format_sql,hibernate.hbm2ddl.auto等。

    而对于一个类,我们如果也要将其属性配置成文件内容,其配置文件示例如下:

    <?xml version="1.0" encoding="GB2312"?>

    <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
    <hibernate-mapping package="com.demo.domain">
    <class name="Student">
    <id name="id">
    <generator class="native" />
    </id>
    <property name="name" />
    <set name="teachers" table="teacher_student">
    <key column="student_id" />
    <many-to-many class="Teacher" column="teacher_id" />
    </set>
    </class>
    </hibernate-mapping>

    如果是使用了annotation则不用这样配置了,当然还有其他类型的一些类属性,在下面的映射会有讲到。 

    在Hibernate中经常使用的持久化操作有get,load,save,persist,delete,update,lock,updateOrSave,merge等其中get和load方法功能相同,只是load方法使用了延迟加载,不会立即访问数据库,而对脱管对象的操作经常merge,updateOrSave方法,merge和update的区别在于merge不会持久化对象,而udpate会变对象为持久化;updateOrSave会自动判断对象是否曾经持久化来决定update还是save。

    我们要对Hibernate操作的持久化类建立时遵循如下原则:提供一个无参的构造器,提供一个标识属性,为每个属性提供getter和setter方法,使用非final类,因为Hibernate在运行时使用CGLIB生成代理,代理对象才是持久化类子类的实例,重写equal和hashCode方法(如果需要把持久化类的实例放入set中,则推荐重写)。

    三、集合映射

    下面来讲述Hibernate的映射文件情况,首先是映射文件的结构,每个映射文件的基本结构都是相同的。根元素为<hibernate-mapping.../>,该元素下拥有多个<class...../>子元素,就是说一个文件可以定义多个持久化类,但最好是一个持久化类对应一个映射文件。<hibernate-mapping../>元素可以指定的属性有schema,catalog,default-cascade,default-access,default-lazy,auto-import,package等,此外class也有很多的属性可以设置,如主键映射,普通属性映射等。主键映射使用<id..../>指定,其name属性的值就是持久化类标识属性名,<generate../>指定主键生成方法,主键生成策略有increment, identity, sequence, hilo, seqhilo, uuid, guid, native, assigned, select, foreign, sequence-identity等。普通属性映射使用 <property../>,配置时需要指定一个name属性,为持久类的属性名,如果需要更改存储列名指定column属性。property中的format属性允许对象属性包含表达式,可以运用sum、average、max函数求值的结果。

    集合属性是非常常见的属性,其大致可分为两种,一种是单值集合,一种是多值集合,Hibernate中要持久化的集合值字段必须声明为接口,实际的接口可以是java.util.Set,java.util.Collection,java.util.List,java.util.Map,java.util.SortedMap等,甚至是自定义类型。之所以要用集合接口是因为,Hibernate在持久化实例时,会自动把程序中的集合实现类替换成Hibernate自己的集合实现类,因此不要试图强转类型。以下配置都是实例配置,在实际中可能加入关联映射的配置。

    List是有序集合,因此持久化到数据库时必须增加一列来表示集合元素的次序。如一个学生可以选多门课程,使用list表示多个课程,配置如下:

    <list name="courses" table="course"

    <key column="studentid" not-null="true"/>

    <list-index column="list_order"/>

    <element type="string" column="course_name"/>

    </list>

    类似的配置有array,而对于Set集合时与list有点不同,因为set是无序、不可重复的集合,因此不用使用<list-index../>子元素来映射集合元素的索引列。使用key元素映射外键列,element映射集合属性的元素列,如下:

    <set name="courses" table="course" >

    <key column="student_id" not-null="true"/>

    <element type="string" column="course_name" not-null="true"/>

    </set>

    bag元素既可以映射list集合属性,也可以映射set集合属性,甚至可以映射Collection集合属性,不管哪种集合,它们都将被映射为无序集合,该集合属性对应的表没有主键。 map集合属性需用使用map元素进行映射,当配置map时也需要使用key映射外键列,map还需要映射map key,当map的key是字符串类型、日期类型时,直接使用<map-key../>元素来映射Map key即可。Hibernate将以外键列和key列来作为联合主键。如下:

    <map name="scores" table="score">

    <key column="student_id" not-null="true"/>

    <map-key column="subject" type="string"/>

    <element column="grade" type="float"/>

    </map>

    对于集合属性来讲,如果在初始化时便完成所有集合属性的抓取,将会导致性能急剧下降,因此集合属性通常使用延迟加载策略。所谓延迟加载就是等系统需要使用集合属性时才从数据库装载关联的数据。因此在<set../>,<list../>,<map../>等元素设置 lazy="true"属性来延迟加载。因此有序集合通常根据 key或index访问,无序集合只能遍历。有序集合的属性在增加、删除、修改中拥有较好的性能表现,set次之。由于set语义最贴近关系模型的关联关系,因此Hibernate关联映射通常使用set元素映射。为此我们在设计良好的模型时,通常在one-to-mang的one方设置inverse="true"属性,放弃关系维护,一般只有在set中才使用inverse。

    四、组件映射

    有时候我们希望在映射文件中创建和删除触发器、存储过程等数据库对象,Hibernate提供了<database-object.../>元素来满足这种需求。其有两种使用形式:

    一种是在映射文件中显式声明create和drop命令:

    <hibernate-mapping>

    .... 

    <database-object>

    <create> create trigger t_full_content_gen ...</create>

    <drop> create trigger t_full_content_gen ....</drop> 

    </database-object> 

    </hibernate-mapping> 

    第二种形式是提供一个类,这个类知道如何组织create和drop命令。这个特别类必须要实现org.hibernate.mapping.AuxiliaryDatabaseObject接口。我们还可以通过<dialect-scope../>来指定在什么数据库中使用该配置。

    <hibernate-mapping>

    ....

    <database-object>

    <definition class="MyTriggerDefinition"/> 

    </database-object> 

    <dialect-scope name="XXXXXXX"/> 

    </hibernate-mapping> 

    组件属性的意思是持久化类的属性并不是基本数据类型,也不是字符串、日期等标量类型的变量,而是一个复合类型的对象,在持久化过程中,它仅仅是被当做值类型,而并非引用另一个持久化实体。配置实例如下:

    <component name="name" class="name" unique="true">

    <parent name="owner" />

    <property name="first"  column="first_name"/>

    <property name="last" column="last_name"/>

    </component>

    如果组件属性为List,set,map等集合属性,则我们可以在<component../>元素里使用<list ../>,<set.../>等子元素来映射这些集合属性。

    如果在集合中除了基本类型,还有组件对象,则我们映射集合属性时,依然使用上述的集合元素,只是不再使用<element.../>元素来映射集合元素了,使用<composite-element....>。

    在一些特殊的map中,如果key为复合对象,则Hibernate使用<composite-map-key>来映射复合类型的key,定义一个<composite-map-key>时需要指定一个class属性,其值为Map key的类名。

    如果使用了组件来作为复合主键,组件类必须实现了java.io.Serializable接口,重写了equalshe hashCode方法。Hibernate使用<composite-id.../>来映射这种复合主键,其还可以指定name,class,access,unsaved-value等可选属性。

    五、关联映射

     由于数据库数据之间的关系通常不是孤立存在的,往往存在关联关系,如部门和员工之间,老师和学生之间,订单和订单项之间等。如果我们已经得到一个老师的实例,则可以直接得到这个老师的全部学生,反过来,如果已经得到一个学生,则可以访问该学生对应的全部老师,这种实例之间的关系就是关联关系。通常有单向关系和双向关系之分。

    单向关系:只需单向访问关联端,例如只能通过老师访问学生;双向关系:关联两端都可以互相访问。

     1)N - 1关联

    如person类有个address属性,单向关联只需奥person端找到address就行了,无序关心某个地址的全部用户。

    无连接表的n-1关联配置如下:

    <many-to-one name="address" cascade="all" class="Address" column="address_id" />

     有连接表的n-1关联配置如下:

    <join table ="person_address" >

    <key column="person_id"/>

    <many-to-one name="address" cascade="all" class="Address" column="address_id"/>

    </join>

    2)1 - 1 关联

    但对于单向的1-1关联,需要在持久化类里为关联实体的引用属性增加setter和getter方法,从持久化类上看,单向1-1和单向n-1没有区别,配置也类似,只需要在原有的<many-to-one../>元素增加 unique=“true”属性,用以表示N的一端必须唯一即可。

    基于外键的单向1-1配置如下:

      <many-to-one name="address" cascade="all" unique="true" class="Address" column="address_id" />

    双向的配置再加入类似:<many-to-one name="person" unique="true" column="person_id" not-null="true"/> 

    有连接表的单向1-1配置如下:

    <join table="person_address">

    <key column="person_id" />

    <many-to-one name="address" cascade="all" unique="true" class="Address" column="address_id" />

    </join>

    双向的配置在各自的映射文件中加入相应类似的配置如下:

     <join table="person_address" inverse="true">

    <key column="person_id" unique="true"/>

    <many-to-one name="address" class="Address" column="address_id" unique="true"/>

    </join> 

    基于主键的1-1配置如下:(基于主键关联的持久化类不能拥有自己的主键生成器策略,在表明主键生成时需要指明是foreign)

    <generator class="foreign">

    <param name="property">address</param> 

    </generator>

    <one-to-one name="address"/>

    双向配置类似,只要再在address映射文件中加入<one-to-one name="person"/> 。

    3)1 - N关联

    由于在该关联中要使用集合属性,因此N端将以集合形式出现如: private Set<Address> addresses= new HashSet<Address>();

    无连接表的单向1-n配置如下:

    <set name="addresses">

    <key column="person_id"/>

    <one-to-many class="Address"/>

    </set>

    有连接表的单向1-n配置如下:

    <set name="addresses" table="person_address">

    <key column="person_id"/>

    <many-to-many class="Address" column="address_id" unique="true"/>

    </set>

    对于双向的1-n与n-1类似,n端增加引用到关联实体的属性,1端增加集合属性,集合元素为关联实体,无连接表配置如下:

     person.hbm.xml:  <set name="addresses" inverse="true">

    <key column="person_id"/>

    <one-to-many class="Address"/>

    </set>

    address.hbm.xml: <many-to-one name="person" class="Person" column="person_id" not-null="true"/> 

    对于双向的映射,两者均没有多大变化,加入table属性和join table就便可。

    4)N - N关联

    对于n-n关联必须使用连接表,与有连接表的1-n类似,只是去掉了unique属性,单向配置如下:

    <set name="addresses" table="person_address">

    <key column="person_id" />

    <many-to-many class="Address" column="address_id" />

    </set>

    双向配置在各自的映射文件中加入相应类似的配置:

     <set name="addresses" table="person_address">

    <key column="person_id"/>

    <many-to-many class="Address" column="address_id"/>

    </set>

    我们在现实编码时可能还会遇到很多其他的映射情况,我们可以通过提示查看,很多的配置类似。通常情况下我们要设置级联来说明持久化的传播性,通过cascade来设置。cascade=”all“是指定所有操作都被级联到关联实体中。一般在1-1,1-n中设置级联,因为级联应该是主表记录传播到从表记录。其中delete-orphan策略是只要一个从表实体失去关联对象的主表实体,则从表实体就变成了orphan,系统会自动将其删除。save-update和delete-orphan是在session flush时才会级联到关联对象上。

    六、继承映射

     同样,持久化类之间也会存在继承关系,对于继承关联,Hibernate支持三种继承映射策略来完成关联映射。

    1)采用subclass元素

    此方法是把整个继承树的所有实例映射到同一个表内,此种情况下我们需要加入一列,来区分记录到底是哪个类的实例,这个被称为辨别者discriminator。这种策略的好处就是不要太多的连接。配置如下:

    <class name="person" table="person" discriminator-value="xx">

    ...

    <discriminator column=" category" type="string"/>

    ..

    <subclass name="employ" discriminator-value="yyy">

    ....

    <subclass name="manager" discriminator-value="zzzz">

    ....</subclass>

    </subclass><class>

    2)采用joined-subclass元素

    此策略是父类实例保存在父类表里,子类实例是父类表和子类表共同存储。父类和子类共同的属性保存在父类中,子类中保存增加的属性。此种方法不需要辨别器,但需要key元素映射共有的主键。配置如下:

    <joined-subclass name="employee">

    <key column="empoyee_id"/>
    .....

    <joined-subclass name="manager">

      <key column="manager_id"/>

    ....

    3)采用unio-subclass元素

    这种策略和上种类似,就是子类的属性保存的子类表中,父类的属性保存在父类表中,这种情况下子类表的字段比父类表多。配置如下:

    <union-subclass name="employee" table="employee_inf">

    ....

    <union-subclass name="manager" table="manager_inf">

    ... 

    七、懒加载机制

     Hibernate 的延迟加载(lazy load)是一个被广泛使用的技术。这种延迟加载保证了应用只有在需要时才去数据库中抓取相应的记录。通过延迟加载技术可以避免过多、过早地加载数据表里的数据,从而降低应用的内存开销。Hibernate 的延迟加载本质上就是代理模式的应用,当程序通过 Hibernate 装载一个实体时,默认情况下,Hibernate 并不会立即抓取它的集合属性、关联实体所以对应的记录,而是通过生成一个代理来表示这些集合属性、关联实体,这就是代理模式应用带来的优势。

    对于集合属性,通常推荐使用延迟加载策略。所谓延迟加载就是等系统需要使用集合属性时才从数据库装载关联的数据。 例如Person类持有一个集合属性,集合中的元素为Address,private Set<Address> addressses = new HashSet<Addresss>() 其配文件为:

      <set name="addresses" table="person_address" lazy="true">

    <key column="person_id"/>

    <composite-element class="Address">

    <property name="detail"/>

    <property name="zip"/>

    </composite-element>

    </set>

    上述的配置文件中 lazy=”true“,指定了Hibernate会延迟加载集合属性里的Address对象,我们可以通过debug看到addresses在运行时,其类型并不是我们熟悉的,而是PersistentSet类,这个是Hibernate为Set接口提供的实现类。在延迟加载时,开始 PersistentSet 集合里并不持有任何元素。但 PersistentSet 会持有一个 Hibernate Session,它可以保证当程序需要访问该集合时“立即”去加载数据记录,并装入集合元素。 

    默认情况下,Hibernate也会采取延迟加载技术加载关联实体,不管是哪种关联方式,如果是多个实体(如一对多,多对多等),关联实体以集合形式存在,Hibernate将使用PersistentSet,PersistentMap,PersistentList,PersistentSortedMap,PersistentSortedSet等集合来管理。如果是一个实体(如一对一,多对一等)时,Hibernate延迟的关联实体将是一个动态生成代理对象。还是上面的列子,Person 实体与 Address 实体形成一对多的双向关联,则在执行时会生成一个Person_$$_javassist_0 类的实例,这个类是 Hibernate 使用 Javassist 项目动态生成的代理类——当 Hibernate 延迟加载关联实体时,将会采用 Javassist 生成一个动态代理对象,这个代理对象将负责代理“暂未加载”的关联实体。

    八、SQL查询 

     Hibernate提供非常强大的查询机制,使用Hibernate有多种查询方式可以选择:既可以使用Hibernate的HQL查询,也可以使用条件查询,甚至可以使用原生态的SQL查询语句。还可以使用数据过滤功能,这些都用于筛选目标数据。

    1)HQL查询简单介绍

    HQL(Hibernate Query Language)是一种面向对象的查询语言,HQL的操作对象是类、实例、属性等。使用步骤如下:

    获取Hibernate Session对象->编写HQL语句->以HQL语言作为参数,调用Session的createQuery方法创建查询对象->如果HQL语言包含参数,则调用Query的setXxx方法为参数赋值->调用Query对象的list等方法返回查询结果列表(持久化实体集).如下使用实例:

    List pl = sess.createQuery("select distinct p from Person p " + "inner join p.myEvents event where event.happenDate " + "between :firstDate and :endDate").setDate("firstDate",start).setDate("endDate",new Date()).list();

     其中HQL类似于PreparedStatement的使用占位符作为参数,HQL的占位符即可以使用”?“,也可以使用”:xxx“。Query还可以使用setFirstResult和setMaxResults来进行分页控制。

    2)条件查询

    条件查询是更具面向对象特色的数据查询方式,条件查询通过如下三个类完成:Criteria代表一次查询,Criterion代表一个查询条件,Restrictions产生查询条件的工具类。使用步骤为:获得Hibernate的Session对象->以Session对象创建Criteria对象->使用Restrictions的静态方法创建Criterion查询条件->向Criteria查询中添加Criterion查询条件->执行Criteria的list等方法返回结果集。如下使用实例:

    List l = session.createCriteria(Student.class).add(Restrictions.gt("name","a")).list();

    3)Native SQL查询

    SQL查询是通过SQLQuery接口来表示的。SQLQuery接口是Query接口的子接口,因此完全可以调用Query接口的方法。使用实例如下:

    session.createSQLQuery("select * from student_inf").addScalar("name",StandardBasicTypes.STRING).list()

    List l = session.createSQLQuery(sqlString).addEntity(Enrolment.class).setInteger("year",2013").list()

    Hibernate的查询远比上面也复杂很多,本博客只是介绍简单的使用,具体要用时还需要查资料。 

    九、事务控制

     Hibernate的事务(Transaction对象)是通过Session的beginTransaction()方法显式打开的,Hibernate自身并不提供事务控制行为(没有添加任何附加锁定行为),Hibernate底层直接使用JDBC连接、JTA资源或其他资源的事务。从底层来看,Hibernate的事务由TransactionFactory的实例来产生的。

    TransactionFactory是一个事务工厂的接口,Hibernate为各种不同的事务环境提供了不同的实现类,如CMTTransactionFactory,JDBCTransactionFactory,JTATransactionFactory等,编程时无需自己动手操作TransactionFactory操作事务,因为SessionFactory底层已经封装了TransactionFactory,SessionFactory的创建代价很高,它是线程安全的被设计成多个线程共享,数据库的事务操作应该尽可能得短,从而降低数据库锁定造成的资源争用。

    Hibernate禁止使用自动提交模式,或者让应用服务器禁止事务自动提交。Hibernate建议采用每个请求对应一次Session的模式,因此一次请求通常表示需要执行一个完整的业务功能。在实际应用中经常面对长事务,Hibernate只要有如下三种模式来解决:

    自动版本化:Hibernate能够自动进行乐观并发控制,如果在用户思考的过程持久化实体发生并发修改,Hibernate能够自动检测到。

    脱管对象:如果每次请求对应一次Session的模式,那么之前载入的实例会与Session脱离,Hibernate允许把脱管对象重新关联到Session上,并且对修改进行持久化。在这种模式下,自动版本化被用来隔离并发修改。

    长生命周期Session:Session可以在数据库事务提交之后,断开和底层的JDBC连接。当新的客户端请求到来时,它又重新连接上底层的JDBC连接。

    十、缓存机制 

     Hibernate包括两个级别的缓存:默认总是启用Session级别的一级缓存,可选的SessionFactory级别的二级缓存。当应用保存持久化实例、修改持久化实例时,Session并不会立即把这种改变flush到数据库,而是缓存在当前的Session的一级缓存中,除非显式调用flush方法,或者关闭Session,通过此方法减少与数据库的交互。

    SessionFactory级别的二级缓存是全局性的,应用的所有Session都共享这个二级缓存,默认是关闭的,必须程序显式开启。一旦开启了,当Session需要数据时会优先从二级缓存中抓取。开启方法如下:<property name="hibernate.cache.user_second_level1_cache">true</property>。

    Hibernate的二级缓存一般不需要自己实现,通常使用第三方实现,如EhCacheProvider就是常用的缓存实现。使用缓存时,需要配置一下,还要设置哪些实体类、实体的哪些集合启用二级缓存,配置所需的缓存策略。

    Hibernate提供了一些函数如contain来判断对象是否在缓存中,evict来清除缓存,使用sf.getStatistic().getSecondLevelCacheStatistics()类分析二级缓存的缓存效果。通过setCacheable(boolean)来设置查询缓存,getCacheHitCount()来统计命中次数。

     

    此外在Hibernate中还可以使用过滤器,拦截器,对于大数据量还可以使用批量处理等机制,在此不多介绍。 

    更多的使用方法参看: http://docs.jboss.org/hibernate/core/3.3/reference/en-US/html/index.html

  • 相关阅读:
    iOS 谁说程序猿不懂浪漫之 爱心
    iOS 星星评价视图 3行搞定
    iOS 柱状图的定制
    iOS 跑马灯 一句话集成
    代理的使用
    发送的网络请求中含有中文 转码的实现
    杂记
    使用纯代码实现UICollectionView(UITableView)需要注册
    NSASSert的使用
    iOS进阶第三节 数据处理之CoreData
  • 原文地址:https://www.cnblogs.com/kingcucumber/p/2841928.html
Copyright © 2011-2022 走看看