我之前的问题How to wrap Wicket page rendering in a Spring / Hibernate transaction?使我开始思考Wicket中的事务划分。

尽管该示例通过将业务逻辑向下移动到Spring管理的层很容易解决,但在其他地方则不可能。

我有一个由Hibernate实现的通用DAO类,

public class HibernateDAO<T> implements DAO<T> {

    protected final Class<T> entityClass;
    private final SessionFactory sessionFactory;

    @Transactional
    public T load(Serializable id) {
        return (T) getSession().get(entityClass, id);
    }

    @Transactional
    public void saveOrUpdate(T object) {
        getSession().saveOrUpdate(object);
    }

}


和一个通用的模型来获取它

public class DAOEntityModel<T> extends LoadableDetachableModel<T>{

    private DAO<T> dao;
    private final Serializable id;

    public DAOEntityModel(DAO<T> dao, Serializable id) {
        this.dao = dao;
        this.id = id;
    }

    public <U extends Entity> DAOEntityModel(DAO<T> dao, U entity) {
        this(dao, entity.getId());
    }

    public Serializable getId() {
        return id;
    }

    @Override
    protected T load() {
        return dao.load(id);
    }

}


现在,我有一个更改实体的最小表单

public class ScreenDetailsPanel extends Panel {

    @SpringBean(name="screenDAO") private DAO<Screen> dao;

    public ScreenDetailsPanel(String panelId, Long screenId) {
        super(panelId);
        final IModel<Screen> screenModel = new DAOEntityModel<Screen>(dao, screenId);
        Form<Screen> form = new Form<Screen>("form") {
            @Override protected void onSubmit() {
                Screen screen = screenModel.getObject();
                dao.saveOrUpdate(screen);
            }};
        form.add(
            new TextField<String>("name", new PropertyModel<String>(screenModel, "name")));
        add(form);
    }
}


到目前为止一切顺利-感谢您坚持使用!

所以我的问题是-提交表单时,PropertyModel将加载screenModel,这将在@Transactional dao.load(id)所描述的事务中发生。当为dao.saveOrUpdate(object)启动的(不同)事务提交时,将提交更改。在这两个时间之间,所有投注均关闭,因此该对象可能不再存在于要提交的数据库中。

我永远不能完全确定数据库代码和事务。尽管我可以构建其他更复杂但更危险的方案,但我是否应该不大理会呢?如果不是,我看不到如何在单个事务中划分整个页面逻辑,这是我的直觉告诉我我应该针对的目标。

最佳答案

通常,您可以通过将@Transactional批注放置在前端层代码使用的服务级别类中来解决此问题,该类将DAO操作包裹起来-以便在同一事务中进行加载和保存。换句话说,您可以通过在表单和DAO代码之间创建一个代码层(一个“服务层”)来解决此问题,该服务层提供业务级逻辑并在表示层中隐藏DAO的存在。

10-05 21:22
查看更多