4.1 交易和数据库完整性

数据库的正常运行模式是每分钟从数百个不同的客户端接收数千个请求。在这种情况下,经常会出现从不同查询访问相同数据的情况。

不太常见,但有时会出现一个请求读取某一行,而另一个请求同时更改它的情况。想象一下,如果有人读到一行只改变了一半会怎样?没什么好的。

这个问题可以通过几种方式解决。首先,您可以只锁定更改的行。既适合阅读,也适合写作。这种方法有效,但基地的速度受到很大影响。

第二种方法是将字符串锁定为只写。但是,当有人试图阅读部分修改的行时,仍然会出现问题。结论 - 不应该出现线路被部分更改的情况。

因此,他们想出了第三种方法——交易。事务是一组操作,这些操作要么一起执行,要么根本不执行。不能出现部分动作执行了而第二部分没有执行的情况。如果不可能进行所有更改,则回滚所有已进行的更改。

任何现代 SQL 服务器都允许您仅在事务中更改数据。您打开一个事务,对任意数量的表进行任何更改,然后提交该事务。SQL Server 然后尝试进行更改。如果一切正常,那么它们将被添加到通用数据库中。如果出现问题,则所有更改都将被取消。

Hibernate 也使用这种范式。这就是为什么在上一讲中我们看到,当试图将 Employee 对象保存到数据库时,首先打开一个事务,保存后,它被提交。

我们将更详细地探讨这个主题,但现在,只知道为什么需要事务以及它们通常用在什么地方。

4.2 获取对象

如果 Hibernate 执行获取数据的请求,则无需显式开启事务。如果 Hibernate 认为合适,它自己会这样做:它有自己的设置,以及 SQL 服务器的设置。

我们将分析如何使用数据库。其中最简单的是通过ID获取对象。为此,请使用会话get()对象上的方法。这种请求的一般形式:

Class Name = session.get(Class.class, ID);

例子:

public User getUserById(Integer id) {
    try (Session session = sessionFactory.openSession()) {
        User user = session.get(User.class, id);
        return user;
    }
}

4.3 保存(添加)对象

如果你想将你的对象保存到数据库中,那么查询将在 SQL 级别执行插入. 因此,您的操作必须作为单独的交易执行。另外,最好使用会话persist()对象的持久化方法。

这种请求的一般形式:

session.persist(An object);

该方法persist()不仅改变了基础,而且改变了对象本身。问题是,当我们向数据库中添加一个对象时,这个对象在添加之前还没有自己的ID。好吧,通常是这样,尽管有细微差别。添加对象后已经有一个 ID 。

public boolean saveUser(User user) {
    try (Session session = sessionFactory.openSession()) {
            Transaction transaction = session.beginTransaction();
            session.persist(user);
            transaction.commit();
            return true;
    }
    catch() {
    return false;
   	}
}

Session对象也有一个save()执行类似功能的方法。只是方法save()是旧的Hibernate标准,方法persist()是JPA标准。

4.4 删除对象

如果要删除现有对象,那么这样做非常容易。为此,会话对象有一个特殊的方法 - remove()

这种请求的一般形式:

session.remove(An object);

当然,让我们用一个例子来编写代码:

public boolean removeUser(User user) {
    try (Session session = sessionFactory.openSession()) {
            Transaction transaction = session.beginTransaction();
            session.remove(user);
            transaction.commit();
            return true;
    }
    catch() {
    return false;
   	}
}

你问为什么这么难?

好吧,首先,对数据库的任何更改总是会产生不同且并不总是显而易见的后果。其次,这个对象可能有与之关联的子对象,等等。所以删除场景通常很重要。