我有这个问题:
我准备与实体的视图
@RequestMapping("/admin/modifyImplant/{id}")
public ModelAndView modifyImplant(@PathVariable Integer id) {
ModelAndView mav = new ModelAndView();
Implant currentImplant =impDAO.findById(id); //this is the dao
Implanttype it= currentImplant.getImplanttype();
Implantinverter ii=new Implantinverter();
ArrayList<Implantpanel> implantpanels = new ArrayList<Implantpanel>();
try{
ii= (Implantinverter)currentImplant.getImplantinverters().toArray()[0];
implantpanels=(ArrayList<Implantpanel>) imppanelDAO.findByProperty("implant",currentImplant );
}
catch (Exception ex){
//TODO
}
mav.addObject("implantpanels", implantpanels);
mav.addObject("implantinverter",ii);
mav.addObject("implant", currentImplant); //THIS IS THE ENTITY I MEAN
mav.addObject("implanttype",it);
mav.setViewName("/implant/modifyImplant.jsp");
return mav;
}
这个jsp的代码方法(一小部分代码)
<form:form action="${pageContext.request.contextPath}/admin/finalizeModifyImplant/${implant.id}" method="POST" modelAttribute="implant">
<table cellpadding="0" cellspacing="0" id="viewTable" >
<tbody>
<tr>
<td class="label">
Name:
</td>
<td>
<form:input id="User_namesurname" path="businessname" cssStyle="width:300px;"/>
</td>
</tr>
实体字段以此类推。实体有一些实体相关,通过外键连接(如implanttype、implantinverter、implantpanels)。
提交到这个控制器:
@RequestMapping(value = "/admin/finalizeModifyImplant/{id}",
method = { RequestMethod.GET,RequestMethod.POST })
public ModelAndView finalizeModifyImplant(@PathVariable int id, @Valid @ModelAttribute Implant implant, BindingResult result){
ModelAndView mav=new ModelAndView();
mav.setViewName("../../admin/modifyImplant/"+id);
if (result.hasErrors()){
return mav;
}
implant.setId(id); //NOTICE WHAT I NEED TO DO HERE!
Implant oldImplant= impDAO.findById(id);
implant.setImplantinverters(oldImplant.getImplantinverters());
implant.setImplantpanels(oldImplant.getImplantpanels());
implant.setImplanttype(oldImplant.getImplanttype());
implant.setInverters(oldImplant.getInverters());
implant.setPvgis(oldImplant.getPvgis());
try{
impDAO.merge(implant); //here i call getSession().merge()
}catch(RuntimeException re){
return mav;
//TODO: errors
}
当我收到表单提交(这是一个更新)时,我有以下问题: 1. 返回的植入程序没有 id(字段 id=null) 2. 相关实体也为空。
以下是植入实体
public class Implant implements java.io.Serializable {
// Fields
private Integer id;
private Pvgis pvgis;
private Gateway gateway;
private Implanttype implanttype;
@JsonIgnore //I NEED TO JSONIGNORE IT BECAUSE IT HAS A RECURSIVE CALL ON IMPLANT
private Users users;
@NotEmpty
private String nameimplant;
private String place;
private double latitude;
private double longitude;
private double expectedpower;
private double tolerance;
[...] and many other fields
以及相关的implant.hbm.xml
<hibernate-mapping>
<class name="it.pstmarche.model.Implant" table="implant" schema="public">
<id name="id" type="integer">
<column name="id" />
<generator class="identity" />
</id>
<many-to-one name="pvgis" class="it.pstmarche.model.Pvgis" fetch="select">
<column name="idpvgis" />
</many-to-one>
<many-to-one name="gateway" class="it.pstmarche.model.Gateway" fetch="select">
<column name="idgateway" />
</many-to-one>
<many-to-one name="implanttype" class="it.pstmarche.model.Implanttype" fetch="select">
<column name="implanttype" />
</many-to-one>
<many-to-one name="users" class="it.pstmarche.model.Users" fetch="select" >
<column name="iduser" />
</many-to-one>
<property name="nameimplant" type="string">
<column name="nameimplant" not-null="true">
<comment>Name</comment>
</column>
我真的不知道如何正确进行更新,因为当我尝试从数据库(通过 findById 或直接查询)获取更新的实体时,我得到随机结果,有时我得到正确和更新的实体,有时我得到旧的实体!!真的很随意。
我试过:1.删除缓存( session.setCacheMode(CacheMode.IGNORE); )没有结果 2.添加 getSession().flush(); getSession().close(); 在合并方法的最后,即:
public void merge(Implant currentImp){
//Session session = HibernateSessionFactory.getSessionFactory().openSession();
Transaction tx= getSession().beginTransaction();
if (currentImp.getId() != null) { // it is an update
getSession().merge(currentImp);
tx.commit();
//getSession().update(currentImp);
log.debug("MERGE");
getSession().flush();// THAT'S THE ADD
session.close(); //THIS IS ALSO
} else { // you are saving a new one
getSession().saveOrUpdate(currentImp);
tx.commit();
getSession().flush();
getSession().close();
log.debug("Save sou");
}
我真的不知道用 Hibernate + Spring 实现更新的正确方法是什么!任何帮助表示赞赏。谢谢
编辑:也许我的问题不清楚。当前的问题是,在我随机保存或合并实体后,当我搜索实体(例如通过查询 findById(int id))时,我随机得到旧实体(我认为它仍在休眠会话中)。解决此问题的唯一方法是清除会话(getSession().clear()),但在此之后我显然得到了延迟异常 -当我尝试获取我需要的实体的相关实体时,没有代理在清除中会议!真可惜
2EDIT:感谢 Tim H。但是,我仍然面临与处理休眠会话相关的问题。前言:我使用每个线程的休眠会话,比如
private static final ThreadLocal<Session> threadLocal = new ThreadLocal<Session>();
private static Configuration configuration = new Configuration();
private static org.hibernate.SessionFactory sessionFactory;
private static String configFile = CONFIG_FILE_LOCATION;
static {
try {
configuration.configure(configFile);
sessionFactory = configuration.buildSessionFactory();
} catch (Exception e) {
System.err
.println("%%%% Error Creating SessionFactory %%%%");
e.printStackTrace();
}
}
private HibernateSessionFactory() {
}
public static Session getSession() throws HibernateException {
Session session = (Session) threadLocal.get();
if (session == null || !session.isOpen()) {
if (sessionFactory == null) {
rebuildSessionFactory();
}
session = (sessionFactory != null) ? sessionFactory.openSession()
: null;
threadLocal.set(session);
}
return session;
}
现在,假设我在 Tomcat 线程 1 上从数据库加载实体 x。实体值为100。加载后我无法关闭会话,因为它是延迟初始化的(如果我关闭会话,我可能会遇到延迟初始化异常 - 无代理/会话)。
之后,我更新线程 2 上实体 x 的值。现在的值为50。
最后,我加载了值,但是 tomcat 让我进入线程 1,实体仍在线程的会话中,值仍然是 100。我得到的是旧值而不是新值!!
所以,在我的 jsp 完成之前我无法关闭会话(我使用惰性字段),我必须通过以下方式在 jsp 结束时关闭会话:<% HibernateSessionFactory.getSession().close (); %> 这太可怕了!我将视图与模型结合起来!有一种模式可以安全地做到这一点?