Hibernate 学习笔记04 --核心开发接口

1、知识点:

1)        Configuration

a)         AnnotationConfiguration

b)        进行配置信息的管理

c)         用来产生SessionFactory

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

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

2)        SessionExport

3)        SessionFactory接口

a)         用来产生和管理Session

b)        通常情况下每个应用只需要一个SessionFactory,除非要访问多个数据库的情况

c)         关注两个方法,即:openSession,getCurrentSession

                        i.             openSession每次都是新的,需要手动close

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

1.         用途:界定事务边界

2.         事务提交自动close(手动close反而可能出错)

3.         currentSession_context_class(jta 或thread)

a)         thread使用connection

b)        jta(java transaction API):使用多个DB处理事务。由middleware和Application Server支持此功能

                                                                  i.             Tomcat暂时不支持此功能,可结合Spring支持

                                                                 ii.             JBoss和weblogic支持此功能

4)        Session接口

a)         管理一个数据库的任务单元

b)        方法(CRUD)

                        i.             save()

                       ii.             delete

                     iii.             load

                     iv.             get

                       v.             get与load的区别

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

2.         load返回的是代理对象,等到真正用到对象的内容时才发出sql语句

3.         get直接从数据库加载,不会延迟

                     vi.             update

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

2.         更新transient对象会报错

3.         更新自己设定id的transient对象可以(数据库有对应记录)

4.         更新部分更改的字段

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

b)        使用xml中的dynamic-update,JPA1.0 Annotation没有对应的属性,hibernate扩展有?未实验。

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

c)         使用HQL(EJBQL)(建议的方法)

                    vii.             saveOrUpdate()

                  viii.             find方法已经过时

                     ix.             clear方法

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

                       x.             flush()方法

1.         可以强制进行从内存到数据库的同步!

2.         flushMode

5)        SchemaExport

6)        Query接口

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

7)        Note:

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

                        i.             比如save和persistent的区别

                       ii.             merge、evict等方法

                     iii.             比如refresh、lock等

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

c)         细节问题参考其他文章

2、三种状态

         三种对象状态图如下:

1、  三种状态的区分关键在于:

a)         有没有ID,没有则肯定为Transient状态;

b)        ID在数据库中有没有;

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

2、  三种状态:

a)         Transient:内存中一个对象,没ID,缓存中也没有;

b)        Persistent:内存中没有,缓存中有,数据库有(ID);

c)         Detached:内存中有,缓存没有,数据库有(ID);

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

a)         强烈建议动手实验;

b)        进行正常人的思考;

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

4、  调用flush()方法可以强制进行从内存到数据库的同步!

3、Session初探

3.1、取得会话

       在Hibernate中,有org.hibernate.Session这一个接口,对于其实现类主要有两种:SessionFactory接口中的open()方法和getCurrentSession()方法。其中openSession ()属于旧方法,所以不推荐使用,而推荐使用getCurrentSession()。

       两个方法的比较,openSession()每次都建立一个新会话,明显会占用更多的资源;而getCurrentSession()只有在上下文中找不到存在的会话才会建立新会话。

       既然上面提到了getCurrentSession()需要查找上下文,那当然在使用getCurrentSession()方法之前,需要配置hibernate.cfg.xml文件,添加以下内容:

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

       其中,可选项有jta、thread、managed和custom.Class。常用的有thread,而jta用于分布式(多个数据库共同处理事务)。

         下面这段代码为了说明openSession()和getCurrentSession()的区别。

package com.wolex.hibernate.model;

import org.hibernate.Session;

import org.hibernate.SessionFactory;

import org.hibernate.cfg.Configuration;

 

public class HibernateCoreAPITest {

    @SuppressWarnings("deprecation")

    public static void main(String[] args) {

        Configuration cf = new Configuration();

        cf.configure();

        SessionFactory sf;

        sf = cf.buildSessionFactory();

        // 以上方法虽然不建议使用,但不影响此次实验

        Session session01 = sf.openSession();

        Session session02 = sf.getCurrentSession();

        Session session03 = sf.openSession();

        Session session04 = sf.getCurrentSession();

        session01.beginTransaction();

        session02.beginTransaction();

        session03.beginTransaction();

        try {

            // 当前事务只能开始一次,此处不支持嵌套事务!

            session04.beginTransaction();

        } catch (Exception e1) {

            e1.printStackTrace();

        }

        System.out.print("session01 equals session02? ");

        System.out.println(session01 == session02 ? "YSE!" : "NO!");

        System.out.print("session01 equals session03? ");

        System.out.println(session01 == session03 ? "YSE!" : "NO!");

        System.out.print("session02 equals session04? ");

        System.out.println(session02 == session04 ? "YSE!" : "NO!");

        session01.close();

        session02.getTransaction().commit();// 相当于关闭

        session03.close();

        try {

            // 出错!因为currentSession只能关闭一次

            session03.getTransaction().commit();

        } catch (Exception e) {

            e.printStackTrace();

        }

        sf.close();

    }

}

org.hibernate.TransactionException: nested transactions not supported

     at org.hibernate.engine.transaction.spi.AbstractTransactionImpl.begin(AbstractTransactionImpl.java:152)

     at org.hibernate.internal.SessionImpl.beginTransaction(SessionImpl.java:1426)

     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)

     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)

     at java.lang.reflect.Method.invoke(Method.java:597)

     at org.hibernate.context.internal.ThreadLocalSessionContext$TransactionProtectionWrapper.invoke(ThreadLocalSessionContext.java:352)

     at $Proxy4.beginTransaction(Unknown Source)

     at com.wolex.hibernate.model.HibernateCoreAPITest.main(HibernateCoreAPITest.java:24)

session01 equals session02? NO!

session01 equals session03? NO!

session02 equals session04? YSE!

org.hibernate.SessionException: Session is closed!

     at org.hibernate.internal.AbstractSessionImpl.errorIfClosed(AbstractSessionImpl.java:129)

     at org.hibernate.internal.SessionImpl.getTransaction(SessionImpl.java:1419)

     at com.wolex.hibernate.model.HibernateCoreAPITest.main(HibernateCoreAPITest.java:39)

2013-6-10 21:00:21 org.hibernate.service.jdbc.connections.internal.DriverManagerConnectionProviderImpl stop

INFO: HHH000030: Cleaning up connection pool [jdbc:oracl:thin:@192.168.0.155:1521:daocn]

         由上面实验可得,openSession()建立的会话,和之后getCurrentSession()取得的会话是不一样的,那为什么呢?不是说getCurrentSession()是取得当前存在的会话吗?

         因为org.hibernate.Session只是一个接口,而openSession()和getCurentSession()是属于SessionFactory接口中两种不同的实现Session接口的方法,所以这两种方法取得的会话当然就不会相等。

