📄 tutorial.html
字号:
} catch (Throwable ex) { // Make sure you log the exception, as it might be swallowed System.err.println("Initial SessionFactory creation failed." + ex); throw new ExceptionInInitializerError(ex); } } public static final ThreadLocal session = new ThreadLocal(); public static Session currentSession() throws HibernateException { Session s = (Session) session.get(); // Open a new Session, if this thread has none yet if (s == null) { s = sessionFactory.openSession(); // Store it in the ThreadLocal variable session.set(s); } return s; } public static void closeSession() throws HibernateException { Session s = (Session) session.get(); if (s != null) s.close(); session.set(null); }}</pre><p> 这个类不仅仅在它的静态初始化过程(仅当加载这个类的时候被JVM执行一次)中产生全局<tt class="literal">SessionFactory</tt>, 同时也有一个<tt class="literal">ThreadLocal</tt>变量来为当前线程保存<tt class="literal">Session</tt>。不论你何时 调用<tt class="literal">HibernateUtil.currentSession()</tt>,它总是返回同一个线程中的同一个Hibernate单元操作。 而一个<tt class="literal">HibernateUtil.closeSession()</tt>调用将终止当前线程相联系的那个单元操作。 </p><p> 在你使用这个帮助类之前,确定你明白Java关于本地线程变量(thread-local variable)的概念。一个功能更加强大的 <tt class="literal">HibernateUtil</tt>帮助类可以在<tt class="literal">CaveatEmptor</tt>http://caveatemptor.hibernate.org/找到 -它同时也出现在书:《Hibernate in Action》中。注意当你把Hibernate部署在一个J2EE应用服务器上的时候,这个类不是必须的: 一个<tt class="literal">Session</tt>会自动绑定到当前的JTA事物上,你可以通过JNDI来查找<tt class="literal">SessionFactory</tt>。 如果你使用JBoss AS,Hibernate可以被部署成一个受管理的系统服务(system service)并自动绑定<tt class="literal">SessionFactory</tt>到JNDI上。 </p><p> 把<tt class="literal">HibernateUtil.java</tt>放在开发目录的源代码路径下面,与 <tt class="literal">Event.java</tt>放在一起: </p><pre class="programlisting">.+lib <Hibernate and third-party libraries>+src Event.java Event.hbm.xml HibernateUtil.java hibernate.cfg.xml+databuild.xml</pre><p> 再次编译这个程序不应该有问题。最后我们需要配置一个日志系统 - Hibernate使用通用日志接口,这允许你在Log4j和 JDK 1.4 logging之间进行选择。多数开发者喜欢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>2.2.6. 加载并存储对象 </h3></div></div><div></div></div><p> 终于,我们可以使用Hibernate来加载和存储对象了。我们编写一个带有<tt class="literal">main()</tt>方法 的<tt class="literal">EventManager</tt>类: </p><pre class="programlisting">import org.hibernate.Transaction;import org.hibernate.Session;import java.util.Date;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.sessionFactory.close(); }}</pre><p> 我们从命令行读入一些参数,如果第一个参数是"store",我们创建并储存一个新的Event: </p><pre class="programlisting">private void createAndStoreEvent(String title, Date theDate) { Session session = HibernateUtil.currentSession(); Transaction tx = session.beginTransaction(); Event theEvent = new Event(); theEvent.setTitle(title); theEvent.setDate(theDate); session.save(theEvent); tx.commit(); HibernateUtil.closeSession();}</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>是一个独立的单元操作。你会对我们有另外一个API:<tt class="literal">Transaction</tt>而感到惊奇。 这暗示一个单元操作可以拥有比一个单独的数据库事务更长的生命周期 - 想像在web应用程序中,一个单元操作跨越多个Http request/response循环 (例如一个创建对话框)。根据“应用程序用户眼中的单元操作”来切割事务是Hibernate的基本设计思想之一。我们调用 一个长生命期的单元操作<span class="emphasis"><em>Application Transaction</em></span>时,通常包装几个更生命期较短的数据库事务。 为了简化问题,在这个教程里我们使用<tt class="literal">Session</tt>和<tt class="literal">Transaction</tt>之间是1对1关系的粒度(one-to-one granularity)。 </p><p> <tt class="literal">Transaction.begin()</tt>和<tt class="literal">commit()</tt>都做些什么?<tt class="literal">rollback()</tt>在哪些情况下会产生错误? Hibernate的<tt class="literal">Transaction</tt> API 实际上是可选的, 但是我们通常会为了便利性和可移植性而使用它。 如果你宁可自己处理数据库事务(例如,调用<tt class="literal">session.connection.commit()</tt>),通过直接和无管理的JDBC,这样将把代码绑定到一个特定的部署环境中去。 通过在Hibernate配置中设置<tt class="literal">Transaction</tt>工厂,你可以把你的持久化层部署在任何地方。 查看<a href="transactions.html" title="第 12 章 事务和并发">第 12 章 <i>事务和并发</i></a>了解更多关于事务处理和划分的信息。在这个例子中我们也忽略任何异常处理和事务回滚。 </p><p> 为了第一次运行我们的应用程序,我们必须增加一个可以调用的target到Ant的build文件中。 </p><pre class="programlisting"><target name="run" depends="compile"> <java fork="true" classname="EventManager" classpathref="libraries"> <classpath path="${targetdir}"/> <arg value="${action}"/> </java></target></pre><p> <tt class="literal">action</tt>参数的值是在通过命令行调用这个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>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -