我之前的问题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的存在。