总结,openSession()每次打开的都是新的会话,所以每次都需调用beginTransaction()方法,每个使用openSession()打开的会话都需要close()。而使用getCurrentSession()取得的会话,能且只能在一个程序中调用一次beginTransaction(),而且每当执行commit时(也是只能commit一次),相当于关闭了会话,不能再调用close()方法。

         经过实验,每次执行完数据库的操作时,都必须关闭Session接口,之后再关闭SessionFactory接口,这样才彻底,干净。因为连接数据库属于资源操作,所以必须释放资源。实验发现,如果只关闭SessionFactory接口,而不关闭Session接口,数据库中的会话还是处于连接的状态。虽然程序执行完毕之后,会自动关闭所有会话,但还是建议在不需要连接数据库时就关闭会话,以降低数据库并发量(负担)。

3.2、save()方法

我们拿之前的Teacher类做测试,分别打印三种状态下Teacher类的id属性。

package com.wolex.hibernate.model;

import java.util.Date;

import org.hibernate.Session;

import org.hibernate.tutorial.util.HibernateUtil;

import com.wolex.hibernate.model.Teacher;

 

public class TeacherTest {

    public static void main(String[] args) {

        // 实例化new时候,对象tea处于Transient状态:

        Teacher tea = new Teacher();

        tea.setName("Kelly");

        tea.setTitle("初级");

        tea.setBirthday(new Date());

        tea.setSex(Sex.FEMALE);

        System.out.println("Transient: " + tea.getId() + "," + tea.getName());

        Session session = HibernateUtil.getSessionFactory().getCurrentSession();

        // save()执行完毕后变为Persistent状态:

        session.beginTransaction();

        session.save(tea);

        System.out.println("Persistent: " + tea.getId() + "," + tea.getName());

        // 会话关闭后变为Detached状态:

        session.getTransaction().commit();

        System.out.println("Detached: " + tea.getId() + "," + tea.getName());

        HibernateUtil.getSessionFactory().close();

    }

}

Transient: 0,So_Yeon

2013-6-10 21:49:22 org.hibernate.annotations.common.Version <clinit>

INFO: HCANN000001: Hibernate Commons Annotations {4.0.2.Final}

……

2013-6-10 21:49:23 org.hibernate.tool.hbm2ddl.SchemaExport execute

INFO: HHH000227: Running hbm2ddl schema export

Hibernate:

    drop table teachers cascade constraints

Hibernate:

    drop sequence teacher_seq_db

Hibernate:

    create table teachers (

        id number(10,0) not null,

        birthday timestamp,

        tname varchar2(20 char),

        sex varchar2(10 char),

        title varchar2(10 char),

        primary key (id)

    )

Hibernate:

create sequence teacher_seq_db

2013-6-10 21:49:23 org.hibernate.tool.hbm2ddl.SchemaExport execute

INFO: HHH000230: Schema export complete

Hibernate:

    select

        teacher_seq_db.nextval

    from

        dual

Persistent: 1,So_Yeon

Hibernate:

    insert

    into

        teachers

        (birthday, tname, sex, title, id)

    values

        (?, ?, ?, ?, ?)

Detached: 1,So_Yeon

         这里重点是观察三种状态打印的位置。了解save()的意义。

3.3、delete()方法

         由三种对象状态图可知,只有在Persistent状态下会话才能执行delete()方法,如下:

package com.wolex.hibernate.model;

import java.util.Date;

import org.hibernate.Session;

import org.hibernate.tutorial.util.HibernateUtil;

import com.wolex.hibernate.model.Teacher;

 

public class TeacherTest {

    public static void main(String[] args) {

        // Transient状态:

        Teacher tea = new Teacher();

        tea.setName("So_Yeon");

        tea.setTitle("初级");

        tea.setBirthday(new Date());

        tea.setSex(Sex.FEMALE);

        Session session = HibernateUtil.getSessionFactory().getCurrentSession();

        session.beginTransaction();

        session.save(tea);

        // save()后,对象为Persistent状态,此状态下才能执行delete()

        session.delete(tea);

        session.getTransaction().commit();

        HibernateUtil.getSessionFactory().close();

    }

}

Hibernate:

    select

        teacher_seq_db.nextval

    from

        dual

Hibernate:

    insert

    into

        teachers

        (birthday, tname, sex, title, id)

    values

        (?, ?, ?, ?, ?)

Hibernate:

    delete

    from

        teachers

    where

        id=?

         而执行完delete()后,对象会变为Transient状态。

3.4、load()与get()方法

         在Session接口中,其中有load()与get()方法比较类似。而load()与get()方法都有很多重载,详细请参考Hibernate API文档。下面介绍比较常用的方法,引自API文档:

●  Object load(Class theClass, Serializable id):

Return the persistentinstance of the given entity class with the given identifier, assuming that theinstance exists. This method might return a proxiedinstance that is initialized on-demand, when a non-identifier method isaccessed.

 

You should not use this method to determine if an instance exists (useget() instead). Use this only to retrieve an instancethat you assume exists, where non-existence would be an actual error.

Parameters:

theClass - a persistent class

id - a valid identifier of anexisting persistent instance of the class

Returns:

the persistent instance or proxy

●  Object get(Class clazz, Serializable id):

Return the persistentinstance of the given entity class with the given identifier, or null if thereis no such persistent instance. (If the instance is already associated with thesession, return that instance. This method never returns an uninitializedinstance.)

Parameters:

clazz - a persistent class

id - an identifier

Returns:

a persistent instance or null

         说明,如果你确定一个instance(在这里,我理解为给定的类和其ID能返回表的一行记录)存在,则可以使用load()方法,否则别用,因为如果instance不存在,则会返回错误;所以,如果你不确定这个instance是否存在,则可以使用get()方法,因为如果instance不存在,get()方法返回null。还有一点,load()方法返回的是代理对象,而至于什么是代理对象,请参考设计模式中的动态代理。

         测试get()与load()的区别:

package com.wolex.hibernate.model;

 

import org.hibernate.Session;

import org.hibernate.tutorial.util.HibernateUtil;

import com.wolex.hibernate.model.Teacher;

 

public class TeacherTest {

    public static void main(String[] args) {

        Session session = HibernateUtil.getSessionFactory().getCurrentSession();

        session.beginTransaction();

        if (session.get(Teacher.class, 1000) == null) {

            System.out.println("No date retrieved!");

        }

        try {

            System.out.println(session.load(Teacher.class, 999));

        } catch (Exception e) {

            e.printStackTrace();

        }

        session.getTransaction().commit();

        HibernateUtil.getSessionFactory().close();

    }

}

Hibernate:

    select

        teacher0_.id as id1_0_0_,

        teacher0_.birthday as birthday2_0_0_,

        teacher0_.tname as tname3_0_0_,

        teacher0_.sex as sex4_0_0_,

        teacher0_.title as title5_0_0_

    from

        teachers teacher0_

    where

        teacher0_.id=?

No date retrieved!

