简体   繁体   English

将数据插入包含外键的mysql表中会出现错误

[英]Insertion of data into mysql table containing foreign key gives an error

I have two tables in my database as : 我的数据库中有两个表:

employee_details_table: employee_details_table:

  • employee_id int primary key , employee_id int主键,
  • employee_name varchar(20) employee_name varchar(20)

employee_attendance: 员工出席:

  • employee_id foreign key references employee_id of employee_details_table , employee_id外键引用employee_details_table的employee_id,
  • attendance_for date , 出勤日期
  • present_or_absent varchar(6) present_or_absent varchar(6)

Here is the java code to insert data into employee_attendance : 这是将数据插入employee_attendance的Java代码:

class Attendance
{
 java.util.Date utilDate;
 java.sql.Date sqlDate;

 String attDate;
 int empid;
 String pa;
 Connection con=null;
 PreparedStatement statement=null;
 ResultSet rs=null;

 private void jButton1ActionPerformed(java.awt.event.ActionEvent evt)
 {                                         
    try
    {
    empid=Integer.parseInt(jTextField1.getText());
    sqlDate=new java.sql.Date(utilDate.getTime());
    pa=jComboBox1.getSelectedItem().toString();
    }

    catch(Exception e)
    {
        JOptionPane.showMessageDialog(null,e.getMessage());
    }

   String query = "Insert into employee_attendance (employee_id,attendance_for,present_or_absent) values (?,?,?)";

        try
        {
           Class.forName("com.mysql.jdbc.Driver");
           con=DriverManager.getConnection("jdbc:mysql:///hrmps?zeroDateTimeBehavior=convertToNull","root","root");
           statement=con.prepareStatement(query); 
           statement.setInt(1,empid);
           //sqlDate=new java.sql.Date(utilDate.getTime());
           statement.setDate(2,sqlDate);
           statement.setString(3, pa);
           statement.executeUpdate();
        }

        catch(Exception e)
        {
             JOptionPane.showMessageDialog(null,e.getMessage());
        }
}                                        
}

Whenever I try to insert data into employee_attendance , I get the exception as: 每当我尝试将数据插入employee_attendance时,都会出现以下异常:

"Cannot add or update a child row: a foreign key constraint fails" “无法添加或更新子行:外键约束失败”

As the commenters have already said, the error tells you the problem. 正如评论者已经说过的那样,错误告诉您问题所在。 A “foreign key constraint” violation means you tried to insert a row into a child table using a foreign key value for a parent row that does not exist. “外键约束”冲突意味着您尝试使用不存在的父行的外键值将行插入子表中。

So you need to examine the data in the parent table (Employee) and the values you are attempting to insert into the child table (Attendance). 因此,您需要检查父表(Employee)中的数据以及尝试插入子表中的值(Attendance)。 You have a mismatch. 您不匹配。

Below is an entire working example, creating a database & inserting rows, all crammed into a single class. 下面是一个完整的工作示例,创建一个数据库并插入行,所有行都塞到一个类中。 While this is not production-worthy code, it is a working demonstration of inserting child rows both properly (three times) and improperly (once, last line of demo method). 尽管这不是有价值的代码,但它是正确插入子行(三次)和不正确地插入子行(一次, demo方法的最后一行)的有效demo

The point of the demo is the four calls to insertAttendance in the demo method. 演示的要点是demo方法中对insertAttendance的四个调用。 We are given employee_ rows with identifiers of 1, 2, and 3. So inserting attendance_ rows for any of those three values succeeds. 我们为employee_行标识符为1、2和3的行。因此,为这三个值中的任何一个插入attendance_行都将成功。

