📄 quickstart.html
字号:
每个持久化类都应该有一个标识属性(实际上,这个类只代表实体,而不是独立的值类型类,后者会被映射称为实体对象中的一个组件)。这个属性用来区分持久化对象:如果<tt class="literal">catA.getId().equals(catB.getId())</tt>结果是true的话,这两个Cat就是相同的。这个概念称为<span class="emphasis"><em>数据库标识</em></span>。Hiernate附带了几种不同的标识符生成器,用于不同的场合(包括数据库本地的顺序(sequence)生成器、hi/lo高低位标识模式、和程序自己定义的标识符)。我们在这里使用UUID生成器(只在测试时建议使用,如果使用数据库自己生成的整数类型的键值更好),并指定<tt class="literal">CAT</tt>表中的<tt class="literal">CAT_ID</tt>字段(作为表的主键)存放生成的标识值。 </p><p> <tt class="literal">Cat</tt>的其他属性都映射到同一个表的字段。对<tt class="literal">name</tt>属性来说,我们把它显式地声明映射到一个数据库字段。如果数据库schema是通过由映射声明使用Hibernate的<span class="emphasis"><em>SchemaExport</em></span>工具自动生成的(作为SQL DDL指令)的话,这就特别有用。所有其它的属性都用Hibernate的默认值映射,大多数情况你都会这样做。数据库中的<tt class="literal">CAT</tt>表看起来是这样的: </p><pre class="programlisting"> Column | Type | Modifiers--------+-----------------------+----------- cat_id | character(32) | not null name | character varying(16) | not null sex | character(1) | weight | real |Indexes: cat_pkey primary key btree (cat_id)</pre><p> 你现在可以在你的数据库中手工创建这个表了,如果你需要使用<tt class="literal">hbm2ddl</tt>工具把这个步骤自动化,请参阅<a href="toolsetguide.html" title="第 21 章 工具箱指南">第 21 章 <i>工具箱指南</i></a>。这个工具能够创建完整的SQL DDL,包括表定义,自定义的字段类型约束,惟一约束和索引。 </p></div><div class="sect1" lang="zh-cn"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="quickstart-playingwithcats"></a>1.4. 与Cat同乐</h2></div></div><div></div></div><p> 我们现在可以开始Hibernate的<tt class="literal">Session</tt>了。它是一个<span class="emphasis"><em>持久化管理器</em></span>,我们通过它来从数据库中存取<tt class="literal">Cat</tt>。首先,我们要从<tt class="literal">SessionFactory</tt>中获取一个<tt class="literal">Session</tt>(Hibernate的工作单元)。 </p><pre class="programlisting">SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory();</pre><p> 通过对<tt class="literal">configure()</tt>的调用来装载<tt class="literal">hibernate.cfg.xml</tt>配置文件,并初始化成一个<tt class="literal">Configuration</tt>实例。 在创建 <tt class="literal">SessionFactory</tt><span class="emphasis"><em>之前</em></span>(它是不可变的),你可以访问<tt class="literal">Configuration</tt>来设置其他属性(甚至修改映射的元数据)。我们应该在哪儿创建<tt class="literal">SessionFactory</tt>,在我们的程序中又如何访问它呢? <tt class="literal">SessionFactory</tt>通常只是被初始化一次,比如说通过一个<span class="emphasis"><em>load-on-startup</em></span> servlet的来初始化。这意味着你不应该在serlvet中把它作为一个实例变量来持有,而应该放在其他地方。进一步的说,我们需要使用<span class="emphasis"><em>单例(Singleton)</em></span>模式,我们才能更容易的在程序中访问<tt class="literal">SessionFactory</tt>。下面的方法就同时解决了两个问题:对<tt class="literal">SessionFactory</tt>的初始配置与便捷使用。 </p><p> 我们实现一个<tt class="literal">HibernateUtil</tt>辅助类: </p><pre class="programlisting">import org.hibernate.*;import org.hibernate.cfg.*;public class HibernateUtil { private static Log log = LogFactory.getLog(HibernateUtil.class); private static final SessionFactory sessionFactory; static { try { // Create the SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory(); } catch (Throwable ex) { // Make sure you log the exception, as it might be swallowed log.error("Initial SessionFactory creation failed.", ex); throw new ExceptionInInitializerError(ex); } } public static final ThreadLocal session = new ThreadLocal(); public static Session currentSession() { Session s = (Session) session.get(); // Open a new Session, if this Thread has none yet if (s == null) { s = sessionFactory.openSession(); session.set(s); } return s; } public static void closeSession() { Session s = (Session) session.get(); if (s != null) s.close(); session.set(null); }}</pre><p> 这个类不但在它的静态初始器中使用了<tt class="literal">SessionFactory</tt>,还使用了一个<tt class="literal">ThreadLocal</tt>变量来保存<tt class="literal">Session</tt>做为当前工作线程。在你使用这个辅助类之前,请确保你理解了thread-local变量这个Java概念。你可以在<tt class="literal">CaveatEmptor</tt>(http://caveatemptor.hibernate.org/)上找到一个更加复杂和强大的 <tt class="literal">HibernateUtil</tt>。 </p><p> <tt class="literal">SessionFactory</tt>是安全线程,可以由很多线程并发访问并获取到<tt class="literal">Sessions</tt>。单个<tt class="literal">Session</tt>不是安全线程对象,它只代表与数据库之间的一次操作。<tt class="literal">Session</tt>通过<tt class="literal">SessionFactory</tt>获得并在所有的工作完成后关闭。在你servlet的<tt class="literal">process()</tt>中可以象是这么写的(省略了异常情况处理): </p><pre class="programlisting">Session session = HibernateUtil.currentSession();Transaction tx= session.beginTransaction();Cat princess = new Cat();princess.setName("Princess");princess.setSex('F');princess.setWeight(7.4f);session.save(princess);tx.commit();HibernateUtil.closeSession();</pre><p> 在一个<tt class="literal">Session</tt>中,每个数据库操作都是在一个事务(transaction)中进行的,这样就可以隔离开不同的操作(甚至包括只读操作)。我们使用Hibernate的<tt class="literal">Transaction</tt> API来从底层的事务策略中(本例中是JDBC事务)脱身出来。这样,我们就不需要更改任何源代码,就可以把我们的程序部署到一个由容器管理事务的环境中去(使用JTA)。 </p><p> 这样你就可以随心所欲的多次调用<tt class="literal">HibernateUtil.currentSession();</tt>,你每次都会得到同一个当前线程的<tt class="literal">Session</tt>。不管是在你的servlet代码中,或者在servlet filter中还是在HTTP结果返回之前,你都必须确保这个<tt class="literal">Session</tt>在你的数据库访问工作完成后关闭。这样做还有一个好处就是可以容易的使用延迟装载(lazy initialization):<tt class="literal">Session</tt>在渲染view层的时候仍然打开着的,所以你在遍历当前对象图的时候可以装载所需的对象。 </p><p> Hibernate有不同的方法用来从数据库中取回对象。最灵活的方式就是使用Hibernate查询语言(HQL),这是一种容易学习的语言,是对SQL的面向对象的强大扩展。 </p><pre class="programlisting">Transaction tx= session.beginTransaction();Query query = session.createQuery("select c from Cat as c where c.sex = :sex");query.setCharacter("sex", 'F');for (Iterator it = query.iterate(); it.hasNext();) { Cat cat = (Cat) it.next(); out.println("Female Cat: " + cat.getName() );}tx.commit();</pre><p> Hibernate也提供一种面向对象的<span class="emphasis"><em>按条件查询</em></span>API,可以执行简洁安全类型的查询。当然,Hibernate在所有与数据库的交互中都使用<tt class="literal">PrepatedStatement</tt>和参数绑定。你也可以使用Hibernate的直接SQL查询特性,或者在特殊情况下从<tt class="literal">Session</tt>获取一个原始的JDBC连接。 </p></div><div class="sect1" lang="zh-cn"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="quickstart-summary"></a>1.5. 结语</h2></div></div><div></div></div><p> 在这个短小的教程中,我们对Hibernate浅尝即止。请注意我们没有在例子中包含任何servlet相关代码。你必须自行编写servlet,并插入适合你的Hibernate代码。 </p><p> 请记住Hibernate作为一个数据库访问层,是与你的程序紧密相关的。通常情况下,所有其他层次都依赖持久机制。请确信你理解了这种设计的内涵。 </p><p> 若希望学习更复杂的例子,请参阅http://caveatemptor.hibernate.org/ 。在 http://www.hibernate.org/Documentation 也可以得到其他教程的链接。 </p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="preface.html">上一页</a> </td><td width="20%" align="center"><a accesskey="u" href="index.html">上一级</a></td><td width="40%" align="right"> <a accesskey="n" href="tutorial.html">下一页</a></td></tr><tr><td width="40%" align="left" valign="top">前言 </td><td width="20%" align="center"><a accesskey="h" href="index.html">起始页</a></td><td width="40%" align="right" valign="top"> 第 2 章 Hibernate入门 </td></tr></table></div></body></html>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -