Java 如何在 Hibernate 4.3.4.Final 中配置和获取会话?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/23646389/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to configure and get session in Hibernate 4.3.4.Final?
提问by Hyman
I recently upgraded the version of my Hibernate to 4.3.4.Final. Based on Contextual Sessions configuration of Hibernate this new version is not based on ThreadLocal anymore.If what I have got so far is correct do I need to do anything to make it more efficient? if it is incorrect what should I do? I have no clue.
我最近将我的 Hibernate 版本升级到 4.3.4.Final。基于 Hibernate 的上下文会话配置,这个新版本不再基于 ThreadLocal。如果到目前为止我所得到的都是正确的,我是否需要做任何事情来提高效率?如果不正确,我该怎么办?我没有线索。
Please noteit is mentioned in documentation that: Hibernate offers three methods of current session tracking. The "thread" based method is not intended for production use; it is merely useful for prototyping and tutorials such as this one.
请注意文档中提到: Hibernate 提供了三种当前会话跟踪的方法。基于“线程”的方法不适合生产使用;它仅对诸如此类的原型设计和教程有用。
Hibernate.cfg.xml
休眠文件.cfg.xml
<hibernate-configuration>
<session-factory>
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost/myDB</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password"></property>
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<!-- Enable Hibernate's automatic session context management -->
<property name="current_session_context_class">thread</property>
<!-- Disable the second-level cache -->
<property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>
<property name="show_sql">true</property>
<property name="hibernate.c3p0.min_size">5</property>
<property name="hibernate.c3p0.max_size">20</property>
<property name="hibernate.c3p0.timeout">300</property>
<property name="hibernate.c3p0.max_statements">50</property>
<property name="hibernate.c3p0.idle_test_period">3000</property>
<!-- <property name="hbm2ddl.auto">update</property>-->
<mapping class="com.myProject.entities.users" />
...
Current Configuration and Code
当前配置和代码
Based on answers blew and this part of documentationmu current configuration is as following:
基于答案自爆,这部分文档mu 当前配置如下:
public class HibernateUtil {
private static SessionFactory sessionFactory = buildSessionFactory();
private static SessionFactory buildSessionFactory() {
try {
Configuration configuration = new Configuration();
return configuration.configure()
.buildSessionFactory(
new StandardServiceRegistryBuilder()
.applySettings(configuration.getProperties())
.build());
} catch (Throwable ex) {
System.err.println("Initial SessionFactory creation failed." + ex);
throw new ExceptionInInitializerError(ex);
}
}
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
}
And the code would be as following
代码如下
final Session session = HibernateUtil.getSessionFactory().openSession();
try {
final Transaction tx = session.beginTransaction();
try {
...
Previous Configuration and Code
以前的配置和代码
public class HibernateUtil {
private static ServiceRegistry serviceRegistry;
private static final ThreadLocal<Session> threadLocal = new ThreadLocal();
private static SessionFactory sessionFactory;
private static SessionFactory configureSessionFactory() {
try {
Configuration configuration = new Configuration();
configuration.configure();
serviceRegistry = new StandardServiceRegistryBuilder()
.applySettings(configuration.getProperties())
.build();
sessionFactory = configuration.buildSessionFactory(serviceRegistry);
return sessionFactory;
} catch (HibernateException e) {
System.out.append("** Exception in SessionFactory **");
e.printStackTrace();
}
return sessionFactory;
}
static {
try {
sessionFactory = configureSessionFactory();
} catch (Exception e) {
System.err.println("%%%% Error Creating SessionFactory %%%%");
e.printStackTrace();
}
}
private HibernateUtil() {
}
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
public static Session getSession() throws HibernateException {
Session session = threadLocal.get();
if (session == null || !session.isOpen()) {
if (sessionFactory == null) {
rebuildSessionFactory();
}
session = (sessionFactory != null) ? sessionFactory.openSession() : null;
threadLocal.set(session);
}
return session;
}
public static void rebuildSessionFactory() {
try {
sessionFactory = configureSessionFactory();
} catch (Exception e) {
System.err.println("%%%% Error Creating SessionFactory %%%%");
e.printStackTrace();
}
}
public static void closeSession() throws HibernateException {
Session session = (Session) threadLocal.get();
threadLocal.set(null);
if (session != null) {
if (session.isOpen()) {
session.close();
}
}
}
}
Code to access to transactions and submit commands
访问交易和提交命令的代码
final Session session = HibernateUtil.getSession();
try {
final Transaction tx = session.beginTransaction();
try {
//Commands related to query go here
if (!tx.wasCommitted()) {
tx.commit();
}
if (session.isOpen()) {
session.close();
}
return true;
} catch (Exception e) {
tx.rollback();
return false;
}
} finally {
HibernateUtil.closeSession();
}
return false;
回答by vanOekel
Access to a single instance of SessionFactory within your aplication is all that is needed.
只需访问应用程序中的 SessionFactory 的单个实例即可。
The following information is all (available) from the Hibernate 4.3 manual chapters 2.2. Contextual sessionsand 13. Transactions and Concurrency.
以下信息全部(可用)来自 Hibernate 4.3 手册第2.2章。上下文会话和 13. 事务和并发。
"A SessionFactoryis an expensive-to-create, threadsafe object, intended to be shared by all application threads. It is created once, usually on application startup, from a Configuration instance."
"A Sessionis an inexpensive, non-threadsafe object that should be used once and then discarded for: a single request, a conversation or a single unit of work."
“ SessionFactory是一个创建成本高昂的线程安全对象,旨在由所有应用程序线程共享。它通常在应用程序启动时从 Configuration 实例创建一次。”
“会话是一种廉价的非线程安全对象,应该使用一次然后丢弃:单个请求、对话或单个工作单元。”
If there is no "unit of work" but just a bunch of (bundled) queries and updates, simply follow the first idiom for the non-managed environment(from chapter 13 mentioned earlier). And unless you can demonstrate this gives performance problems(*), do not try to optimize because that is the root of all evil.
如果没有“工作单元”而只有一堆(捆绑的)查询和更新,只需遵循非托管环境的第一个习惯用法(来自前面提到的第 13 章)。除非你能证明这会导致性能问题(*),否则不要尝试优化,因为这是万恶之源。
If there is a "unit of work" or "session-per-request", the HibernateUtil
from the question can be replaced by using org.hibernate.context.internal.ThreadLocalSessionContext
as CurrentSessionContext
(see chapter 2.2 mentioned earlier) and following the second idiom for the non-managed environment.
如果有“工作单元”或“每个请求的会话”,则HibernateUtil
可以使用org.hibernate.context.internal.ThreadLocalSessionContext
as CurrentSessionContext
(参见前面提到的第 2.2 章)并遵循非托管环境的第二个习语来替换问题中的。
If you use JTA, replace ThreadLocalSessionContext
with org.hibernate.context.internal.JTASessionContext
and follow the idioms described in Using JTA.
如果你使用JTA,更换ThreadLocalSessionContext
用org.hibernate.context.internal.JTASessionContext
并按照所描述的成语使用JTA。
Pay attention to the chapter that discusses the "unit of work": a good architecture for your software depends on a good understanding of what a "business transaction" and "application transaction" means for your application.
请注意讨论“工作单元”的章节:良好的软件架构取决于对“业务事务”和“应用程序事务”对应用程序意味着什么的充分理解。
(*) Performance problems can be caused by configuration problems, e.g. this questionwhich has related documentation herein the Hibernate manual.
回答by Vlad Mihalcea
I would drop the TreadUtil class which reminds me of the Spring 1.0 Hibernate integration style. If you plan on moving to Hibernate 4.
我会删除 TreadUtil 类,它让我想起 Spring 1.0 Hibernate 集成风格。如果您打算迁移到 Hibernate 4。
Beside the fact that you should rely on Hibernate 4 bootstrapmechanism, your code also has the following problems:
除了您应该依赖 Hibernate 4引导机制之外,您的代码还存在以下问题:
The session factory rebuilding is not synchronized
synchronized(HibernateUtil.class) { if (sessionFactory == null) { rebuildSessionFactory(); } }
I don't see why you need to rebuild it, since you never set it to null, the session factory being initialized static block.
会话工厂重建不同步
synchronized(HibernateUtil.class) { if (sessionFactory == null) { rebuildSessionFactory(); } }
我不明白为什么你需要重建它,因为你从来没有将它设置为 null,会话工厂被初始化为静态块。
If you always have to wrap your Hibernate code in the HibernateUtil.openSession() try/finally blocks, you would duplicate a lot of session management logic while mixing business logic with transaction logic. This breaks the single responsibility principle.
如果您总是必须将您的 Hibernate 代码包装在 HibernateUtil.openSession() try/finally 块中,您将在混合业务逻辑和事务逻辑的同时复制大量会话管理逻辑。这打破了单一职责原则。
If you still don't want to let the HibernateUtil go, you can at least use a mechanism similar to JDBCTemplateto abstract the session/transaction management in a template method, while supplying the business code in a Callable, which for you might look like:
如果你还是不想让 HibernateUtil 去,你至少可以使用类似于JDBCTemplate的机制在模板方法中抽象会话/事务管理,同时在 Callable 中提供业务代码,对于你来说可能看起来像:
interface SessionCallback<T> {T doInSession(Session session);}
class HibernateUtil {
public T execute(SessionCallback<T> action) {
try{
//open session
//open transcation
T result = action.doInSession(sessionFactory.getCurrentSession());
//commit tx
return result;
}
catch(RuntimeException e) {
//rollback tx
throw e;
}
finally {
//close session
}
}
}
HibernateUtil.execute(new SessionCallback<Void>() {
public Void doInSession(Session session) {
session.createQuery(...);
return null;
}
});
final customerID = ...
Customer customer = HibernateUtil.execute(new SessionCallback<Customer>() {
public Customer doInSession(Session session) {
return (Customer) session.get(Customer.class, customerID);
return null;
}
});
Looking at your code indicates you want JDBC resource local transactions with the session-per-request access idiom, meaning you need the ThreadLocalSessionContext:
查看您的代码表明您需要具有 session-per-request 访问习惯用法的 JDBC 资源本地事务,这意味着您需要 ThreadLocalSessionContext:
hibernate.current_session_context_class=thread
hibernate.transaction.factory_class=JDBCTransactionFactory
Extra
额外的
You might consider switching to JPA as well and moving the Hibernate properties to persistence.xml.
您也可以考虑切换到 JPA 并将 Hibernate 属性移动到 persistence.xml。