0

我正在处理一些遗留代码,这些代码在某些地方没有一种干净可靠的方式来获取给定实体的 JPA EntityManager(或 Hibernate Session),以根据需要调用 lock(...) 方法。本质上,我们在实体中有一个方法,需要执行以下操作:

@Entity
public class SomeEntity {
    @Column(...)
    @Basic(...)
    private String name; 

    ... 

    public void doSomething(/* arguments irrelevant */) {
         ...
         myCurrentEntityManagerOrSession.lock(...);
         ...
    }

    ...
}

问题是如何做到这一点 - 如何访问该实体管理器或会话?我们设计了两种方法来完成我们需要的事情,即使两者都有效,但没有一种是可取的:

选项 #1 - 令人尴尬的属性触发器

    final String originalName = getName();
    setName("modified " + originalName);
    setName(originalName);

...“欺骗”Hibernate(我们使用字节码增强,顺便说一句)来执行锁定本身,然后撤消更改但保留锁定(我们会在任何“廉价”属性上执行此操作)。

选项 #2:不恰当地滥用 Hibernate 字节码增强及其内部 API 的反射

  private static final Method HIBERNATE_ENTITY_ENTRY_GETTER;
    static {
        Method getter;
        try {
            getter = SomeEntity.class.getMethod("$$_hibernate_getEntityEntry");
        } catch (NoSuchMethodException e) {
            /// Oooh .. not good!
            getter = null;
        }
        HIBERNATE_ENTITY_ENTRY_GETTER = getter;
    }
    public Session getEntitySession()  {
        try {
            final MutableEntityEntry entry = (MutableEntityEntry) HIBERNATE_ENTITY_ENTRY_GETTER.invoke(this);
            return (Session) entry.getPersistenceContext().getSession();
        } catch (RuntimeException e) {
            throw e;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    public void lock(final LockMode lockMode) {
        getEntitySession().lock(this, lockMode);
    }
    public void lock() {
        lock(LockMode.OPTIMISTIC_FORCE_INCREMENT);
    }

是否有适当、干净的方法来获取当前管理/拥有特定实体的 EntityManager / Session?当然,我们知道底层引擎必须已经知道这一点……但这似乎被很好地隐藏起来了。

附加说明:ThreadLocal 在某些项目中可能是一个答案,但在这个项目中不是。不要问。

4

0 回答 0