Hibernate:

    select

        teacher0_.id as id1_0_0_,

        teacher0_.birthday as birthday2_0_0_,

        teacher0_.tname as tname3_0_0_,

        teacher0_.sex as sex4_0_0_,

        teacher0_.title as title5_0_0_

    from

        teachers teacher0_

    where

        teacher0_.id=?

Exception in thread "main" org.hibernate.ObjectNotFoundException: No row with the given identifier exists: [com.wolex.hibernate.model.Teacher#999]

     at org.hibernate.internal.SessionFactoryImpl$1$1.handleEntityNotFound(SessionFactoryImpl.java:244)

     at org.hibernate.proxy.AbstractLazyInitializer.checkTargetState(AbstractLazyInitializer.java:261)

     at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:175)

     at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:285)

     at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:185)

     at com.wolex.hibernate.model.Teacher_$$_javassist_0.toString(Teacher_$$_javassist_0.java)

     at java.lang.String.valueOf(String.java:2827)

     at java.io.PrintStream.println(PrintStream.java:771)

     at com.wolex.hibernate.model.TeacherTest.main(TeacherTest.java:17)

         从以上程序可以看出,get()方法即使没有找到ID对应的行,也不返回错误而是返回null;而load()方法如果没有找到对应ID的行,则直接返回错误。

         观察程序执行结果中发出的SQL语句,可以发现,Hibernate默认都会给表起个别名,在这里我们暂且不深入研究为什么这样做,这是否会影响SQL调优等等?

         注意:以上程序是在Hibernate 4.0.2.Final中测试的结果。此时我们都打印了get()和load()方法的结果,所以Hibernate才会发出SQL语句,但如果我们不打印他们的结果呢,只是分别调用这两个方法得到Teacher类的对象呢?

         下面测试当只调用get()与load()方法进行构造对象,观察结果。

package com.wolex.hibernate.model;

import org.hibernate.Session;

import org.hibernate.tutorial.util.HibernateUtil;

 

public class TeacherTest02 {

    public static void main(String[] args) {

        Session session = HibernateUtil.getSessionFactory().getCurrentSession();

        session.beginTransaction();

        Teacher tea1 = (Teacher) session.get(Teacher.class, 1);

        System.out.println("==========:END OF get()==========");

        Teacher tea2 = (Teacher) session.load(Teacher.class, 2);

        System.out.println("==========:END OF load()==========");

        Teacher tea3 = (Teacher) session.get(Teacher.class, 3333);//不存在ID

        System.out.println("==========:END OF get()==========");

        Teacher tea4 = (Teacher) session.load(Teacher.class, 4444);//不存在ID

        System.out.println("==========:END OF load()==========");

        session.getTransaction().commit();

        HibernateUtil.getSessionFactory().close();

    }

}

 忘记粘贴结果………

         上面实验对get()和load()方法都分别执行了两次,一次是ID存在的,一次是ID不存在的情况。由以上的输出结果可以发现,每次只要执行get()方法,Hibernate就会立刻发出SQL语句,而执行load()方法时,由于返回的是代理,所以Hibernate并不会立刻发出SQL,只会等到需要的时候才执行SQL语句。程序中后两次执行说明,即使ID不存在的,get()load()方法都不会立刻返回错误信息

         综合运用,测试将构造对象与打印对象信息分开,观察get()与load()方法的区别。

package com.wolex.hibernate.model;

import org.hibernate.Session;

import org.hibernate.tutorial.util.HibernateUtil;

import com.wolex.hibernate.model.Teacher;

 

public class TeacherTest {

    public static void main(String[] args) {

        Session session = HibernateUtil.getSessionFactory().getCurrentSession();

        session.beginTransaction();

        Teacher tea1 = (Teacher) session.get(Teacher.class, 1);

        System.out.println("After constructing object--tea1.");

        System.out.println("Print imformation of tea1: "

                + tea1.getClass().getName());

        try {

            Teacher tea2 = (Teacher) session.load(Teacher.class, 3);

            System.out.println("After constructiong object--tea2.");

            System.out.println("Print imformation of tea2: "

                    + tea2.getClass().getName());

            System.out.println("=========================");

            System.out.println("Print directly the object--tea2: " + tea2);

            System.out.println("*************************");

        } catch (Exception e) {

            e.printStackTrace();

        }

        session.getTransaction().commit();

        HibernateUtil.getSessionFactory().close();

    }

}

Hibernate:

    select

        teacher0_.id as id1_0_0_,

        teacher0_.birthday as birthday2_0_0_,

        teacher0_.tname as tname3_0_0_,

        teacher0_.sex as sex4_0_0_,

        teacher0_.title as title5_0_0_

    from

        teachers teacher0_

    where

        teacher0_.id=?

After constructing object--tea1.

Print imformation of tea1: com.wolex.hibernate.model.Teacher

After constructiong object--tea2.

Print imformation of tea2: com.wolex.hibernate.model.Teacher_$$_javassist_0

=========================

Hibernate:

    select

        teacher0_.id as id1_0_0_,

        teacher0_.birthday as birthday2_0_0_,

        teacher0_.tname as tname3_0_0_,

        teacher0_.sex as sex4_0_0_,

        teacher0_.title as title5_0_0_

    from

        teachers teacher0_

    where

        teacher0_.id=?

Print directly the object--tea2: com.wolex.hibernate.model.Teacher@7b48392

*************************

         输出结果信息较多,请仔细阅读。上面的执行结果也说明了get()方法是马上在后台发出SQL语句的。而load()在上面实验中只有执行直接输出tea2对象信息时,才会发出SQL语句,而执行“tea2.getClass().getName()”此语句时也不会发出SQL语句,原因是为什么呢?

同时我们可以看到“tea2.getClass().getName()”返回的结果是“Teacher_$$_javassist_0”这个javassist其实就是Hibernate中的一个专门生成动态代理的类库。此程序中,Teacher_$$_javassist_0是Teacher的子类,继承于Teacher类。

         还有,上面程序中如果我们把“session.load(Teacher.class, 3) ”中的3改为“1”,则整个程序中只会发出一次SQL语句,这应该是Hibernate中对SQL语句重用的机制。

         By now,我们已经深深觉得Hibernate中有不少小细节,其实在学习过程中不必要excessively纠结、死抠这些细节。

3.5、update()方法

       关于update()方法在Hibernate4的API文档中如此描述:
Ÿ  update :

void update(String entityName,

          Object object)

Update the persistent instance with theidentifier of the given detached instance. If there is a persistent instance withthe same identifier, an exception is thrown. This operation cascades toassociated instances if the association is mapped with cascade="save-update"

Parameters:

entityName - The entity name

object - a detached instance containing updated state

 

       其中,entityName可选。文档大概意思,指定一个带有ID的detached实例,使用update()将其更新为persistent实例。但实验中可以发现,不管什么状态下的对象都可以执行update()方法,只是有不少细节的区别,下面一一实验。

       对象处于Transient状态时,更新ID为1的数据,只更新tname字段,观察结果。

SQL> SELECT * FROM teachers;

        ID BIRTHDAY                       TNAME           SEX       TITLE

---------- ------------------------------ --------------- --------------------

         1 22-OCT-12 12.00.00.000000AM   Theresa         FEMALE     高级

         2 08-JUN-1312.00.00.000000 AM   Angelababy      FEMALE    中级

         3 08-JUN-1311.49.28.434000 PM   Selina          FEMALE     初级

         4 08-JUN-1311.49.51.160000 PM   Kelly           FEMALE     初级

         5 10-JUN-1311.05.08.828000 PM   So_Yeon         FEMALE     初级

       程序如下:

package com.wolex.hibernate.model;

import org.hibernate.Session;

import org.hibernate.tutorial.util.HibernateUtil;

import com.wolex.hibernate.model.Teacher;

 

public class TeacherTest {

    public static void main(String[] args) {

        Teacher tea = new Teacher();

        tea.setId(1);

        tea.setName("kym");

        tea.setBirthday(new java.util.Date());

        Session session = HibernateUtil.getSessionFactory().getCurrentSession();

        session.beginTransaction();

        session.update(tea);

        session.getTransaction().commit();

        HibernateUtil.getSessionFactory().close();

    }

}

Hibernate:

    update

        teachers

    set

        birthday=?,

        tname=?,

        sex=?,

        title=?

    where

        id=?

       更新完毕,观察数据库中teachers表:

SQL> SELECT * FROM teachers;

        ID BIRTHDAY                       TNAME           SEX        TITLE

---------- ------------------------------ --------------- --------------------

         1                                kym

         2 08-JUN-1312.00.00.000000 AM   Angelababy      FEMALE    中级

         3 08-JUN-1311.49.28.434000 PM   Selina          FEMALE     初级

         4 08-JUN-1311.49.51.160000 PM   Kelly           FEMALE     初级

         5 10-JUN-1311.05.08.828000 PM   So_Yeon         FEMALE     初级

         首先,需要注意的是,对象tea调用setId()设置ID值时,数据库里面一定要存在此ID值,否则在执行update()方法时就会报错。

可以看到,执行更新的时候,Hibernate把ID=1的所有字段都更新了,而且如果在程序中没有setter的字段,则默认更新为空,明显这并不是我们想要的。要想指定Hibernate只更新程序中setter过的属性对应的表字段,则需要在Persistent和Detached状态下进行save()方法。

更新对象处于Detached状态时的情况。更新ID为2的数据,更新前查询:

SQL> SELECT * FROM teachersWHERE id=2;

        ID BIRTHDAY                       TNAME           SEX        TITLE

---------- ------------------------------ --------------- --------------------

         2 08-JUN-1311.49.05.077000 PM   kym             FEMALE     中级

         程序如下:

package com.wolex.hibernate.model;

import org.hibernate.Session;

import org.hibernate.tutorial.util.HibernateUtil;

import com.wolex.hibernate.model.Teacher;

 

public class TeacherTest {

    public static void main(String[] args) {

        Session session = HibernateUtil.getSessionFactory().getCurrentSession();

        session.beginTransaction();

         Teacher tea = (Teacher) session.get(Teacher.class, 2);

        // get()方法之后,对象tea处于Persistent状态

        session.getTransaction().commit();

        // commit()之后,tea对象此时处于Detached状态

        Session session2 = HibernateUtil.getSessionFactory()

                .getCurrentSession();

        session2.beginTransaction();

        // 此時對象處於Detached狀態

        tea.setName("Angelababy");

        session2.update(tea);

        // update()后,tea对象此时处于Persistent状态

        session2.getTransaction().commit();

        // commit()后,Detached state.

        HibernateUtil.getSessionFactory().close();

    }

}

         查询teachers表:

SQL> SELECT * FROM teachersWHERE id=2;

        ID BIRTHDAY                       TNAME           SEX        TITLE

---------- ------------------------------ --------------- --------------------

         2 08-JUN-1312.00.00.000000 AM   Angelababy      FEMALE     中级

当对象处于Persistent状态下,更新teachers表ID为1的数据,更新前查询:

SQL> SELECT * FROM teachersWHERE id=1;

        ID BIRTHDAY                       TNAME           SEX        TITLE

---------- ------------------------------ --------------- --------------------

         1 08-JUN-1311.43.52.944000 PM   Jolin           FEMALE    高级

         程序如下,将“Jolin”改为“Cyndi Wang”。

package com.wolex.hibernate.model;

import org.hibernate.Session;

import org.hibernate.tutorial.util.HibernateUtil;

import com.wolex.hibernate.model.Teacher;

 

public class TeacherTest {

    public static void main(String[] args) {

        Session session = HibernateUtil.getSessionFactory().getCurrentSession();

        session.beginTransaction();

        Teacher tea = (Teacher) session.get(Teacher.class, 1);

        // get()后,tea对象此时处于Persistent状态

        tea.setName("Cyndi Wang");

        session.update(tea);

        // update()后,仍然处于Persistent状态

        session.getTransaction().commit();

        // commit()后,tea对象此时处于Detached状态

        HibernateUtil.getSessionFactory().close();

    }

}

Hibernate:

    select

        teacher0_.id as id1_0_0_,

        teacher0_.birthday as birthday2_0_0_,

        teacher0_.tname as tname3_0_0_,

        teacher0_.sex as sex4_0_0_,

        teacher0_.title as title5_0_0_

    from

        teachers teacher0_

    where

        teacher0_.id=?

Hibernate:

    update

        teachers

    set

        birthday=?,

        tname=?,

        sex=?,

        title=?

    where

        id=?

     更新成功,查询teachers表:

SQL> SELECT * FROM teachersWHERE id=1;

        ID BIRTHDAY                       TNAME           SEX        TITLE

---------- ------------------------------ --------------- --------------------

         1 08-JUN-1311.43.52.944000 PM   Cyndi Wang      FEMALE     高级

         从结果中可以发现,如果对象处于Persistent状态或Detached状态下,更新对象会成功,而且只有在程序中修改过的属性对应的表字段才会更新。

从Hibernate发出的update语句可以看到,update语句还是把teachers表的全部数据都更新了,而不仅仅是更新修改过的数据。同时问题来了,为什么在程序中没有修改过的属性,经过update语句后,还能保持之前的值呢?

其实,全部字段都更新了而且这种更新(这里使用get()load()方法使对象处于Persistent状态)只会更新修改过的数据(如,这里是setName(“CyndiWang”)),前提是使对象处于Persistent状态或Detached状态,因为这两种状态下表明缓存中是存在对象信息的(将相应表中一行的每个字段信息映射到对象中),观察以下一段代码即可demonstrate它:

package com.wolex.hibernate.model;

import org.hibernate.Session;

import org.hibernate.tutorial.util.HibernateUtil;

import com.wolex.hibernate.model.Teacher;

 

public class TeacherTest {

    public static void main(String[] args) {

        Session session = HibernateUtil.getSessionFactory().getCurrentSession();

        session.beginTransaction();

        Teacher tea = (Teacher) session.get(Teacher.class, 2);

        // get()方法之后,对象tea处于Persistent状态

        System.out.println("Persistent object state:" + tea.getId() + ", "

                + tea.getName() + ", " + tea.getTitle());

        session.getTransaction().commit();

        // commit()之后,tea对象此时处于Detached状态

        System.out.println("Detached object state:" + tea.getId() + ", "

                + tea.getName() + ", " + tea.getTitle());

        HibernateUtil.getSessionFactory().close();

    }

}

Hibernate:

    select

        teacher0_.id as id1_0_0_,

        teacher0_.birthday as birthday2_0_0_,

        teacher0_.tname as tname3_0_0_,

        teacher0_.sex as sex4_0_0_,

        teacher0_.title as title5_0_0_

    from

        teachers teacher0_

    where

        teacher0_.id=?

Persistent object state:2, Angelababy, 中级

Detached object state:2, Angelababy, 中级

         由上可知,如果对象处于Persistent或Detached状态,程序确实打印出了teachers表的对应信息。因此也就很容易理解为什么Hibernate能只更新程序中修改过(setter)的属性对应的表字段的同时,而保证没修改的数据不变。

         这其实有带来了一个问题,既然有部分属性在程序中没修改,那干嘛在执行update()方法时发出的update语句还要把表的全部字段都更新一遍呢?这不是吃力不讨好吗?

         要想解决这儿问题,有以下三种方法:

u  XML中设置property标签,Annotation中设置@Column(updatable=false);

u  XML中设置dynamic-update,JPA对应注解未发现;

u  使用HQL;

由于方法一十分不灵活,每次都要手工修改;方法二无法在跨会话的时候使用,即使可以使用merge()方法弥补,但也不自然,所以我们着重学习第三种方法。此次实验也只测试第三种方法。

下面我们使用HQL更新teacher表中ID=3的行,更新前查询:

SQL> SELECT * FROM teachersWHERE id=3;

        ID BIRTHDAY                      TNAME           SEX        TITLE

---------- ------------------------------ --------------- --------------------

         3 08-JUN-1311.49.28.434000 PM   Selina          FEMALE     初级

使用HQL实现更新字段:

package com.wolex.hibernate.model;

import org.hibernate.Query;

import org.hibernate.Session;

import org.hibernate.tutorial.util.HibernateUtil;

 

public class TeacherTest {

    public static void main(String[] args) {

        Session session = HibernateUtil.getSessionFactory().getCurrentSession();

        session.beginTransaction();

        Query q = session

                .createQuery("update Teacher s set s.name='Charlene Choi' where s.id=3");

        q.executeUpdate();

        session.getTransaction().commit();

        HibernateUtil.getSessionFactory().close();

    }

}

Hibernate:

    update

        teachers

    set

        tname='Charlene Choi'

    where

        id=3

 

         使用HQL中Query接口时需要注意的是,导入的包是org.hibernate.Query!

更新后的数据库:

SQL> SELECT * FROM teachersWHERE id=3;

        ID BIRTHDAY                       TNAME           SEX        TITLE

---------- ------------------------------ --------------- --------------------

         3 08-JUN-13 11.49.28.434000 PM   Charlene Choi   FEMALE    初级

         关于更多HQL的使用语法以后再详谈,现在大概有个印象就行。

3.6、saveOrUpdate()方法

 

 

         程序执行前,teachers表:

SQL> SELECT * FROM teachers;

        ID BIRTHDAY                       TNAME           SEX             TITLE

---------------------------------------- --------------- --------------- ---------------

         1 13-JUN-13 12.00.00.000000 AM   Mary

         2 08-JUN-13 12.00.00.000000 AM   Angelababy      FEMALE          中级

         3 08-JUN-13 11.49.28.434000 PM   Charlene Choi   FEMALE          初级

         4 13-JUN-13 12.00.00.000000 AM   Coco

         5 10-JUN-13 11.05.08.828000 PM   So_Yeon         FEMALE          初级

         编写测试类:

package com.wolex.hibernate.model;

import org.hibernate.Session;

import org.hibernate.tutorial.util.HibernateUtil;

 

public class TeacherTest {

    public static void main(String[] args) {

        Teacher tea = new Teacher();

        //tea.setId(999); //这里不要设置teachers表中不存在的ID

        tea.setName("Ji_Yeon");

        tea.setBirthday(new java.util.Date());

        tea.setTitle("初级");

        Session session = HibernateUtil.getSessionFactory().getCurrentSession();

        session.beginTransaction();

        session.saveOrUpdate(tea);

        session.getTransaction().commit();

        tea.setName("Hebe");

        Session session2 = HibernateUtil.getSessionFactory()

                .getCurrentSession();

        session2.beginTransaction();

        session2.saveOrUpdate(tea);

        session2.getTransaction().commit();

        HibernateUtil.getSessionFactory().close();

    }

}

Hibernate:

    select

        teacher_seq_db.nextval

    from

        dual

Hibernate:

    insert

    into

        teachers

        (birthday, tname, sex, title, id)

    values

        (?, ?, ?, ?, ?)

Hibernate:

    update

        teachers

    set

        birthday=?,

        tname=?,

        sex=?,

        title=?

    where

        id=?

         程序执行后,teachers表:

SQL> SELECT * FROM teachers;

        ID BIRTHDAY                       TNAME           SEX             TITLE

---------------------------------------- --------------- --------------- ---------------

         1 13-JUN-13 12.00.00.000000 AM   Mary

         2 08-JUN-13 12.00.00.000000 AM   Angelababy      FEMALE          中级

         3 08-JUN-13 11.49.28.434000 PM   Charlene Choi   FEMALE          初级

         4 13-JUN-13 12.00.00.000000 AM   Coco

         5 10-JUN-13 11.05.08.828000 PM   So_Yeon         FEMALE          初级

        10 14-JUN-13 12.00.00.000000 AM   Hebe                            高级

6 rowsselected.

         由于在Teacher类中添加了ID生成器,所以上面不能使用setId()方法设置teacher表中不存在的ID值,否则报错,因为如果设置的ID值不存在于teacher表中,saveOrUpdate()方法会执行插入(即save()方法)操作,此时便会与Teacher类中ID生成器冲突,因此报错,。如果setId()方法设置的ID值在teacher表中存在的话,则saveOrUpdate()方法会执行更新(update())操作,此时不会报错。

         如果我们想自己定义ID值,只要把ID生成器去掉即可,如下Teacher类:

package com.wolex.hibernate.model;

import java.util.Date;

import javax.persistence.Column;

import javax.persistence.Entity;

import javax.persistence.EnumType;

import javax.persistence.Enumerated;

import javax.persistence.GeneratedValue;

import javax.persistence.GenerationType;

import javax.persistence.Id;

import javax.persistence.SequenceGenerator;

