问题
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.
Please note it 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.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 documentation mu current configuration is as following:
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;
回答1:
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.
Beside the fact that you should rely on Hibernate 4 bootstrap mechanism, your code also has the following problems:
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.
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.
If you still don't want to let the HibernateUtil go, you can at least use a mechanism similar to JDBCTemplate to abstract the session/transaction management in a template method, while supplying the business code in a Callable, which for you might look like:
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:
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.
回答2:
Access to a single instance of SessionFactory within your aplication is all that is needed.
The following information is all (available) from the Hibernate 4.3 manual chapters 2.2. Contextual sessions and 13. Transactions and Concurrency.
"A SessionFactory is 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 Session is 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."
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.
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.
If you use JTA, replace ThreadLocalSessionContext
with org.hibernate.context.internal.JTASessionContext
and follow the idioms described in Using 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 question which has related documentation here in the Hibernate manual.
来源:https://stackoverflow.com/questions/23646389/how-to-configure-and-get-session-in-hibernate-4-3-4-final