📄 tutorial.html
字号:
}}</pre><p> 这个类不但在它的静态初始化过程(仅当加载这个类的时候被JVM执行一次)中产生全局的<tt class="literal">SessionFactory</tt>,而且隐藏了它使用了静态singleton的事实。它也可能在应用程序服务器中的JNDI查找<tt class="literal">SessionFactory</tt>。 </p><p> 如果你在配置文件中给<tt class="literal">SessionFactory</tt>一个名字,在<tt class="literal">SessionFactory</tt>创建后,Hibernate会试着把它绑定到JNDI。要完全避免这样的代码,你也可以使用JMX部署,让具有JMX能力的容器来实例化<tt class="literal">HibernateService</tt>并把它绑定到JNDI。这些高级可选项在后面的章节中会讨论到。 </p><p> 把<tt class="literal">HibernateUtil.java</tt>放在开发目录的源代码路径下,与放<tt class="literal">events</tt>的包并列: </p><pre class="programlisting">.+lib <Hibernate and third-party libraries>+src +events Event.java Event.hbm.xml +util HibernateUtil.java hibernate.cfg.xml+databuild.xml</pre><p> 再次编译这个应用程序应该不会有问题。最后我们需要配置一个日志(logging)系统 - Hibernate使用通用日志接口,允许你在Log4j和JDK 1.4 日志之间进行选择。多数开发者更喜欢Log4j:从Hibernate的发布包中(它在<tt class="literal">etc/</tt>目录下)拷贝<tt class="literal">log4j.properties</tt>到你的<tt class="literal">src</tt>目录,与<tt class="literal">hibernate.cfg.xml</tt>.放在一起。看一下配置示例,如果你希望看到更加详细的输出信息,你可以修改配置。默认情况下,只有Hibernate的启动信息才会显示在标准输出上。 </p><p> 示例的基本框架完成了 - 现在我们可以用Hibernate来做些真正的工作。 </p></div><div class="sect2" lang="zh-cn"><div class="titlepage"><div><div><h3 class="title"><a name="tutorial-firstapp-workingpersistence"></a>1.2.6. 加载并存储对象 </h3></div></div><div></div></div><p> 我们终于可以使用Hibernate来加载和存储对象了,编写一个带有<tt class="literal">main()</tt>方法的<tt class="literal">EventManager</tt>类: </p><pre class="programlisting">package events;import org.hibernate.Session;import java.util.Date;import util.HibernateUtil;public class EventManager { public static void main(String[] args) { EventManager mgr = new EventManager(); if (args[0].equals("store")) { mgr.createAndStoreEvent("My Event", new Date()); } HibernateUtil.getSessionFactory().close(); } private void createAndStoreEvent(String title, Date theDate) { Session session = HibernateUtil.getSessionFactory().getCurrentSession(); session.beginTransaction(); Event theEvent = new Event(); theEvent.setTitle(title); theEvent.setDate(theDate); session.save(theEvent); session.getTransaction().commit(); }}</pre><p> 我们创建了个新的<tt class="literal">Event</tt>对象并把它传递给Hibernate。现在Hibernate负责与SQL打交道,并把<tt class="literal">INSERT</tt>命令传给数据库。在运行之前,让我们看一下处理<tt class="literal">Session</tt>和<tt class="literal">Transaction</tt>的代码。 </p><p> 一个<tt class="literal">Session</tt>就是个单一的工作单元。我们暂时让事情简单一些,并假设Hibernate<tt class="literal">Session</tt>和数据库事务是一一对应的。为了让我们的代码从底层的事务系统中脱离出来(此例中是JDBC,但也可能是JTA),我们使用Hibernate <tt class="literal">Session</tt>中的<tt class="literal">Transaction</tt> API。 </p><p> <tt class="literal">sessionFactory.getCurrentSession()</tt>是干什么的呢?首先,只要你持有<tt class="literal">SessionFactory</tt>(幸亏我们有<tt class="literal">HibernateUtil</tt>,可以随时获得),大可在任何时候、任何地点调用这个方法。<tt class="literal">getCurrentSession()</tt>方法总会返回“当前的”工作单元。记得我们在<tt class="literal">hibernate.cfg.xml</tt>中把这一配置选项调整为"thread"了吗?因此,当前工作单元的范围就是当前执行我们应用程序的Java线程。但是,这并非总是正确的。 <tt class="literal">Session</tt>在第一次被使用的时候,或者第一次调用<tt class="literal">getCurrentSession()</tt>的时候,其生命周期就开始。然后它被Hibernate绑定到当前线程。当事务结束的时候,不管是提交还是回滚,Hibernate也会把<tt class="literal">Session</tt>从当前线程剥离,并且关闭它。假若你再次调用<tt class="literal">getCurrentSession()</tt>,你会得到一个新的<tt class="literal">Session</tt>,并且开始一个新的工作单元。这种<span class="emphasis"><em>线程绑定(thread-bound)</em></span>的编程模型(model)是使用Hibernate的最广泛的方式。 </p><p> 关于事务处理及事务边界界定的详细信息,请参看<a href="transactions.html" title="第 11 章 事务和并发">第 11 章 <i>事务和并发</i></a>。在上面的例子中,我们也忽略了所有的错误与回滚的处理。 </p><p> 为第一次运行我们的程序,我们得在Ant的build文件中增加一个可以调用得到的target。 </p><pre class="programlisting"><target name="run" depends="compile"> <java fork="true" classname="events.EventManager" classpathref="libraries"> <classpath path="${targetdir}"/> <arg value="${action}"/> </java></target></pre><p> <tt class="literal">action</tt>参数(argument)的值是通过命令行调用这个target的时候设置的: </p><pre class="programlisting">C:\hibernateTutorial\>ant run -Daction=store</pre><p> 你应该会看到,编译以后,Hibernate根据你的配置启动,并产生一大堆的输出日志。在日志最后你会看到下面这行: </p><pre class="programlisting">[java] Hibernate: insert into EVENTS (EVENT_DATE, title, EVENT_ID) values (?, ?, ?)</pre><p> 这是Hibernate执行的<tt class="literal">INSERT</tt>命令,问号代表JDBC的绑定参数。如果想要看到绑定参数的值或者减少日志的长度,就要调整你在<tt class="literal">log4j.properties</tt>文件里的设置。 </p><p> 我们想要列出所有已经被存储的events,就要增加一个条件分支选项到main方法中去。 </p><pre class="programlisting">if (args[0].equals("store")) { mgr.createAndStoreEvent("My Event", new Date());}else if (args[0].equals("list")) { List events = mgr.listEvents(); for (int i = 0; i < events.size(); i++) { Event theEvent = (Event) events.get(i); System.out.println("Event: " + theEvent.getTitle() + " Time: " + theEvent.getDate()); }}</pre><p> 我们也增加一个新的<tt class="literal">listEvents()</tt>方法: </p><pre class="programlisting">private List listEvents() {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -