簡體   English   中英

將數據插入包含外鍵的mysql表中會出現錯誤

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

我的數據庫中有兩個表:

employee_details_table:

  • employee_id int主鍵,
  • employee_name varchar(20)

員工出席:

  • employee_id外鍵引用employee_details_table的employee_id,
  • 出勤日期
  • present_or_absent varchar(6)

這是將數據插入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());
        }
}                                        
}

每當我嘗試將數據插入employee_attendance時,都會出現以下異常:

“無法添加或更新子行:外鍵約束失敗”

正如評論者已經說過的那樣,錯誤告訴您問題所在。 “外鍵約束”沖突意味着您嘗試使用不存在的父行的外鍵值將行插入子表中。

因此,您需要檢查父表(Employee)中的數據以及嘗試插入子表中的值(Attendance)。 您不匹配。

下面是一個完整的工作示例,創建一個數據庫並插入行,所有行都塞到一個類中。 盡管這不是有價值的代碼,但它是正確插入子行(三次)和不正確地插入子行(一次, demo方法的最后一行)的有效demo

演示的要點是demo方法中對insertAttendance的四個調用。 我們為employee_行標識符為1、2和3的行。因此,為這三個值中的任何一個插入attendance_行都將成功。

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

當我們嘗試一個無效的數字時,如果沒有這樣的employee_ ,例如4 ,那么我們將失敗。 我們得到一個SQLException,它指出了違反外鍵 約束的情況 數據庫正在執行引用完整性的工作 如果我們不阻止我們將創建一個“孤兒”行,一個attendance_排不匹配employee_行。

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

本示例使用純Java數據庫H2數據庫 您必須將其添加為依賴項才能運行此代碼。 易於通過Maven等添加

運行時。

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]

示例代碼。

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.
        }
    }

}

順便說說…

您的代碼表明您可能對java.util.Datejava.sql.Date感到困惑。 第一個是日期時間,而第二個則僅是沒有日期的日期。

避免使用舊的java.util.Date類(和.Calendar),因為它的設計不良,令人困惑且麻煩。 改用Java 8和更高版本內置的java.time。

java.sql類型也一樣。 但是我們必須繼續使用它們,直到我們的JDBC驅動程序更新為直接使用java.time類型。 在此之前,請盡可能簡短地使用java.sql類型將數據移入/移出數據庫。 接收到值后立即從java.sql轉換為java.time。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM