java - 在 MySQL JDBC 中获取 AUTO_INCREMENT *before* 数据库插入
问题描述
我正在使用 JDBC 开发一个 MySQL 数据库项目。它使用与外键链接的父/子表。
TL;DR:我希望能够在语句之前获取AUTO_INCREMENT
表的 ID 。我已经知道JDBC 在插入后执行此操作的方法,但我的应用程序在插入之前需要 ID。也许对于这个特定的应用程序有更好的解决方案?详情如下:INSERT
getGeneratedKeys()
在此应用程序的一部分中,用户可以通过表单或控制台输入来创建新项目以输入详细信息 - 其中一些详细信息以新项目中的“子项目”的形式出现。
这些输入存储在 Java 对象中,因此表的每一行都对应于其中一个对象 - 以下是一些示例:
MainItem
- id (int)
- a bunch of other details...
MainItemTitle
- mainItemId (int)
- languageId (int)
- title (String)
ItemReference
- itemId (int) <-- this references MainItem id
- referenceId (int) <-- this references another MainItem id that is linked to the first
所以本质上每个 Java 对象代表 MySQL 数据库相关表中的一行。
当我将输入中的值存储到对象中时,我使用了一个虚拟 id,如下所示:
private static final int DUMMY_ID = 0;
...
MainItem item = new MainItem(DUMMY_ID, ...);
// I read each of the titles and initialise them using the same dummy id - e.g.
MainItemTitle title = new MainItemTitle(DUMMY_ID, 2, "Here is a a title");
// I am having trouble with initialising ItemReference so I will explain this later
读取用户输入后,它们将存储在“持有者”类中:
class MainItemValuesHolder {
MainItem item;
ArrayList<MainItemTitle> titles;
ArrayList<ItemReference> references;
// These get initialised and have getters and setters, omitted here for brevity's sake
}
...
MainItemValuesHolder values = new MainItemValuesHolder();
values.setMainItem(mainItem);
values.addTitle(englishTitle);
values.addTitle(germanTitle);
// etc...
在应用程序的最后一层(在另一个类中,值持有者作为参数传递),来自“持有者”类的数据被读取并插入到数据库中:
// First insert the main item, belonging to the parent table
MainItem mainItem = values.getMainItem();
String insertStatement = mainItem.asInsertStatement(true); // true, ignore IDs
// this is an oversimplification of what actually happens, but basically constructs the SQL statement while *ignoring the ID*, because...
int actualId = DbConnection.insert(insertStatement);
// updates the database and returns the AUTO_INCREMENT id using the JDBC getGeneratedKeys() method
// Then do inserts on sub-items belonging to child tables
ArrayList<MainItemTitle> titles = values.getTitles();
for (MainItemTitle dummyTitle : titles) {
MainItemTitle actualTitle = dummyTitle.replaceForeignKey(actualId);
String insertStatement = actualTitle.asInsertStatement(false); // false, use the IDs in the object
DbConnection.insert(insertStatement);
}
现在,问题是将此过程用于ItemReference
. 因为它链接了两个MainItem
s,所以使用(或多个)虚拟 ID 来预先构造对象会破坏这些关系。
最明显的解决方案似乎是能够AUTO_INCREMENT
事先获取 ID,这样我就不需要使用虚拟 ID。
我想另一种解决方案是在输入数据后立即插入数据,但我更愿意将应用程序的不同功能保留在单独的类中——因此一个类负责一个操作。此外,通过在输入数据时立即插入,如果用户在完成输入“主要项目”、标题、参考文献等的所有数据之前选择取消,则需要删除现在无效的数据。
总之,我怎么能AUTO_INCREMENT
在插入之前得到?对于这个特定的应用程序有更好的解决方案吗?
解决方案
您无法在插入之前获取值。您无法知道在桌面上可能采取的其他行动。AUTO_INCREMENT 可能不会增加一,您可能已经设置了它,但它可以更改。
您可以使用临时表来存储数据,其中包含您控制的键。我建议使用 Uuid 而不是 Id,这样您就可以假设它始终是唯一的。然后您的其他类可以将数据复制到实时表中,您仍然可以使用 Uuid 链接数据以在临时表中查找相关数据,但以对数据库有意义的顺序写入(因此 'root ' 首先记录以获得它的密钥,然后在需要时使用它。
推荐阅读
- html - HTML屏幕的拆分布局,下面的内容不可见
- google-workflows - 您如何暂停并稍后从 nodejs 恢复工作流程
- python - pandas to_datetime('today') 抛出错误
- c++ - 不将文本从函数输出到控制台?
- swiftui - 如何为图像设置动画以在屏幕上连续移动?
- reactjs - 更新 React + Django 上的更改,而无需每次都运行“npm run build”
- snakemake - Snakemake 中的错误“规则定义中的意外关键字扩展”
- python - 将数据插入 SQL Server 数据库时如何处理无日期值
- javascript - javascript正则表达式匹配两个字符串之间的所有内容(没有换行符)
- python - 在另一台计算机上复制 Python 环境