java - 是否有必要开始事务以在数据库中查找对象?
问题描述
我知道与数据库中的对象交互需要以下内容:
db.getTransaction().begin();
//Code to modify objects in the data base
db.getTransaction().commit();
但是当我使用函数 find(object.class, object.id) 时有必要吗?
解决方案
是否有必要开始事务以在数据库中查找对象?
取决于您所说的“交易”一词的含义。
数据库在事务中做所有事情。时期。因此,简单地说,“是的”,开始事务是必要的,因为不这样做就无法与数据库交互。
但是,数据库具有“便利”功能,您可以在其中像不存在事务一样工作。这是个谎言; 它仅意味着您发送到数据库的每条语句都被默默地包装在“开始交易”中;和“提交;” 来电。这被称为“自动提交”模式(而不是“无事务模式”),因为这是它的正确词:它在每个事务之后自动提交。
因此,在基本 JDBC(Java 中所有基于 SQL 的 DB 交互通常建立在其上的基础层,但请注意,您正在使用构建在它之上的某种库!)中,您可以只运行一个选择查询,通过使用自动提交模式,无需“打扰”事务。
但是,自动提交模式通常是一个坏主意。
事务是数据库设计的基础。即使您只是进行“读取”查询,事务仍然很重要。它们保证一致性和原子性。这是一个例子:
假设您想知道 Jane 的银行余额和 Jack 的银行余额,例如检查余额是否足以出租房屋或诸如此类。
看起来很简单:
SELECT balance FROM bankaccounts WHERE user = 'Jack';
SELECT balance FROM bankaccounts WHERE user = 'Jane';
把它们加起来,对吧?
错了。
如果您在自动提交模式下运行它,那么可能 Jack 有 50k,Jane 有 100k,但总和似乎是 200k。这是通过杰克设法在两条语句之间将他的 50k 转移给 jane 来完成的,给你一个 50k+150k = 200k 的总和,即使这是一个谎言。
因此事务也适用于只读会话;假设您使用正确的隔离级别(SERIALIZABLE 是合理的级别),它们甚至会导致重试。通过交易,您每次都会得到 150k 的正确答案,无论简和杰克何时或多久来回转移资金以试图欺骗您。
JDBC 本身没有“getTransaction()”或“开始”,通常这不是“执行”事务的正确方法。因此,不清楚您在这里使用的是哪个第三方库。
一个适当的数据库抽象看起来像:
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 的)策略可能晚于你的 DB 库的开始(lambdas 是在 java8 中添加的;诚然,那是十年前的事了)。
推荐阅读
- azure-sql-database - 使用多个 OrderBy 时应该创建哪个索引
- blockchain - 将 UI 选定字段转换为 Solidity 智能合约
- excel - 如何在将文本格式化为大写时导入文本文件
- javascript - 如何显示两个水平滚动菜单栏
- java - 我可以将用户输入从一个包拉到另一个包吗?
- windows - 在 windows 上安装 ocaml 失败
- calendar - 如何使用 MS Graph API 读取公共日历
- survey - 使用 SurveyMonkey 是否可以为问题提供规范名称?
- mongodb - mongo 索引键限制与索引名称长度
- python - 如何修复 pip:无法导入名称 main?(已安装 pip 并且 pip3 工作正常)