Java 休眠:更新对象->;还将执行不需要的delete语句
我在Java应用程序中使用Hibernate作为ORM。 我有一个项目人员很多关系,该项目是地图所有者 现在我有一个问题,我想更新项目。项目有一个id,一个名称。。。和一组人。在执行更新时,将删除Project_Person join表中的所有人员,控制台上的SQL语句:Java 休眠:更新对象->;还将执行不需要的delete语句,java,hibernate,Java,Hibernate,我在Java应用程序中使用Hibernate作为ORM。 我有一个项目人员很多关系,该项目是地图所有者 现在我有一个问题,我想更新项目。项目有一个id,一个名称。。。和一组人。在执行更新时,将删除Project_Person join表中的所有人员,控制台上的SQL语句: Hibernate: update Project set description=?, name=? where id=? Hibernate: delete from Project_Person where projec
Hibernate: update Project set description=?, name=? where id=?
Hibernate: delete from Project_Person where project_id=?
但我不希望执行delete语句
我的Java应用程序中有:
this.projService.updateProject(p);
其中p是项目,但以POJO方式,没有人员集。所以我想,为了让它“Hibernate就绪”,我在一个单独的事务中将其设置为findProjectById,因此我从数据库中获取项目:
Project proj = this.projService.findProjectById(p.getId());
proj.setName(p.getName());
proj.setDescription(p.getDescription());
所以我得到Hibernate就绪的项目对象,更改值,然后告诉他更新项目。但是,该集在调试器视图中是一个PersistentSet,其中没有人(我认为,因为他们是延迟加载的)。
但是用一个
session.update(p);
在新事务中,我得到update语句和不需要的delete语句。
如何避免delete语句
我是否必须创建一个特殊的SQL语句,以便只更新要更新的数据库表字段?还是有其他/更好的解决方案
致以最良好的祝愿
更新 这会引发LazyInitializationException:
public Project findProjectById(int projectId) {
SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
Session sess = sessionFactory.getCurrentSession();
Transaction tx = sess.beginTransaction();
try {
Project project = (Project)sess.createQuery("from Project where id = "+projectId).list().get(0);
tx.commit();
System.out.println(project.getPersons().size());
return project;
} catch (IndexOutOfBoundsException ex) {
return null;
}
}
调试器的屏幕截图:
HibernateUtil
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class HibernateUtil {
// SessionFactory of Hibernate
private static final SessionFactory sessionFactory;
static {
try {
sessionFactory = new Configuration().configure("/hibernate.cfg.xml").buildSessionFactory();
}
catch (Throwable ex) {
System.err.println("Initial SessionFactory creation failed. " + ex);
throw new ExceptionInInitializerError(ex);
}
}
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
}
发送前的屏幕截图。提交()
这意味着(正如您所建议的)您的收藏是空的。但这并不是由于延迟加载——调试器将允许您加载集合。也许它是空的,因为另一个原因。通过显示collection.size()
来确认这一点
问题的另一部分是级联。如果您已定义级联删除孤立项
,请将其删除,或确保集合已实际填充。您不需要调用“更新”
以下代码:
Project proj = this.projService.findProjectById(p.getId());
proj.setName(p.getName());
proj.setDescription(p.getDescription());
然后不需要更新,因为项目引用是持久的,对它的任何更改都将被保存。这是hibernate和其他ORM的一个特性,称为透明持久性
有关hibernates更新方法的更多信息,请参阅。如果在新事务中更新项目对象,则可能应该使用
session.merge(project)
这可能会检测到未初始化的PersistentSet,用新会话中的新PersistentSet替换它,并确保该集合的条目不会被删除。否则,Hibernate可能无法处理该集合,因为创建该集合的事务已经关闭,并且假定该集合为空。我没有定义像delete orphan这样的级联。我更深入地研究了该项目的人员:没有人员。集合的size()总是会返回LazyInitialization错误。我在问题中举了一个例子,它引发了LazyInit异常。然后将断点放在会话尚未关闭的方法中。我不太确定,如果我理解正确,但我放了一个指向我问题的屏幕截图的链接,因此,您可以看到调试器视图和带有断点的源代码。@Tim-在返回对象之前,将断点放在
projectService
中。会话在那里是可用的(并且在控制器中是关闭的,也许您的服务层周围有一个事务管理器)非常奇怪。尝试在提交事务之前打印大小。我将调试器的屏幕截图放在tx.commit()行之前。更新:把这里放在tx.commit()行前面getPersons().size(),我明白了!因此,会话在提交后关闭。那么,对于不需要的SQL delete语句,我能做些什么来解决这个问题呢?是的,但是我的模型关闭了事务,所以我需要tzo在我的例子中调用它。你的链接是好的,但我不使用它在这种情况下。