Tôi đang làm việc với JDBC và HSQLDB 2.2.9. Cách hiệu quả nhất và chính xác nhất để chèn hàng mới vào DB là gì, và sau đó, giữ lại giá trị id
(PK được đặt thành tự động tăng) của bạn? Lý do tôi cần phải làm điều này có lẽ là khá rõ ràng, nhưng tôi sẽ minh họa bằng một ví dụ để thảo luận:Cách lấy giá trị PK ID được tạo tự động trước đó bằng JDBC và HSQLDB
Giả sử có một bảng Customer
rằng có một trường PersonId
với một hạn chế FK đề cập đến một hàng từ một bảng Person
. Tôi muốn tạo một Customer
mới, nhưng để làm điều này, trước tiên tôi cần tạo một Person
mới và sử dụng giá trị Person.id
mới để đặt Customer.PersonId
.
Tôi đã nhìn thấy bốn cách tiếp cận này:
Chèn hàng
Person
đặt trườngid
đểnull
. HSQLDB tự động tạo giá trịid
tiếp theo. Sau đó, thực hiện truy vấn trên bảngPerson
để nhận giá trịid
vừa tạo và sử dụng nó để tạo hàngCustomer
mới.Điều này có vẻ tốn kém chỉ để truy xuất một giá trị số nguyên duy nhất.
Lấy
id
giá trị tiếp theo trong bảngPerson
và sử dụng nó trong báo cáo kết quảINSERT
để thiết lập giá trịPerson.id
bằng tay. Sử dụng cùng một giá trịid
để đặtCustomer.PersonId
. Không cần đọc tiếp từ DB.Không nhất quán có thể phát sinh nếu giá trị
id
thu được, nhưng một kết nối khác thực hiệnINSERT
trong bảng trước khi tuyên bốINSERT INTO Person...
của tôi được thực thi.Thực thi câu lệnh
INSERT
, như trong tùy chọn 1 ở trên, đặtid=null
để cho phép tự động tạo. Sau đó, sử dụng phương thứcgetGeneratedKeys
để truy xuất các khóa được tạo trong câu lệnh cuối cùng.Tôi nghĩ rằng điều này nghe có vẻ giống như một lựa chọn tốt, nhưng tôi không thể làm cho nó hoạt động. Dưới đây là một đoạn mã của tôi:
// PreparedStatement prepared previously... preparedStatement.executeUpdate(); ResultSet genKeys = preparedStatement.getGeneratedKeys(); int id; if (genKeys.next()) { id = genKeys.getInt(1); } // Finish up method...
Mã này đã được trả lại một trống
ResultSet
chogenKeys
. Tôi có đang sử dụng phương phápgetGeneratedKeys
không chính xác không? Nếu tôi có thể làm việc này, đây có thể là cách để đi.Một lần nữa, hãy thực hiện câu lệnh
INSERT
cho phép tự động tạoid
. Sau đó, ngay lập tức thực hiệnCALL IDENTITY()
để truy xuất giá trịid
mới nhất do kết nối tạo ra (như được giải thích here và được đề cập trong câu hỏi this SO).Điều này cũng có vẻ như là một lựa chọn hợp lý, mặc dù tôi phải thực hiện thêm
executeQuery
. Về mặt tích cực, tôi đã thực sự có thể làm cho nó làm việc với đoạn mã sau:// INSERT statement executed here... statement = connection.createStatement(); ResultSet rs = statement.executeQuery("CALL IDENTITY();"); int id; if (rs.next()) id = rs.getInt(1); // Finish up method...
Vì vậy, trong Tóm lại, hai tùy chọn đầu tiên tôi không điên về.Thứ hai có vẻ ok, nhưng tôi chỉ có thể nhận được tùy chọn 4 để làm việc. Tùy chọn nào được ưa thích hơn và tại sao? Nếu tùy chọn 3 là tốt nhất, tôi đang làm gì sai? Ngoài ra, có cách nào tốt hơn mà tôi chưa đề cập? Tôi biết những từ như 'tốt hơn' có thể chủ quan, nhưng tôi đang làm việc với một DB đơn giản và muốn giải pháp trực tiếp nhất không mở DB cho những mâu thuẫn có thể và không làm tăng tỷ lệ thất bại giao dịch (do cố gắng để tạo bản ghi với số id
đã tồn tại).
Điều này có vẻ giống như một câu hỏi cơ bản (và cần thiết), nhưng tôi không thể tìm thấy nhiều hướng dẫn về cách tốt nhất để làm điều đó. Cảm ơn.
EDIT: Tôi chỉ tìm thấy this câu hỏi thảo luận về lựa chọn của tôi 3. Theo câu trả lời được chấp nhận, dường như tôi đã bỏ đi
Statement.RETURN_GENERATED_KEYS
thông số cần thiết để kích hoạt chức năng đó. Tôi không hiển thị phương thức
prepareStatement
trong đoạn mã của mình, nhưng tôi đã sử dụng phiên bản tham số duy nhất. Tôi cần phải thử lại bằng cách sử dụng phiên bản hai tham số quá tải.
Ngoài ra còn có một số câu hỏi SO khác hiển thị với câu hỏi đó liên quan chặt chẽ đến câu hỏi của tôi. Vì vậy, tôi đoán tôi có thể được coi là một bản sao (không chắc chắn làm thế nào tôi bị mất những câu hỏi khác trước). Nhưng tôi vẫn muốn bất kỳ hướng dẫn nào về việc liệu một giải pháp có được coi là tốt hơn những giải pháp khác hay không. Bây giờ, nếu tôi nhận được tùy chọn 3 để làm việc, tôi có thể sẽ đi với điều đó.
Thành thật mà nói, tôi không hiểu tại sao bạn won't dính vào giải pháp của bạn No1. Thực hiện một SELECT trên ID của hàng mới được chèn vào có giá trị thông thường của một truy vấn, nhưng sau đó một lần nữa, tất cả các tùy chọn khác của bạn cũng làm như vậy. –
Tôi sẽ không được 'SELECT'ing trên' id', mà là trên một loạt các trường khác bao gồm một khóa duy nhất khác. Giá trị 'id' sẽ là thứ tôi đang tìm kiếm. Tuy nhiên, nhận xét của bạn về "chi phí thông thường của truy vấn" vẫn không phụ thuộc vào chi tiết của truy vấn. Tuy nhiên, tôi đã không chắc chắn về chi phí đi kèm trong tùy chọn 3. Tôi nghĩ rằng thông tin sẽ được còn lại từ việc thực hiện tuyên bố trước đó. Đối với tùy chọn 4 Tôi đã không chắc chắn nếu thực hiện một truy vấn của 'CALL IDENTITY()' là bất kỳ rẻ hơn so với một "thường xuyên" 'SELECT' tuyên bố. – neizan
Tôi không biết nếu nó là một trong hai. Cá nhân, tôi sẽ không lo lắng về chỉ một truy vấn sau khi chèn, nhưng tự nhiên tôi không biết các chi tiết cụ thể của nhiệm vụ của bạn. –