import javax.persistence.Table;

import javax.persistence.Temporal;

import javax.persistence.TemporalType;

import javax.persistence.Transient;

 

@Entity

// 指定数据表名为"teachers":

@Table(name = "teachers")

//@SequenceGenerator(name = "teacher_seq", sequenceName = "teacher_seq_db",allocationSize = 1)

public class Teacher {

    private int id;

    private String name;

    private String title;

    private String spouseName;

    private Date birthday;

    private Sex sex;

 

    @Id

//  @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "teacher_seq")

    public int getId() {

        return id;

    }

 

    @Column(name = "tname", length = 20)

    public String getName() {

        return name;

    }

 

    // 不持久化的属性

    @Transient

    public String getSpouse() {

        return spouseName;

    }

 

    @Column(length = 10)

    public String getTitle() {

        return title;

    }

 

    // 但只有一个值的时候,value可写可不写: @Temporal(value = TemporalType.TIME)

    // 枚举类TemporalType中的其他常量:DATETIMESTAMP

    @Temporal(TemporalType.TIMESTAMP)

    public Date getBirthday() {

        return birthday;

    }

 

    // EnumType.ORDINAL表示采用枚举的序数(12。。。)

    @Enumerated(EnumType.STRING)

    @Column(length = 10)

    public Sex getSex() {

        return sex;

    }

 

    public void setBirthday(Date birthday) {

        this.birthday = birthday;

    }

 

    public void setId(int id) {

        this.id = id;

    }

 

    public void setName(String name) {

        this.name = name;

    }

 

    public void setSpouse(String spouse) {

        this.spouseName = spouse;

    }

 

    public void setTitle(String title) {

        this.title = title;

    }

 

    public void setSex(Sex sex) {

        this.sex = sex;

    }

}

         编写测试类,手动设置ID值。

package com.wolex.hibernate.model;

import org.hibernate.Session;

import org.hibernate.tutorial.util.HibernateUtil;

 

public class TeacherTest {

    public static void main(String[] args) {

        Teacher tea = new Teacher();

        tea.setId(20);

        tea.setName("Ji_Yeon");

        tea.setBirthday(new java.util.Date());

        tea.setTitle("初级");

        Session session = HibernateUtil.getSessionFactory().getCurrentSession();

        session.beginTransaction();

        session.saveOrUpdate(tea);

        session.getTransaction().commit();

        tea.setName("Kym");

        Session session2 = HibernateUtil.getSessionFactory()

                .getCurrentSession();

        session2.beginTransaction();

        session2.saveOrUpdate(tea);

        session2.getTransaction().commit();

        HibernateUtil.getSessionFactory().close();

    }

}

Hibernate:

    select

        teacher_.id,

        teacher_.birthday as birthday2_0_,

        teacher_.tname as tname3_0_,

        teacher_.sex as sex4_0_,

        teacher_.title as title5_0_

    from

        teachers teacher_

    where

        teacher_.id=?

Hibernate:

    insert

    into

        teachers

        (birthday, tname, sex, title, id)

    values

        (?, ?, ?, ?, ?)

Hibernate:

    select

        teacher_.id,

        teacher_.birthday as birthday2_0_,

        teacher_.tname as tname3_0_,

        teacher_.sex as sex4_0_,

        teacher_.title as title5_0_

    from

        teachers teacher_

    where

        teacher_.id=?

Hibernate:

    update

        teachers

    set

        birthday=?,

        tname=?,

        sex=?,

        title=?

    where

        id=?

         更新后的teachers表:

SQL> SELECT * FROM teachers ORDER BY id;

        ID BIRTHDAY                       TNAME           SEX             TITLE

---------------------------------------- --------------- --------------- ---------------

         1 13-JUN-13 12.00.00.000000 AM   Mary

         2 08-JUN-13 12.00.00.000000 AM   Angelababy      FEMALE          中级

         3 08-JUN-13 11.49.28.434000 PM   Charlene Choi   FEMALE          初级

         4 13-JUN-13 12.00.00.000000 AM   Coco

         5 10-JUN-13 11.05.08.828000 PM   So_Yeon         FEMALE          初级

        10 14-JUN-13 12.00.00.000000 AM   Hebe                            高级

        20 14-JUN-1312.00.00.000000 AM   Kym                             初级

7 rowsselected.

         从Hibernate反馈回来的SQL语句中可以看到,比前一个程序多了两条查询teachers表的select语句,用于检查teachers表中是否存在ID=20的记录是否存在。

3.7、clear()方法

         此方法用于清空缓存内容。

        

         使用get()方法取出ID值不一样的时候:

package com.wolex.hibernate.model;

 

import org.hibernate.Session;

import org.hibernate.tutorial.util.HibernateUtil;

 

public class TeacherTest {

    public static void main(String[] args) {

        Session session = HibernateUtil.getSessionFactory().getCurrentSession();

        session.beginTransaction();

        Teacher tea = (Teacher) session.get(Teacher.class, 1);

 

        tea = (Teacher) session.get(Teacher.class, 2);

        session.getTransaction().commit();

        HibernateUtil.getSessionFactory().close();

    }

}

Hibernate:

    select

        teacher0_.id as id1_0_0_,

        teacher0_.birthday as birthday2_0_0_,

        teacher0_.tname as tname3_0_0_,

        teacher0_.sex as sex4_0_0_,

        teacher0_.title as title5_0_0_

    from

        teachers teacher0_

    where

        teacher0_.id=?

Hibernate:

    select

        teacher0_.id as id1_0_0_,

        teacher0_.birthday as birthday2_0_0_,

        teacher0_.tname as tname3_0_0_,

        teacher0_.sex as sex4_0_0_,

        teacher0_.title as title5_0_0_

    from

        teachers teacher0_

    where

        teacher0_.id=?

         此时,由于ID值不同,所以Hibernate发出了两条select语句,但是这两条select语句是完全一样的,说明在DB中是同一语句执行了两次,他们共享执行计划。这是因为Hibernate使用了绑定变量的结果。同样,我们可以查询v$sql视图demonstrate:

SQL> select SQL_TEXT,SQL_ID,EXECUTIONS,HASH_VALUE fromv$sql where upper(sql_text) like 'SELECT TEACHER%';

SQL_TEXT                                                    SQL_ID        EXECUTIONSHASH_VALUE

------------------------------------------------------------------------- ---------- ----------

select teacher0_.id as id1_0_0_, teacher0_.birthday as birth1w7satzwa62f7          2 4171434439

day2_0_0_, teacher0_.tname as tname3_0_0_, teacher0_.sex as

sex4_0_0_, teacher0_.title as title5_0_0_ from teachers teac

her0_ where teacher0_.id=:1

         使用load()结果一样,这里不再演示了。

         使用get()方法取出同一ID的数据:

package com.wolex.hibernate.model;

import org.hibernate.Session;

import org.hibernate.tutorial.util.HibernateUtil;

 

