是否需要开始事务以在数据库中查找对象?

问题描述

我知道以下是与数据库中的对象交互所必需的:

db.getTransaction().begin();
//Code to modify objects in the data base
db.getTransaction().commit();

但是当我使用函数 find(object.class,object.id) 时有必要吗?

解决方法

在数据库中查找对象是否需要开始事务?

取决于您对“交易”一词的含义。

数据库在事务中做所有事情。时期。因此,简单地说,“是”,必须开始事务,因为不这样做就无法与数据库交互。

然而,数据库有一个“方便”的特性,您可以像不存在事务一样工作。这是个谎言;它只是意味着每条语句你发送到数据库都被默默地包裹在“START TRANSACTION;”中和'提交;'调用。这被称为“自动提交”模式(而不是“无事务模式”),因为这是正确的词:它在每个事务后自动提交。

因此,在基本的 JDBC(Java 中所有基于 SQL 的数据库交互的基础层,但请注意,您正在使用构建在它之上的某种库!),您可以只运行一个使用自动提交模式选择查询,“无需”处理事务。

但是,自动提交模式通常是个坏主意。

事务是数据库设计的基础。即使您只是进行“读取”查询,事务仍然很重要。它们保证一致性和原子性。下面是一个例子:

假设您想知道 Jane 的银行余额和 Jack 的银行余额,例如检查余额是否足以出租房屋等。

看起来很简单:

SELECT balance FROM bankaccounts WHERE user = 'Jack';
SELECT balance FROM bankaccounts WHERE user = 'Jane';

把它们加起来,对吗?

错误

如果您在自动提交模式下运行它,那么可能 Jack 有 50k,Jane 有 100k,但总和似乎是 200k。这是通过 jack 设法在 2 条语句之间将他的 50k 转移给 jane 来完成的,即使这是一个谎言,您也得到了 50k+150k = 200k 的总和。

因此事务也适用于只读会话;假设您使用正确的隔离级别(SERIALIZABLE 是合理的级别),它们甚至可能导致重试。通过交易,您每次都会得到 150k 的正确答案,无论 jane 和 jack 何时或以何种频率来回转移资金以试图欺骗您。

JDBC 本身没有“getTransaction()”这个东西,或者“begin”,一般来说这不是“做”事务的正确方式。因此,不清楚您在这里使用的是什么第三方库。

一个合适的数据库抽象应该是这样的:

int sum = dbAccess.executeInt(db -> {
  // query or modify things here:
  return
  db.select("SELECT balance FROM bankaccount WHERE user = ?","Jack").singleInt() +
  db.select("SELECT balance FROM bankaccount WHERE user = ?","Jane").singleInt();
};

它需要在 lambda 中来处理重试,并且它与所有与数据库的交互都是事务性的这一事实非常吻合。

您可能想再仔细阅读文档;这种(使用 lambdas 的)策略可能会晚于您的数据库库的开始(lambdas 是在 java8 中添加的;诚然,那是十年前)。

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...