我之前的问题How to wrap Wicket page rendering in a Spring / Hibernate transaction?让我开始思考 Wicket 中的事务划分。
虽然通过将业务逻辑下移到 Spring 托管层可以轻松解决该示例,但在其他地方这是不可能的。
我有一个通用的 DAO 类,由 Hibernate 实现,具有
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 的存在。
关于java - 如何对 Wicket/Spring 页面 View 使用单个事务?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6161743/