Java 处理Hibernate事务
目前,我在每个控制器方法中都复制了此代码:Java 处理Hibernate事务,java,hibernate,jakarta-ee,transactions,Java,Hibernate,Jakarta Ee,Transactions,目前,我在每个控制器方法中都复制了此代码: Transaction transaction = HibernateUtil.getSessionFactory().getCurrentSession().getTransaction(); if (!HibernateUtil.getSessionFactory().getCurrentSession().getTransaction().isActive()) { transaction.begin(); } 这是正确的方法还是有更好
Transaction transaction = HibernateUtil.getSessionFactory().getCurrentSession().getTransaction();
if (!HibernateUtil.getSessionFactory().getCurrentSession().getTransaction().isActive()) {
transaction.begin();
}
这是正确的方法还是有更好的方法,也许在我可以参考的单独的类中?如果是,怎么做?每次我试图将它放在一个单独的类中,并从其他类中引用它时,它都失败了
编辑:我正在尝试使用尽可能少的外部库。如果Java在JDK中内置了ORM/JPA实现,我不会使用Hibernate,因为您可以为连接创建单独的类
public class HibernateUtil {
private static final SessionFactory sessionFactory = buildSessionFactory();
@SuppressWarnings("deprecation")
private static SessionFactory buildSessionFactory() {
try {
// Create the SessionFactory from Annotation
return new AnnotationConfiguration().configure().buildSessionFactory();
}
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 SessionFactory getSessionFactory() {
return sessionFactory;
}
}
在服务器端,您可以编写:-
Session session=null;
Transaction tx=null;
try {
session =HibernateUtil.getSessionFactory().openSession();
tx=session.beginTransaction();
} catch (HibernateException e) {
e.printStackTrace();
}finally
{
session.close();
}
如果您有像glassfish这样的应用服务器,它已经嵌入了eclipselink JPA/ORM实现,您可以使用standart JEE注释管理事务
package com.project.stackoverflow;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
public class HibernateUtil {
private static final ThreadLocal threadSession = new ThreadLocal();
private static SessionFactory sessionFactory;
/**
* A public method to get the Session.
*
* @return Session
*/
public static Session getSession() {
Session session = (Session) threadSession.get();
// Open a Session, if this thread has none yet
if ((null == session) || !session.isOpen()) {
logger.info("Null Session");
session = sessionFactory.openSession();
logger.info("Session Opened");
threadSession.set(session);
}
return session;
}
public static void closeSession() {
Session session = (Session) threadSession.get();
// Open a Session, if this thread has none yet
if (null != session) {
session.close();
session = null;
threadSession.set(null);
}
}
return sessionFactory;
}
public void setSessionFactory(SessionFactory sessionFactory) {
logger.info("Inside set session Factory");
this.sessionFactory = sessionFactory;
logger.info("After set session Factory");
}
public static void save(Object obj) {
getSession().save(obj);
getSession().flush();
}
public static void saveOrUpdate(Object obj) {
getSession().saveOrUpdate(obj);
getSession().flush();
}
public static void batchUpdate(Object obj) {
getSession().saveOrUpdate(obj);
getSession().flush();
}
public static void update(Object obj) {
getSession().update(obj);
getSession().flush();
}
public static void delete(Object obj) {
getSession().delete(obj);
getSession().flush();
}
}
你可能会选择这个解决方案。我为Hibernate实例化和使用创建了一个单独的JavaClass。您可以从这里获得满足您需要的会话。希望有帮助:)我自己也遇到过很多次。通常我的第一个建议是,但是我知道您正在试图限制您使用的第三方库的数量 由于您在HibernateUtil类中使用的是静态API,您可能会发现将逻辑整合到一个方法中,并将“在事务中要做什么”代码(根据控制器的不同而不同)放入回调中很有帮助 首先,定义一个接口来描述每个控制器的内部交换行为:
public interface TransactionCallback {
void doInTransaction();
}
现在,在HibernateUtil类中创建一个静态方法来处理事务的开始、提交和回滚(如有必要):
public class HibernateUtil {
public static void inTransaction(TransactionCallback tc) {
Transaction transaction = HibernateUtil.getSessionFactory().getCurrentSession().getTransaction();
if (!HibernateUtil.getSessionFactory().getCurrentSession().getTransaction().isActive()) {
transaction.begin();
try {
tc.doInTransaction();
transaction.commit();
} catch (Exception e) {
transaction.rollback();
}
}
}
}
在控制器中,您可以将新方法与匿名内部类一起使用:
....
HibernateUtil.inTransaction(new TransactionCallback() {
void doInTransaction() {
// do stuff for this controller
}
});
....
这种方法至少应该考虑到您希望消除的重复,并且有足够的空间扩展它以处理特定的异常等。为了避免使用额外的外部库,您可能希望提供一个实现标准J2EE servlet接口的拦截器。这种实现有时被称为视图中的开放会话模式。我引述如下:
当必须处理HTTP请求时,将开始新的会话和数据库事务。在将响应发送到客户端之前,以及在完成所有工作之后,事务将被提交,会话将被关闭
您必须在每个事务(例如控制器请求)之后关闭hibernate事务。 在这种情况下,您将不需要
if (!HibernateUtil.getSessionFactory().getCurrentSession().getTransaction().isActive())
每次请求后都需要调用.close()
最好使用以下代码:
class Controller {
//...
commonActionMethod() {
begin transaction
specificActionMethod();
close transaction
}
此控制器类的子类应实现specificActionMethod()
代码是干净的。交易是安全的。不需要第三方LIB 如果您在项目中使用spring。我建议使用TX-UsingSpringAOP,因为您只需要为事务指定切入点。Spring AOP TX将根据您的切入点开始并提交事务,并且在发生异常时也可以回滚TX。请浏览示例的链接-
如果您开始管理实例(服务),您可以通过FactoryPattern+JDK代理(实际接口)+AOP概念的组合来实现许多魔术 我使用了这种技术 我的Servlet上下文如下所示:
<beans:bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close" p:driverClassName="${jdbc.driverClassName}"
p:url="${jdbc.databaseurl}" p:username="${jdbc.username}" p:password="${jdbc.password}" />
<beans:bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<beans:property name="dataSource" ref="dataSource" />
<beans:property name="configLocation">
<beans:value>classpath:hibernate.cfg.xml</beans:value>
</beans:property>
<beans:property name="configurationClass">
<beans:value>org.hibernate.cfg.AnnotationConfiguration</beans:value>
</beans:property>
<beans:property name="hibernateProperties">
<beans:props>
<beans:prop key="hibernate.dialect">${jdbc.dialect}</beans:prop>
<beans:prop key="hibernate.show_sql">true</beans:prop>
</beans:props>
</beans:property>
</beans:bean>
<beans:bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<beans:property name="sessionFactory" ref="sessionFactory" />
</beans:bean>
<tx:annotation-driven transaction-manager="transactionManager" />
Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
session.save(userAccount);
transaction.commit();
session.close();
每当我想使用会话或执行任何操作时,我都会这样做:
<beans:bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close" p:driverClassName="${jdbc.driverClassName}"
p:url="${jdbc.databaseurl}" p:username="${jdbc.username}" p:password="${jdbc.password}" />
<beans:bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<beans:property name="dataSource" ref="dataSource" />
<beans:property name="configLocation">
<beans:value>classpath:hibernate.cfg.xml</beans:value>
</beans:property>
<beans:property name="configurationClass">
<beans:value>org.hibernate.cfg.AnnotationConfiguration</beans:value>
</beans:property>
<beans:property name="hibernateProperties">
<beans:props>
<beans:prop key="hibernate.dialect">${jdbc.dialect}</beans:prop>
<beans:prop key="hibernate.show_sql">true</beans:prop>
</beans:props>
</beans:property>
</beans:bean>
<beans:bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<beans:property name="sessionFactory" ref="sessionFactory" />
</beans:bean>
<tx:annotation-driven transaction-manager="transactionManager" />
Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
session.save(userAccount);
transaction.commit();
session.close();
我想这会有帮助的 为什么不使用Spring或CDI等提供的声明性事务和AOP?如何实例化控制器?我可以为
服务
之类的方法调用想出一个解决方案,但不确定控制器。您尝试过TransactionManager和LocalSessionFactoryBean吗?这正是我要问的如何避免的。Apache不是java ee服务器。因此,您需要外部ORM(如hibernate)和外部事务管理框架(如spring)。用手做事务很痛苦。“会话将被关闭。”-不必要,这是使用DAO模式的实现。