![](/img/trans.png)
[英]Insertion of values into a MySQL table referencing another table for a foreign key
[英]Insertion of data into mysql table containing foreign key gives an error
我的數據庫中有兩個表:
employee_details_table:
員工出席:
這是將數據插入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.Date
和java.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.