由于foregin键错误,保存失败

时间:2015-08-10 13:30:16

标签: java sql

在我的java bat文件中,我收到一个错误:

    com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Cann
ot add or update a child row: a foreign key constraint fails (`ellinel`.`invento
ryitems`, CONSTRAINT `FK_inventoryitems_2` FOREIGN KEY (`accountid`) REFERENCES
`accounts` (`id`) ON DELETE CASCADE)
        at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)

        at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source)

        at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Sou
rce)
        at java.lang.reflect.Constructor.newInstance(Unknown Source)
        at com.mysql.jdbc.Util.handleNewInstance(Util.java:408)
        at com.mysql.jdbc.Util.getInstance(Util.java:383)
        at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1049)
        at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4226)
        at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4158)
        at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2615)
        at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2776)
        at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2840)
        at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.ja
va:2082)
        at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java
:2334)
        at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java
:2262)
        at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java
:2246)
        at client.inventory.ItemFactory.saveItems(ItemFactory.java:249)
        at server.MapleStorage.saveToDB(MapleStorage.java:137)
        at client.MapleCharacter.saveToDB(MapleCharacter.java:5188)
        at net.server.channel.handlers.ChangeChannelHandler.handlePacket(ChangeC
hannelHandler.java:97)
        at net.MapleServerHandler.messageReceived(MapleServerHandler.java:128)
        at org.apache.mina.core.filterchain.DefaultIoFilterChain$TailFilter.mess
ageReceived(DefaultIoFilterChain.java:690)
        at org.apache.mina.core.filterchain.DefaultIoFilterChain.callNextMessage
Received(DefaultIoFilterChain.java:417)
        at org.apache.mina.core.filterchain.DefaultIoFilterChain.access$1200(Def
aultIoFilterChain.java:47)
        at org.apache.mina.core.filterchain.DefaultIoFilterChain$EntryImpl$1.mes
sageReceived(DefaultIoFilterChain.java:765)
        at org.apache.mina.filter.codec.ProtocolCodecFilter$ProtocolDecoderOutpu
tImpl.flush(ProtocolCodecFilter.java:407)
        at org.apache.mina.filter.codec.ProtocolCodecFilter.messageReceived(Prot
ocolCodecFilter.java:236)
        at org.apache.mina.core.filterchain.DefaultIoFilterChain.callNextMessage
Received(DefaultIoFilterChain.java:417)
        at org.apache.mina.core.filterchain.DefaultIoFilterChain.access$1200(Def
aultIoFilterChain.java:47)
        at org.apache.mina.core.filterchain.DefaultIoFilterChain$EntryImpl$1.mes
sageReceived(DefaultIoFilterChain.java:765)
        at org.apache.mina.core.filterchain.IoFilterAdapter.messageReceived(IoFi
lterAdapter.java:109)
        at org.apache.mina.core.filterchain.DefaultIoFilterChain.callNextMessage
Received(DefaultIoFilterChain.java:417)
        at org.apache.mina.core.filterchain.DefaultIoFilterChain.fireMessageRece
ived(DefaultIoFilterChain.java:410)
        at org.apache.mina.core.polling.AbstractPollingIoProcessor.read(Abstract
PollingIoProcessor.java:710)
        at org.apache.mina.core.polling.AbstractPollingIoProcessor.process(Abstr
actPollingIoProcessor.java:664)
        at org.apache.mina.core.polling.AbstractPollingIoProcessor.process(Abstr
actPollingIoProcessor.java:653)
        at org.apache.mina.core.polling.AbstractPollingIoProcessor.access$600(Ab
stractPollingIoProcessor.java:67)
        at org.apache.mina.core.polling.AbstractPollingIoProcessor$Processor.run
(AbstractPollingIoProcessor.java:1124)
        at org.apache.mina.util.NamePreservingRunnable.run(NamePreservingRunnabl
e.java:64)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
        at java.lang.Thread.run(Unknown Source)

它是代码执行的部分:

