首页 > 解决方案 > 在 MySQL JDBC 中获取 AUTO_INCREMENT *before* 数据库插入

问题描述

我正在使用 JDBC 开发一个 MySQL 数据库项目。它使用与外键链接的父/子表。

TL;DR:我希望能够在语句之前获取AUTO_INCREMENT表的 ID 。我已经知道JDBC 在插入后执行此操作的方法,但我的应用程序在插入之前需要 ID。也许对于这个特定的应用程序有更好的解决方案?详情如下:INSERTgetGeneratedKeys()


在此应用程序的一部分中,用户可以通过表单或控制台输入来创建新项目以输入详细信息 - 其中一些详细信息以新项目中的“子项目”的形式出现。

这些输入存储在 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. 因为它链接了两个MainItems,所以使用(或多个)虚拟 ID 来预先构造对象会破坏这些关系。

最明显的解决方案似乎是能够AUTO_INCREMENT事先获取 ID,这样我就不需要使用虚拟 ID。

我想另一种解决方案是在输入数据后立即插入数据,但我更愿意将应用程序的不同功能保留在单独的类中——因此一个类负责一个操作。此外,通过在输入数据时立即插入,如果用户在完成输入“主要项目”、标题、参考文献等的所有数据之前选择取消,则需要删除现在无效的数据。


总之,我怎么能AUTO_INCREMENT 插入之前得到?对于这个特定的应用程序有更好的解决方案吗?

标签: javamysqljdbcsql-insertauto-increment

解决方案


您无法在插入之前获取值。您无法知道在桌面上可能采取的其他行动。AUTO_INCREMENT 可能不会增加一,您可能已经设置了它,但它可以更改。

可以使用临时表来存储数据,其中包含您控制的键。我建议使用 Uuid 而不是 Id,这样您就可以假设它始终是唯一的。然后您的其他类可以将数据复制到实时表中,您仍然可以使用 Uuid 链接数据以在临时表中查找相关数据,但以对数据库有意义的顺序写入(因此 'root ' 首先记录以获得它的密钥,然后在需要时使用它。


推荐阅读