2011-05-19 40 views
9

Tôi có hai bảng trong cơ sở dữ liệu MySQL của tôi, mà đã được tạo ra như thế này:JDBC: khoá ngoại trên PK tạo ra trong cùng một giao dịch

CREATE TABLE table1 (
    id int auto_increment, 
    name varchar(10), 
    primary key(id) 
) engine=innodb 

CREATE TABLE table2 (
    id_fk int, 
    stuff varchar(30), 
    CONSTRAINT fk_id FOREIGN KEY(id_fk) REFERENCES table1(id) ON DELETE CASCADE 
) engine=innodb 

(Đây không phải là bảng gốc Điểm là bảng 2 có khóa ngoài tham chiếu khóa chính trong bảng 1)

Bây giờ trong mã của tôi, tôi muốn thêm mục vào cả hai bảng trong một giao dịch. Vì vậy, tôi đặt autoCommit false:

Connection c = null;   

    PreparedStatement insertTable1 = null; 
    PreparedStatement insertTable2 = null; 

    try { 
     // dataSource was retreived via JNDI 
     c = dataSource.getConnection(); 
     c.setAutoCommit(false); 

     // will return the created primary key 
     insertTable1 = c.prepareStatement("INSERT INTO table1(name) VALUES(?)",Statement.RETURN_GENERATED_KEYS); 
     insertTable2 = c.prepareStatement("INSERT INTO table2 VALUES(?,?)"); 

     insertTable1.setString(1,"hage"); 
     int hageId = insertTable1.executeUpdate(); 

     insertTable2.setInt(1,hageId); 
     insertTable2.setString(2,"bla bla bla"); 
     insertTable2.executeUpdate(); 

     // commit 
     c.commit(); 
    } catch(SQLException e) { 
     c.rollback(); 
    } finally { 
     // close stuff 
    } 

Khi tôi thực thi mã trên, tôi nhận được một ngoại lệ:

MySQLIntegrityConstraintViolationException: Cannot add or update a child row: a foreign key constraint fails 

Nó có vẻ như khóa chính là không có sẵn trong giao dịch trước khi tôi cam kết.

Tôi có thiếu gì đó ở đây không? Tôi thực sự nghĩ rằng khóa chính được tạo nên có sẵn trong giao dịch.

Chương trình chạy trên Glassfish 3.0.1 sử dụng kết nối mysql 5.1.14 và MySQL 5.5.8

Bất kỳ trợ giúp nào thực sự được đánh giá cao!

Kính trọng, Hage

Trả lời

5

Bạn bỏ lỡ điều gì đó cho trở lại id cập nhật, bạn phải làm như thế này:

Long hageId = null; 

try { 
    result = insertTable1.executeUpdate(); 
} catch (Throwable e) { 
    ... 
} 

ResultSet rs = null; 

try { 
    rs = insertTable1.getGeneratedKeys(); 
    if (rs.next()) { 
     hageId = rs.getLong(1); 
    } 
... 
+0

Cảm ơn bạn! Nó hoạt động hoàn hảo ngay bây giờ. Nhưng điều gì đó vẫn chưa rõ ràng với tôi: Các bảng của tôi trống trước khi tôi chạy mã. Vì vậy, 'exececuteUpdate' trả về số hàng bị ảnh hưởng (trong trường hợp này 1) cũng là ID được tạo. Tôi nghĩ rằng điều này nên đã làm việc quá - cũng có thể nó đã đưa ra ngoại lệ trong một lần chạy thứ hai ... Hoặc không 'getGeneratedKeys()' làm cho các phím có sẵn? – hage

+0

Id hàng được chèn bắt đầu đến hàng cuối cùng + 1, trừ khi bạn thực hiện 'cắt ngắn' trên bảng của mình, nó sẽ không được khởi tạo thành 0. – EricParis16

+0

+1 Tôi đang tìm câu trả lời này trong thời gian dài –

1

Thay vì sử dụng executeUpdate() sử dụng thực hiện() và sau đó trở về khóa chính.

http://www.coderanch.com/t/301594/JDBC/java/Difference-between-execute-executeQuery-executeUpdate

Nhưng tôi không làm việc với db ... vì vậy tôi có thể làm một sai lầm

+0

Tôi biết sự khác biệt giữa các phương thức thực thi *() khác nhau. Tôi chỉ cố gắng lấy chìa khóa sai. Tôi nghĩ executeUpdate() sẽ trả về khóa thay vì số hàng đã thay đổi khi 'Statement.RETURN_GENERATED_KEYS' được đặt. Nhưng cảm ơn câu trả lời của bạn anyway. – hage

Các vấn đề liên quan