public class TeacherTest {

    public static void main(String[] args) {

        Session session = HibernateUtil.getSessionFactory().getCurrentSession();

        session.beginTransaction();

        Teacher tea = (Teacher) session.get(Teacher.class, 1);

 

        tea = (Teacher) session.get(Teacher.class, 1);

        session.getTransaction().commit();

        HibernateUtil.getSessionFactory().close();

    }

}

Hibernate:

    select

        teacher0_.id as id1_0_0_,

        teacher0_.birthday as birthday2_0_0_,

        teacher0_.tname as tname3_0_0_,

        teacher0_.sex as sex4_0_0_,

        teacher0_.title as title5_0_0_

    from

        teachers teacher0_

    where

        teacher0_.id=?

         此时后台只发出一条select语句。表明(indicate)在数据库中只执行了一次这条select语句。其实每次执行get()或load()方法的时候,都会先检查缓存中是否存在记录(即以前是否执行过此语句),如果有,则直接重用缓存中数据。由于第一次执行get()方法时,缓存中没有记录,所以Hibernate会发出一次select语句,而第二次执行get()方法时,不再执行select语句,而是直接重用在缓存中的结果。

         我们可以以sys身份到数据库中查询执行结果:

SQL> conn / as sysdba

Connected.

SQL> select SQL_TEXT,SQL_ID,EXECUTIONS,HASH_VALUE fromv$sql where upper(sql_text) like 'SELECT TEACHER%';

SQL_TEXT                                                    SQL_ID        EXECUTIONS HASH_VALUE

------------------------------------------------------------------------- ---------- ----------

selectteacher0_.id as id1_0_0_, teacher0_.birthday as birth 1w7satzwa62f7          14171434439

day2_0_0_,teacher0_.tname as tname3_0_0_, teacher0_.sex as

sex4_0_0_,teacher0_.title as title5_0_0_ from teachers teac

her0_ whereteacher0_.id=:1

         从动态性能视图v$sql中可以发现,上面select语句只执行了一次。

使用load()也一样,只是要注意的是,load()返回的是代理。所以我们要添加触发条件(getName()):

package com.wolex.hibernate.model;

import org.hibernate.Session;

import org.hibernate.tutorial.util.HibernateUtil;

 

public class TeacherTest {

    public static void main(String[] args) {

        Session session = HibernateUtil.getSessionFactory().getCurrentSession();

        session.beginTransaction();

        Teacher tea = (Teacher) session.get(Teacher.class, 1);

 

        tea = (Teacher) session.load(Teacher.class, 1);

        tea.getName();

        session.getTransaction().commit();

        HibernateUtil.getSessionFactory().close();

    }

}

         结果一样,不再演示了。

         说了这么多,终于可以引出clear()方法的使用了。在上面程序中加入clear()方法,以清除缓存中数据。

package com.wolex.hibernate.model;

import org.hibernate.Session;

import org.hibernate.tutorial.util.HibernateUtil;

 

public class TeacherTest {

    public static void main(String[] args) {

        Session session = HibernateUtil.getSessionFactory().getCurrentSession();

        session.beginTransaction();

        Teacher tea = (Teacher) session.get(Teacher.class, 1);

        session.clear();

        tea = (Teacher) session.get(Teacher.class, 1);

        session.getTransaction().commit();

        HibernateUtil.getSessionFactory().close();

    }

}

Hibernate:

    select

        teacher0_.id as id1_0_0_,

        teacher0_.birthday as birthday2_0_0_,

        teacher0_.tname as tname3_0_0_,

        teacher0_.sex as sex4_0_0_,

        teacher0_.title as title5_0_0_

    from

        teachers teacher0_

    where

        teacher0_.id=?

Hibernate:

    select

        teacher0_.id as id1_0_0_,

        teacher0_.birthday as birthday2_0_0_,

        teacher0_.tname as tname3_0_0_,

        teacher0_.sex as sex4_0_0_,

        teacher0_.title as title5_0_0_

    from

        teachers teacher0_

    where

        teacher0_.id=?

         可见,此时即使ID值一样,也发出了两条select语句。

3.8、flush()方法

         此方法用于手动刷新缓存,将脏数据写入到硬盘中,保持数据一致性。说白了,就是同步(synchronize)内存和数据库。

         执行两次setName()方法,之后commit(),查看后台发出几条update语句,观察数据库表结果。

package com.wolex.hibernate.model;

import org.hibernate.Session;

import org.hibernate.tutorial.util.HibernateUtil;

 

public class TeacherTest {

    public static void main(String[] args) {

        Session session = HibernateUtil.getSessionFactory().getCurrentSession();

        session.beginTransaction();

        Teacher tea = (Teacher) session.get(Teacher.class, 20);

        tea.setName("Gillian");

        tea.setName("Ji Yeon");

        session.getTransaction().commit();

        HibernateUtil.getSessionFactory().close();

    }

}

Hibernate:

    select

        teacher0_.id as id1_0_0_,

        teacher0_.birthday as birthday2_0_0_,

        teacher0_.tname as tname3_0_0_,

        teacher0_.sex as sex4_0_0_,

        teacher0_.title as title5_0_0_

    from

        teachers teacher0_

    where

        teacher0_.id=?

Hibernate:

    update

        teachers

    set

        birthday=?,

        tname=?,

        sex=?,

        title=?

    where

        id=?

         默认情况下,当执行commit()时,会执行一次flush()方法,将数据写入到数据库。查询teachers表:

SQL> SELECT * FROM teachers WHERE id=20;

        ID BIRTHDAY                       TNAME           SEX             TITLE

---------- ------------------------------ ------------------------------ ---------------

        20 14-JUN-1312.00.00.000000 AM   Ji Yeon                         初级

         可以看到,hibernate最终只发出了一条update语句,因为只有在flush()时,hibernate才会发出update语句将内存中对象持久化到数据库当中。所以第一次setName(“Gillian”)时只是把tea对象信息写入到内存中,此时并不与DB打交道;而第二次setName(“Ji Yeon”)时,也只是把之前在内存里tea对象信息中name的值改为“Ji Yeon”,此时还不和DB打交道;当执行到commit()时,默认情况下回flush一次,所以此时和DB打交道了,即向数据库中发出update语句以把对象内容持久化到DB中。因此如果在以上程序中,去掉commit(),则数据库并不会更新ID=20的记录。

         手动使用flush(),观察后台发出多少条update语句。

package com.wolex.hibernate.model;

import org.hibernate.Session;

import org.hibernate.tutorial.util.HibernateUtil;

 

public class TeacherTest {

    public static void main(String[] args) {

        Session session = HibernateUtil.getSessionFactory().getCurrentSession();

        session.beginTransaction();

        Teacher tea = (Teacher) session.get(Teacher.class, 20);

        tea.setName("Cica");

        session.flush();

        tea.setName("Juniel");

        session.getTransaction().commit();

        HibernateUtil.getSessionFactory().close();

    }

}

