问题描述
我知道以下是与数据库中的对象交互所必需的:
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 中添加的;诚然,那是十年前)。