使用 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