this.insertAttendance ( conn , 2 …
this.insertAttendance ( conn , 1 …
this.insertAttendance ( conn , 3 …

When we try an invalid number for which we have no such employee_ , such as 4 , then we fail. 当我们尝试一个无效的数字时,如果没有这样的employee_ ,例如4 ,那么我们将失败。 We get a SQLException noting a violation of the foreign key constraint . 我们得到一个SQLException,它指出了违反外键 约束的情况 The database is doing its job in enforcing referential integrity . 数据库正在执行引用完整性的工作 If we were not blocked we would be creating an “orphan” row, an attendance_ row with no matching employee_ row. 如果我们不阻止我们将创建一个“孤儿”行,一个attendance_排不匹配employee_行。

this.insertAttendance ( conn , 4 …  // Throws SQLException for violation of the foreign key constraint.

This example uses the pure Java database, H2 Database . 本示例使用纯Java数据库H2数据库 You must add as a dependency to run this code. 您必须将其添加为依赖项才能运行此代码。 Easy to add via Maven, etc. 易于通过Maven等添加

When run. 运行时。

Tables established and populated.

Table dump: employee_
Employee id_: 1 | name_: Alfred
Employee id_: 2 | name_: Barbara
Employee id_: 3 | name_: Charlie

Table dump: attendance_
Attendance id_: 1 | fkey_employee_id_: 2 | when_expected_: 2016-01-23T10:00:00Z | status_:  present
Attendance id_: 2 | fkey_employee_id_: 1 | when_expected_: 2016-01-23T10:00:00Z | status_:  present
Attendance id_: 3 | fkey_employee_id_: 3 | when_expected_: 2016-01-23T10:00:00Z | status_:  absent

SQLException: Referential integrity constraint violation: "CONSTRAINT_32: PUBLIC.ATTENDANCE_ FOREIGN KEY(FKEY_EMPLOYEE_ID_) REFERENCES PUBLIC.EMPLOYEE_(ID_) (4)"; SQL statement:
INSERT INTO attendance_ ( fkey_employee_id_ , when_expected_ , status_ ) VALUES ( ? , ? , ? ); [23506-191]

Example code. 示例代码。

package com.example.h2example;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.time.Instant;

/**
 * Demonstrates how to both properly and improperly insert rows into a child
 * table.
 *
 * Caveat: Not production-worthy code. For demonstration purposes only. Use at
 * your own risk.
 *
 * @author Basil Bourque
 */
public class App {

    public static void main ( String[] args ) {
        App app = new App ();
        app.demo ();
    }

    private void demo () {
        Connection conn = this.fetchConnection ();

        this.insertAttendance ( conn , 2 , Instant.parse ( "2016-01-23T10:00:00Z" ) , "present" );
        this.insertAttendance ( conn , 1 , Instant.parse ( "2016-01-23T10:00:00Z" ) , "present" );
        this.insertAttendance ( conn , 3 , Instant.parse ( "2016-01-23T10:00:00Z" ) , "absent" );

        this.dumpTable_Employee ( conn );
        this.dumpTable_Attendance ( conn );

        // Insert invalid value (BAD).
        this.insertAttendance ( conn , 4 , Instant.parse ( "2016-01-23T10:00:00Z" ) , "absent" );
    }

    private Connection fetchConnection () {
        Connection conn = null;

        try {
            Class.forName ( "org.h2.Driver" );
        } catch ( ClassNotFoundException e ) {
            // TODO: Handle exception.
            System.out.println ( "Database failure: " + e );
            return null;
        }

        // Specify a database named 'EmployeeAttendanceBogus.mv.db' in the Unix user’s home folder.
        String dbFolderPath = "~/";
        String dbName = "EmployeeAttendanceBogus";
        String dbUrl = "jdbc:h2:" + dbFolderPath + dbName;
        String dbUserName = "h2";
        String dbPassword = "pw";

        try {
            // If database does not yet exist, it is automatically created.
            conn = DriverManager.getConnection ( dbUrl , dbUserName , dbPassword );
        } catch ( SQLException ex ) {
            System.out.println ( "SQLException on DriverManager.getConnection: " + ex.getMessage () );
            // TODO: Handle exception when no Connection is made.
        }

        if ( null == conn ) {
            System.out.println ( "Database error. No Connection." );
            // TODO: Handle exception when no Connection is made.
        } else {
            // ELSE got database connection. Normal.
            this.recreateTables ( conn );
//            this.dumpTable_Employee ( conn );
//            this.dumpTable_Attendance ( conn );
        }
        return conn;
    }

    private void recreateTables ( Connection conn ) {
        // Update database structure if needed.

        StringBuilder sql = new StringBuilder ();

        // Delete any existing tables.
        sql.append ( "DROP TABLE IF EXISTS attendance_ ; " + " \n" );   // Drop child table first, because of referential integrity.
        sql.append ( "DROP TABLE IF EXISTS employee_ ; " + " \n" );

        // Define tables.
        sql.append ( "CREATE TABLE employee_ " + " \n" );
        sql.append ( "(" + " \n" );
        sql.append ( "id_ IDENTITY PRIMARY KEY , " + " \n" );  // Primary key, Long type.
        sql.append ( "name_ VARCHAR_IGNORECASE NOT NULL " + " \n" );
        sql.append ( ")" + " \n" );
        sql.append ( ";" + " \n" );

        sql.append ( "" );
        sql.append ( "CREATE TABLE attendance_ " + " \n" );
        sql.append ( "(" + " \n" );
        sql.append ( "id_ IDENTITY PRIMARY KEY , " + " \n" );  // Primary key, Long type.
        sql.append ( "fkey_employee_id_ BIGINT , " + " \n" );
        sql.append ( "when_expected_ TIMESTAMP NOT NULL , " + " \n" );
        sql.append ( "status_ VARCHAR_IGNORECASE NOT NULL " + " \n" );  // Domain: "present" | "absent" .
        sql.append ( ")" + " \n" );
        sql.append ( ";" + " \n" );
        sql.append ( "" );

        sql.append ( "ALTER TABLE attendance_ ADD FOREIGN KEY ( fkey_employee_id_ ) REFERENCES employee_( id_ ) ;" );
        sql.append ( "" );

        sql.append ( "INSERT INTO employee_ ( name_ ) VALUES ( 'Alfred' ) ;" );
        sql.append ( "INSERT INTO employee_ ( name_ ) VALUES ( 'Barbara' ) ;" );
        sql.append ( "INSERT INTO employee_ ( name_ ) VALUES ( 'Charlie' ) ;" );

        System.out.println ( "Tables established and populated.\n" );

        try ( Statement stmt = conn.createStatement () ) {
            stmt.executeUpdate ( sql.toString () );

        } catch ( SQLException ex ) {
            System.err.println ( "SQLException: " + ex.getMessage () );
            // TODO: Handle exception.
        }

    }

    private void dumpTable_Employee ( Connection conn ) {

        StringBuilder sql = new StringBuilder ();
        sql.append ( "SELECT * FROM employee_ ;" );

        try ( PreparedStatement pstmt = conn.prepareStatement ( sql.toString () ) ) {
            try ( ResultSet rs = pstmt.executeQuery (); ) {
                System.out.println ( "Table dump: employee_" );
                while ( rs.next () ) {
                    long id = rs.getLong ( "id_" );
                    String name = rs.getString ( "name_" );
                    System.out.println ( "Employee id_: " + id + " | name_: " + name );
                }
                System.out.println ( "" );
            }

        } catch ( SQLException ex ) {
            System.err.println ( "SQLException: " + ex.getMessage () );
            // TODO: Handle exception.
        }
    }

    private void dumpTable_Attendance ( Connection conn ) {

        StringBuilder sql = new StringBuilder ();
        sql.append ( "SELECT * FROM attendance_ ;" );

        try ( PreparedStatement pstmt = conn.prepareStatement ( sql.toString () ) ) {
            try ( ResultSet rs = pstmt.executeQuery (); ) {
                System.out.println ( "Table dump: attendance_" );
                while ( rs.next () ) {
                    long id = rs.getLong ( "id_" );
                    long fkey = rs.getLong ( "fkey_employee_id_" );
                    java.sql.Timestamp whenExpectedTs = rs.getTimestamp ( "when_expected_" );
                    Instant whenExpected = whenExpectedTs.toInstant ();  // Convert as soon as possible from java.sql.Timestamp to java.time.
                    String status = rs.getString ( "status_" );
                    System.out.println ( "Attendance id_: " + id + " | fkey_employee_id_: " + fkey + " | when_expected_: " + whenExpected + " | status_:  " + status );
                }
                System.out.println ( "" );
            }

        } catch ( SQLException ex ) {
            System.err.println ( "SQLException: " + ex.getMessage () );
            // TODO: Handle exception.
        }
    }

    private void insertAttendance ( Connection conn , long employeeId , Instant whenExpected , String status ) {
        StringBuilder sql = new StringBuilder ();
        sql.append ( "INSERT INTO attendance_ ( fkey_employee_id_ , when_expected_ , status_ ) VALUES ( ? , ? , ? );" );

        try ( PreparedStatement pstmt = conn.prepareStatement ( sql.toString () ) ) {
            pstmt.setLong ( 1 , employeeId );
            pstmt.setTimestamp ( 2 , java.sql.Timestamp.from ( whenExpected ) );
            pstmt.setString ( 3 , status );
            int rowsAffected = pstmt.executeUpdate ();

        } catch ( SQLException ex ) {
            System.err.println ( "SQLException: " + ex.getMessage () );
            // TODO: Handle exception.
        }
    }

}

By the way… 顺便说说…

Your code shows you may be confused about java.util.Date and java.sql.Date . 您的代码表明您可能对java.util.Datejava.sql.Date感到困惑。 The first is a date and time-of-day while the second pretends to be only a date without time-of-day. 第一个是日期时间,而第二个则仅是没有日期的日期。

Avoid the old java.util.Date class (and .Calendar) as it is poorly designed, confusing, and troublesome. 避免使用旧的java.util.Date类(和.Calendar),因为它的设计不良,令人困惑且麻烦。 Use java.time instead, built into Java 8 and later. 改用Java 8和更高版本内置的java.time。

The java.sql types are just as bad. java.sql类型也一样。 But we must continue to use them until our JDBC drivers are updated to directly use java.time types. 但是我们必须继续使用它们,直到我们的JDBC驱动程序更新为直接使用java.time类型。 Until then use java.sql types as briefly as possible to move data in/out of database. 在此之前,请尽可能简短地使用java.sql类型将数据移入/移出数据库。 Convert from java.sql to java.time immediately after receiving a value. 接收到值后立即从java.sql转换为java.time。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM