我一直收到这个错误:
Error code 20000, SQL state 23505
Insert command failed: The statement was aborted because it would have caused a duplicate key value in a unique or primary key constraint or unique index identified by 'SQL160524112023610' defined on 'TEST'.
当我运行此代码时:
import java.io.File;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.logging.Level;
import java.util.logging.Logger;
public class DerbyBatch {
private static Connection connection;
public static void main(String args[]) {
try {
createDatabase();
createTable();
insertBatch();
} catch (ClassNotFoundException | SQLException ex) {
Logger.getLogger(DerbyBatch.class.getName()).log(Level.SEVERE, null, ex);
}
}
public static void createDatabase() throws SQLException {
connection = DriverManager.getConnection("jdbc:derby:" + new File("test").getAbsolutePath() + ";" + "create=true");
disconnect();
}
public static void createTable() throws ClassNotFoundException, SQLException {
connect();
String createTable = "CREATE TABLE \"APP\".\"TEST\" (ID INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1), TEXT VARCHAR (30000) NOT NULL, PRIMARY KEY (ID))";
PreparedStatement preparedStatement = connection.prepareStatement(createTable);
preparedStatement.executeUpdate();
preparedStatement.close();
connection.commit();
disconnect();
}
public static void insertBatch() throws SQLException, ClassNotFoundException {
connect();
String sql = "INSERT INTO TEST (ID, TEXT) VALUES (?,?)";
PreparedStatement preparedStatement = connection.prepareStatement(sql);
preparedStatement.setInt(1, 1);
preparedStatement.setString(2, "TEST");
preparedStatement.addBatch();
preparedStatement.executeBatch();
connection.commit();
disconnect();
Logger.getLogger(DerbyBatch.class.getName()).log(Level.SEVERE, "All data inserted.");
}
public static void connect() throws ClassNotFoundException, SQLException {
Class.forName("net.sf.log4jdbc.DriverSpy");
Connection temp = DriverManager.getConnection("jdbc:log4jdbc:derby:" + new File("test").getAbsolutePath());
connection = new net.sf.log4jdbc.ConnectionSpy(temp);
connection.setAutoCommit(false);
}
public static void disconnect() throws SQLException {
connection.close();
}
}
然后尝试在netbeans服务标签中手动插入记录 - >数据库:
我确保所有内容都已提交并且连接已正确关闭,因此我不确定为什么德比会在执行批量插入后继续拾取重复索引?
答案 0 :(得分:4)
关于GENERATED BY DEFAULT
,假设自动生成的值应该从最后一个现有ID开始是错误的;它们总是从START WITH
值开始。
因此,当您尝试使用NetBeans插入另一行时,将首次触发自动ID生成,并且它将尝试插入具有START WITH
值的ID;因为这是1
,就像您通过Java手动输入的ID一样,它会因重复键错误而失败。
official documentation也涵盖了您的具体情况:
create table greetings (i int generated by default as identity, ch char(50)); -- specify value "1": insert into greetings values (1, 'hi'); -- use generated default insert into greetings values (DEFAULT, 'salut'); -- use generated default insert into greetings(ch) values ('bonjour');
请注意,与
因此,在上面的例子中,GENERATED ALWAYS
列不同,GENERATED BY DEFAULT
列不保证唯一性。hi
和salut
行的标识值均为1
,因为。{ 生成的列从1
开始,用户指定的值也是1
。防止重复,尤其是在加载或导入时 数据,使用对应的
START WITH
值创建表 系统应分配的第一个标识值。
因此,您要么不手动插入ID而只使用自动生成,要么相应地将START WITH
更改为手动插入的ID,例如START WITH 2
。
您还可以使用START WITH
ALTER TABLE
更改RESTART WITH
值。 documentation of ALTER TABLE
有一个例子可以解决与你类似的情况:
考虑以下示例,其中涉及到的组合 自动生成的数据和手动插入的数据:
CREATE TABLE tauto(i INT GENERATED BY DEFAULT AS IDENTITY, k INT) CREATE UNIQUE INDEX tautoInd ON tauto(i) INSERT INTO tauto(k) values 1,2
系统 将自动为标识列生成值。但现在 您需要手动将一些数据插入标识列:
INSERT INTO tauto VALUES (3,3) INSERT INTO tauto VALUES (4,4) INSERT INTO tauto VALUES (5,5)
标识列使用了
1
到5
的值 这点。如果您现在希望系统生成一个值,那么系统 将生成3
,这将导致唯一的密钥异常,因为 值3
已经手动插入。为了弥补 手动插入,为标识列发出
ALTER TABLE
语句 与RESTART WITH 6
:ALTER TABLE tauto ALTER COLUMN i RESTART WITH 6
答案 1 :(得分:0)
从我所看到的情况来看,您的测试只能成功运行一次。之后,除非您在测试后删除创建的表,否则它将在重复的插入,重复的表创建或类似的东西上失败。