使用 remove() 方法删除
最后,让我们看看删除一个对象。原则上,从数据库中删除对象非常简单,但正如他们所说,存在细微差别。有六个这样的细微差别:
- 使用remove()方法删除
- 为公司除名
- 被孤儿移除
- 使用 JPQL 删除
- 通过 NativeQuery 删除
- 软删除()
我们将从最明显的解决方案开始——调用remove()方法。
User user = new User();
user.setName("Kolyan");
session.persist(user); // add an object to the database
session.flush();
session.clear(); // close the session
user = (User) session.find(User.class, user.getId() ); //receive the object from the database
session.remove(user);
session.flush();
session.clear(); // close the session
//here the object is actually deleted.
调用flush()方法或关闭事务后,才会执行数据库中的实际操作。
级联删除
大家还记得我们学SQL的时候,依赖表是可以写CONSTRAINT的。其中一个是这样的:
CONSTRAINT ONDELETE REMOVE
它的意思是,如果我们有一个包含子实体的表,那么当分配父实体时,必须删除它的所有子实体。
假设我们把用户的个人信息存放在某个地方,并在数据库中设置CONSTRAINT,这样当用户被删除时,这条数据也被删除了。然后我们只需要删除父对象,所有子对象将在基础级别删除:
User user = new User();
UserPrivateInfo info = new UserPrivateInfo();
user.setPrivateInfo(info);
session.persist(user); //add the object to the database, the info object will also be saved to the database
session.flush();
session.clear(); // close the session
user = (User) session.find(User.class, user.getId() ); //receive the object from the database
session.remove(user);
session.flush();
session.clear(); // close the session
// here the user and info objects are actually removed from the database.
被孤儿移除
还有另一种类型的移除称为孤儿移除。它与以前的版本有些相似。当子实体与父实体的关系中断时,子实体将被删除。在这种情况下,通常不会删除父实体。
假设我们有一个用户,他有一个帖子列表:
User user = new User();
UserMessage message = new UserMessage();
user.getMessageList().add(message);
session.persist(user); //add the object to the database, the message object will also be saved to the database
session.flush();
session.clear(); // close the session
user = (User) session.find(User.class, user.getId() ); //receive the object from the database
UserMessage message2 = user.getMessageList().get(0); //get the user's message
user.getMessageList().remove(message2); //remove the message from the list
session.flush();
session.clear(); // close the session
// here the message2 object is actually removed from the database
还有一个重要的细微差别,如果我们希望 Hibernate 实现此行为,则必须在使用注释链接两个实体时明确指定:
@Entity
public class User {
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
private List<UserMessage> messageList = new ArrayList<UserMessage>();
}
通过 JPQL 删除
另一种删除对象的有趣方法是编写 HQL(或 JPQL)查询。只是不要忘记在最后调用executeUpdate()方法,否则 Hibernate 会创建一个只读事务,您将不会得到任何删除。
例子:
User user = new User();
session.persist(user); // add an object to the database
session.flush();
session.clear(); // close the session
session.createQuery("delete from User where id = :id")
.setParameter("id", user.getId())
.executeUpdate();
更改数据库不会以任何方式更改现有的实体对象。
通过 NativeQuery 删除
同样,您可以删除并调用 NativeQuery。
例子:
User user = new User();
session.persist(user); // add an object to the database
session.flush();
session.clear(); // close the session
session.createNativeQuery("DELETE FROM user WHERE id = :id")
.setParameter("id", user.getId())
.executeUpdate();
数据库中的更改不会以任何方式影响现有的实体对象。
软删除
有时,不是删除数据库中的数据,而是简单地将其标记为已删除会很方便。然后,这些数据可以参与各种场景。首先,这样的删除很容易恢复——这些行可以再次被标记为活动的。
其次,“存档”此类远程数据很有用,因为在某些情况下,服务器的行为受到法律等的监管。但是,如果您将数据标记为已删除,那么只有您知道它已被删除。Hibernate 仍然会找到这些数据并在排序时使用它。
因此,Hibernate 的创建者想出了一个特殊的注释,可以将对象标记为活动的。例子:
@Entity
@Where(clause = "DELETED = 0") //in all WHEREs "AND DELETED = 0" will be added
public class User {
// mapping fields
@Column(name = "DELETED") // if the value in the DELETED column == 0, then the record is alive, if 1 - dead
private Integer deleted = 0;
//getters and setters
public void softDeleted() {
this.deleted = 1; //mark the post as dead
}
}
要将对象标记为已删除,您只需要对其调用softDeleted()方法:
User user = new User();
session.persist(user); // add an object to the database
session.flush();
session.clear(); // close the session
user = (User) session.find(User.class, user.getId() ); //receive the object from the database
user.softDeleted(); // mark the object as deleted
session.flush();
session.clear(); // close the session
//this object will no longer reside via Hibernate
GO TO FULL VERSION