Hibernate:

    select

        teacher0_.id as id1_0_0_,

        teacher0_.birthday as birthday2_0_0_,

        teacher0_.tname as tname3_0_0_,

        teacher0_.sex as sex4_0_0_,

        teacher0_.title as title5_0_0_

    from

        teachers teacher0_

    where

        teacher0_.id=?

Hibernate:

    update

        teachers

    set

        birthday=?,

        tname=?,

        sex=?,

        title=?

    where

        id=?

Hibernate:

    update

        teachers

    set

        birthday=?,

        tname=?,

        sex=?,

        title=?

    where

        id=?

         可见,此时后台发出了两条update语句。

         注意区别flush()与clear()的区别。

         默认情况下commit()之后会发出flush(),其实有一个FlushMode玩意可以指定什么情况下才发出flush()。在Session接口中,有setFlushMode(FlushModeflushMode)和getFlushMode()这两个方法。其中FlushMode是一个Enum类,可选值有:MANUAL、ALWAYS、AUTO、COMMIT、NEVER。其中AUTO是默认的,NEVER deprecated,use MANUALinstead.。

         修改FlushMode要在会话开始事务前,观察以下程序:

package com.wolex.hibernate.model;

import org.hibernate.FlushMode;

import org.hibernate.Session;

import org.hibernate.tutorial.util.HibernateUtil;

 

public class TeacherTest {

    public static void main(String[] args) {

        Session session = HibernateUtil.getSessionFactory().getCurrentSession();

        session.setFlushMode(FlushMode.MANUAL);// 要在事务开始前设置。

        session.beginTransaction();

        Teacher tea = (Teacher) session.get(Teacher.class, 20);

        tea.setName("Cica");

        tea.setName("Juniel");

        session.getTransaction().commit();

        HibernateUtil.getSessionFactory().close();

    }

}

Hibernate:

    select

        teacher0_.id as id1_0_0_,

        teacher0_.birthday as birthday2_0_0_,

        teacher0_.tname as tname3_0_0_,

        teacher0_.sex as sex4_0_0_,

        teacher0_.title as title5_0_0_

    from

        teachers teacher0_

    where

        teacher0_.id=?

         将FlushMode设置为MANUAL(手动)时,即使程序最后commit()了,也不会执行flush()。

         但设置FlushMode的意义何在呢?设置FlushMode与优化有关,但实际中用得很少。引自API中对setFlushMode的说明:

The flush mode determines thepoints at which the session is flushed. Flushing is theprocess of synchronizing the underlying persistent store with persistable stateheld in memory.

For a logically "read only" session, it is reasonable to set thesession's flush mode to FlushMode.MANUAL atthe start of the session (in order to achieve someextra performance).

         大概就是在纯查询(只可读不可修改)的情况中设置会话模式为FlushMode.MANUAL可以获得额外的性能。

3.9、SchemaExport类

         在org.hibernate.tool.hbm2ddl包中有SchemaExport类。API文档对其说明:

Class SchemaExport

         java.lang.Object

                   org.hibernate.tool.hbm2ddl.SchemaExport

Ÿ  public class SchemaExport
extends Object

Commandline(命令行) tool to export table schema to the database. This class may also be called from inside an application.

         大概意思是此类是使用命令行工具的方式在数据库中创建表(需在hibernate.cfg.xml中配置)。其中也可以只打印出建表语句而不真正执行。我们这里只探究一个方法——create,其他的执行了解。SchemaExport类中create(…)方法说明:

create

public void create(boolean script,

          boolean export)

Run the schema creation script; drop script is automatically executedbefore running the creation script.

Parameters:

script - print the DDL to the console

export - export the script to the database

         第一个参数script指打印DDL语句到控制台,第二个参数指将脚本导出到DB中(即在DB中执行)。

         因为这个方法执行的就是DDL,所以如果使用此类时,可以把hiberna.cfg.xml以下内容去掉:

<!-- Drop and re-create the database schema on startup -->

<property name="hbm2ddl.auto">update</property>

编写测试类,观察结果:

package com.wolex.hibernate.model;

import org.hibernate.cfg.Configuration;

import org.hibernate.tool.hbm2ddl.SchemaExport;

 

public class ShemaExportDemo {

    public static void main(String[] args) {

        // deprecated写法:因为AnnotationCofiguratoion类都已经的deprecated

        // new SchemaExport(new

        // AnnotationConfiguration().configure()).create(...);

        new SchemaExport(new Configuration().configure()).create(true, false);

    }

}

2013-6-14 16:57:14 org.hibernate.tool.hbm2ddl.SchemaExport execute

INFO: HHH000227: Running hbm2ddl schema export

 

    drop table teachers cascade constraints

 

    drop sequence teacher_seq_db

 

    create table teachers (

        id number(10,0) not null,

        birthday date,

        tname varchar2(20 char),

        sex varchar2(10 char),

        title varchar2(10 char),

        primary key (id)

    )

 

    create sequence teacher_seq_db

2013-6-14 16:57:14 org.hibernate.tool.hbm2ddl.SchemaExport execute

INFO: HHH000230: Schema export complete

         相比较于配置hibernate.cfg.xml中hbm2ddl.auto参数来输出DDL语句(后台中只输出一行),使用SchemaExport的create()方法跟美观些(多行显示)。

         So far,核心开发接口的常用方法介绍完毕。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
hibernate-jpa-2.1-api 1.0.2是一个Java持久化规范的实现库。它是基于JPA(Java Persistence API)2.1规范的Hibernate实现。Hibernate是一个流行的ORM(对象关系映射)框架,用于在Java应用程序和关系数据库之间进行数据持久化。 该版本的hibernate-jpa-2.1-api是对JPA 2.1规范的实现,并且是Hibernate团队为了确保应用程序与Java EE 7兼容性而发布的一个版本。 JPA是一种使用对象模型操作数据库的标准规范,它提供了一组API,使开发人员可以使用面向对象的方式访问和操作数据库。Hibernate作为一个JPA的实现,提供了许多附加的功能和特性,使得开发人员可以更加简化和灵活地进行数据库操作。 通过使用hibernate-jpa-2.1-api,开发人员可以使用JPA的标准API,以及Hibernate提供的独有特性,来实现应用程序的数据持久化需求。它提供了实体管理器,用于管理实体对象的生命周期,以及CRUD操作。此外,它还提供了用于查询和各种持久化注解的支持。 通常情况下,使用hibernate-jpa-2.1-api需要将其添加到项目的依赖中,并与其他必需的Hibernate库一起使用。开发人员需要熟悉JPA的基本概念和API,并且理解Hibernate特有的扩展和配置选项。 总的来说,hibernate-jpa-2.1-api 1.0.2提供了开发人员在使用JPA进行数据持久化时的基本工具和功能。它是Hibernate团队为了支持JPA 2.1规范而发布的一个版本,开发人员可以使用它来简化和灵活地操作数据库。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值