我们正在使用JSF 2.0(primefaces)和Hibernate 3.6.1开发一个应用程序 我们正在遵循让应用程序的更高级别与DAL框架无关的方法....这意味着我们不使用每请求会话方法,但我们配置Hibernate来处理会话每线程。 我们已经实现了一个类,它的作用是处理“原子操作”,在它们不存在时打开会话和事务,并简单地将其他数据库操作挂钩到现有事务,使它们成为一部分主要操作,让他们知道他们是独立执行还是作为更大的操作的一部分。 这是我们的OperationManager的代码:
public class OperationManager implements IOperationManager {
Transaction tx = null;
boolean isInternalTransaction = false;
/* (non-Javadoc)
* @see alekso.npe.dal.IOperationManager#beginOperation()
*/
@Override
public Session beginOperation(){
Session session = SessionFactoryUtil.getInstance().getCurrentSession();
if (session.getTransaction().isActive()) {
isInternalTransaction = false;
tx = session.getTransaction();
}
else {
isInternalTransaction = true;
tx = session.beginTransaction();
}
return session;
}
/* (non-Javadoc)
* @see alekso.npe.dal.IOperationManager#commitOperation()
*/
@Override
public void commitOperation(){
if (isInternalTransaction)
tx.commit();
}
/* (non-Javadoc)
* @see alekso.npe.dal.IOperationManager#rollbackOperation()
*/
@Override
public void rollbackOperation(){
if (isInternalTransaction)
tx.rollback();
}
}
SessionFactoryUtil类是hibernate的“经典”工厂工具,随处可见......我们选择了这个实现:
public class SessionFactoryUtil {
final static Logger log = Logger.getLogger(SessionFactoryUtil.class);
/** The single instance of hibernate SessionFactory */
private static org.hibernate.SessionFactory sessionFactory;
/**
* disable contructor to guaranty a single instance
*/
private SessionFactoryUtil() {
}
static {
// Annotation and XML
// sessionFactory = new
// AnnotationConfiguration().configure().buildSessionFactory();
// XML only
try {
sessionFactory = new Configuration().configure().buildSessionFactory();
} catch (Exception e) {
log.error("Errore nella creazione del session factory", e);
System.out.println("Errore nella creazione del session factory");
}
}
public static SessionFactory getInstance() {
try{
return sessionFactory;
} catch (Exception ex)
{
log.error("errore nella creazione della session di hibernate", ex);
return null;
}
}
/**
* Opens a session and will not bind it to a session context
*
* @return the session
*/
public Session openSession() {
return sessionFactory.openSession();
}
/**
* Returns a session from the session context. If there is no session in the
* context it opens a session, stores it in the context and returns it. This
* factory is intended to be used with a hibernate.cfg.xml including the
* following property <property
* name="current_session_context_class">thread</property> This would return
* the current open session or if this does not exist, will create a new
* session
*
* @return the session
*/
public Session getCurrentSession() {
return sessionFactory.getCurrentSession();
}
/**
* closes the session factory
*/
public static void close() {
if (sessionFactory != null)
sessionFactory.close();
sessionFactory = null;
}
}
现在,我们如何使用运营经理? 简单地说,无论谁想要对db上的原子操作负责,都可以在OperationManager上调用该方法。
public class BL1{
public void highMethod() {
IOperationManager om = new OperationManager();
BL2 bl2 = new BL2();
BL3 bl3 = new BL3();
try {
om.beginOperation();
bl2.midMethod();
bl3.midMethod();
om.commitOperation();
} catch (Exception ex) {
omrollbackOperation();
}
}
}
public class BL2{
public void midMethod() {
IOperationManager om = new OperationManager();
DAL1 dal1 = new DAL1();
DAL2 dal2 = new DAL2();
try {
om.beginOperation();
dal1.lowMethod1();
dal2.lowMethod1();
om.commitOperation();
} catch (Exception ex) {
omrollbackOperation();
}
}
}
public class BL3{
public void midMethod() {
IOperationManager om = new OperationManager();
DAL1 dal1 = new DAL1();
DAL2 dal2 = new DAL2();
try {
om.beginOperation();
dal1.lowMethod2();
dal2.lowMethod2();
om.commitOperation();
} catch (Exception ex) {
omrollbackOperation();
}
}
}
public class DAL1{
public void lowMethod1() {
IOperationManager om = new OperationManager();
Session session = nullM
try {
session = om.beginOperation();
// do some work on session
session.saveOrUpdate(...);
session.load(..);
session.somethingElse(....);
om.commitOperation();
} catch (Exception ex) {
omrollbackOperation();
}
}
public void lowMethod2() {
IOperationManager om = new OperationManager();
Session session = nullM
try {
session = om.beginOperation();
// do some work on session
session.saveOrUpdate(...);
session.load(..);
session.somethingElse(....);
om.commitOperation();
} catch (Exception ex) {
omrollbackOperation();
}
}
}
public class DAL2{
public void lowMethod1() {
IOperationManager om = new OperationManager();
Session session = nullM
try {
session = om.beginOperation();
// do some work on session
session.saveOrUpdate(...);
session.load(..);
session.somethingElse(....);
om.commitOperation();
} catch (Exception ex) {
omrollbackOperation();
}
}
public void lowMethod2() {
IOperationManager om = new OperationManager();
Session session = nullM
try {
session = om.beginOperation();
// do some work on session
session.saveOrUpdate(...);
session.load(..);
session.somethingElse(....);
om.commitOperation();
} catch (Exception ex) {
omrollbackOperation();
}
}
}
}
这样做,如果我调用BL1.highMethod,下面的每一个(从内部收集的方法)将在它开始的转换下:调用方法的om.beginOperation(),只返回由BL1启动的会话.highMethod,以及所调用方法的om.commitOperation或om.rollBackOperation,根本不做任何事情,留下在BL1.highMethod中创建的om实例提交/回滚和关闭会话的责任。 但是如果我们直接调用BL2.midMethod,那么管理会话和事务的责任就是它自己的。如果我们直接调用DAL1.lowMethod1,也会发生同样的情况。 模式是:如果我(作为一种方法)没有调用beginOperation,我用来完成工作的所有东西都将自己处理会话/事务;如果我开始操作,那么我将负责管理会话/转换。 我希望我说清楚。
现在,在我看来,这是一种非常聪明的方法......直到出现问题。 出了什么问题,真的很难说。 简单的应用程序开始变得怪异:有时应用程序在更新期间(数据库谈论锁定行,但查看刷新到db的sql语句的序列,在没有意义的情况下)在db上创建锁定;有时没有锁定,也没有记录错误,但是应用程序似乎读取了“旧数据”...就像我们几秒前做的操作一样,不存在......而且它似乎就在那里30秒之后(或10或60 ......这取决于)。我的意思是,非常剧烈的行为。我们只看到日志上的一些错误,当我们点击db上的rowlock时,这会导致一个长时间的事务,否则似乎没有错。为了使事情变得更复杂,应用程序上的用户操作的相同确切顺序(在同一记录上,由同一用户等...)有时可以工作,有时不工作。 这种行为发生在我们使用OperationManager类重构引入上面显示的模式的代码时。
那里的任何人都知道我们做错了什么,为什么这种模式不能按预期工作? 我对发布的问题的长度表示道歉......
答案 0 :(得分:0)
SessionFactoryUtil
不是“经典”的东西。它如此普遍的唯一原因是因为它被用作first chapter of the Hibernate reference guide教程的一部分。它只是 tutorial 代码,即使参考指南从未说过,我也会:此代码永远不会用于生产。 答案 1 :(得分:0)
实际上我解决了输入上述问题的问题! 在代码的最后一部分,调用OperationManager的类和方法,我声明并在方法内部实现了OperationManager对象。这种方式将标志isInternalTransaction绑定到方法本身。 在我的实际代码中,在类中我在类级别声明了OperationManager:这意味着调用同一个类实例的不同方法,打破了模式,因为isInternalTransaction falg从owner方法外部修改了! 所以这是我唯一的错误:我使用我为模式创建的服务,而不是模式本身。 现在它很好用,即使没有Spring。
这对我有好处,不仅仅是因为我不需要学习春天,而是因为我更喜欢在问题/模式中深入挖掘,并理解为什么以及如何运作......不只是采取有效的方法,并认为它是神奇的;)