public synchronized void saveItems(List<Pair<Item, MapleInventoryType>> items, int id) throws SQLException {
        PreparedStatement ps = null;
        PreparedStatement pse = null;
        try {
            StringBuilder query = new StringBuilder();
            query.append("DELETE FROM `inventoryitems` WHERE `type` = ? AND `");
            query.append(account ? "accountid" : "characterid").append("` = ?");
            Connection con = DatabaseConnection.getConnection();
            ps = con.prepareStatement(query.toString());
            ps.setInt(1, value);
            ps.setInt(2, id);
            ps.executeUpdate();
            ps.close();
            ps = con.prepareStatement("INSERT INTO `inventoryitems` VALUES (DEFAULT, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", Statement.RETURN_GENERATED_KEYS);
            pse = con.prepareStatement("INSERT INTO `inventoryequipment` VALUES (DEFAULT, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");

            for (Pair<Item, MapleInventoryType> pair : items) {
                Item item = pair.getLeft();
                MapleInventoryType mit = pair.getRight();
                ps.setInt(1, value);
                ps.setString(2, account ? null : String.valueOf(id));
                ps.setString(3, account ? String.valueOf(id) : null);
                ps.setInt(4, item.getItemId());
                ps.setInt(5, mit.getType());
                ps.setInt(6, item.getPosition());
                ps.setInt(7, item.getQuantity());
                ps.setString(8, item.getOwner());
                ps.setInt(9, item.getPetId());
                ps.setInt(10, item.getFlag());
                ps.setLong(11, item.getExpiration());
                ps.setString(12, item.getGiftFrom());
                ps.setString(13, item.getRewards());
                ps.executeUpdate();//line 249

                if (mit.equals(MapleInventoryType.EQUIP) || mit.equals(MapleInventoryType.EQUIPPED)) {
                    try (ResultSet rs = ps.getGeneratedKeys()) {

                        if (!rs.next()) {
                            throw new RuntimeException("Inserting item failed.");
                        }

                        pse.setInt(1, rs.getInt(1));
                    }
                    Equip equip = (Equip) item;
                    pse.setInt(2, equip.getUpgradeSlots());
                    pse.setInt(3, equip.getLevel());
                    pse.setInt(4, equip.getStr());
                    pse.setInt(5, equip.getDex());
                    pse.setInt(6, equip.getInt());
                    pse.setInt(7, equip.getLuk());
                    pse.setInt(8, equip.getHp());
                    pse.setInt(9, equip.getMp());
                    pse.setInt(10, equip.getWatk());
                    pse.setInt(11, equip.getMatk());
                    pse.setInt(12, equip.getWdef());
                    pse.setInt(13, equip.getMdef());
                    pse.setInt(14, equip.getAcc());
                    pse.setInt(15, equip.getAvoid());
                    pse.setInt(16, equip.getHands());
                    pse.setInt(17, equip.getSpeed());
                    pse.setInt(18, equip.getJump());
                    pse.setInt(19, 0);
                    pse.setInt(20, equip.getVicious());
                    pse.setInt(21, equip.getItemLevel());
                    pse.setInt(22, equip.getItemExp());
                    pse.setInt(23, equip.getRingId());
                    pse.executeUpdate();
                }
            }

            pse.close();
            ps.close();
        } finally {
            if (ps != null) {
                ps.close();
            }
            if (pse != null) {
                pse.close();
            }
        }
    }

不幸的是,我不知道如何使用外键。有人可以解释一下我的问题是什么,解决问题的方法是什么?

SQL代码:

DROP TABLE IF EXISTS `ellinel`.`inventoryitems`;
CREATE TABLE  `ellinel`.`inventoryitems` (
  `inventoryitemid` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `type` tinyint(3) unsigned NOT NULL,
  `characterid` int(11) DEFAULT NULL,
  `accountid` int(11) DEFAULT NULL,
  `itemid` int(11) NOT NULL DEFAULT '0',
  `inventorytype` int(11) NOT NULL DEFAULT '0',
  `position` int(11) NOT NULL DEFAULT '0',
  `quantity` int(11) NOT NULL DEFAULT '0',
  `owner` tinytext NOT NULL,
  `petid` int(11) NOT NULL DEFAULT '-1',
  `flag` int(11) NOT NULL,
  `expiration` bigint(20) NOT NULL DEFAULT '-1',
  `giftFrom` varchar(26) NOT NULL,
  `rewards` text NOT NULL,
  PRIMARY KEY (`inventoryitemid`),
  KEY `FK_inventoryitems_1` (`characterid`),
  KEY `FK_inventoryitems_2` (`accountid`) USING BTREE,
  CONSTRAINT `FK_inventoryitems_1` FOREIGN KEY (`characterid`) REFERENCES `characters` (`id`) ON DELETE CASCADE,
  CONSTRAINT `FK_inventoryitems_2` FOREIGN KEY (`accountid`) REFERENCES `accounts` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=113340972 DEFAULT CHARSET=latin1;

3 个答案:

答案 0 :(得分:0)

您无法删除具有与之关联的外键的表。外键的问题在于,在创建外键后,链接必须始终存在。这使得删除和复制痛苦。您需要做的是首先使用临时名称创建新表,并在其中创建所有新的主键和外键。您需要为与inventoryitemsaccounts相关联的所有内容制作临时表格,然后从下往上删除原始表格,这样您就不会违反任何关键约束条件。最后,使用旧表名重命名新表。

基本上,首先按照您想要的方式创建临时结构。然后删除旧结构并重命名新结构以匹配。

答案 1 :(得分:0)

在您的表格中,accountid列引用了id表的accounts列中的值。

accountid是外键,这意味着它只能保存accounts.id中可以找到的值。

因此,当一个新值插入accountid或更新现有值时,您必须确保accounts中有一个条目,以便满足约束条件。

简单地说,外键是一个引用另一个表中的条目的值。

答案 2 :(得分:0)

一个表中的外键(FK)指向另一个表中的主键(PK)。您可以阅读更多信息,并在w3schools

上查看一些示例

您的错误说明:

Cannot add or update a child row: a foreign key constraint fails 
(`ellinel`.`inventoryitems`, CONSTRAINT `FK_inventoryitems_2` FOREIGN KEY (`accountid`) REFERENCES`accounts` (`id`) ON DELETE CASCADE)

在这里,我们看到了约束&#39; FK_inventoryitems_2&#39;是一个错误的原因。我们在Create table语句中找到它:

CONSTRAINT `FK_inventoryitems_2` FOREIGN KEY (`accountid`) REFERENCES `accounts` (`id`) ON DELETE CASCADE

在这里,您可以看到约束FK_inventoryitems_2代表表accounts的FK。 这基本上意味着您要在表accountid中插入的inventoryitems在表accounts中不存在。我相信这是为accountid字段增加价值的部分:

ps.setString(3, account ? String.valueOf(id) : null);

一句话,在您向表格accountid中的inventoryitems字段添加一些值之前,您需要在表id中添加accounts