Đóng các kết nối JDBC trong nhóm


109

Phần mã tiêu chuẩn của chúng tôi để sử dụng JDBC là ...

Connection conn = getConnection(...);
Statement  stmt = conn.conn.createStatement (ResultSet.TYPE_SCROLL_INSENSITIVE,
                                                ResultSet.CONCUR_READ_ONLY);
ResultSet  rset = stmt.executeQuery (sqlQuery);

// do stuff with rset

rset.close(); stmt.close(); conn.close();

Câu hỏi 1: Khi sử dụng Nhóm kết nối, người ta có nên đóng Kết nối ở cuối không? Nếu vậy, không phải mục đích của việc gộp chung đã mất đi? Và nếu không, làm cách nào DataSource biết khi nào một phiên bản cụ thể của Connection được giải phóng và có thể được sử dụng lại? Tôi hơi bối rối về điều này, bất kỳ con trỏ nào được đánh giá cao.

Câu hỏi 2: Phương pháp sau đây có gì gần với tiêu chuẩn không? Có vẻ như một nỗ lực để lấy kết nối từ nhóm và nếu không thể thiết lập DataSource, hãy sử dụng DriverManager kiểu cũ. Chúng tôi thậm chí không chắc phần nào đang được thực thi trong thời gian chạy. Lặp lại câu hỏi ở trên, người ta có nên đóng Kết nối ra khỏi một phương pháp như vậy không?

Xin cảm ơn - MS.

synchronized public Connection getConnection (boolean pooledConnection)
                                                        throws SQLException {
        if (pooledConnection) {
                if (ds == null) {
                        try {
                                Context envCtx = (Context)
                                        new InitialContext().lookup("java:comp/env");
                                ds = (DataSource) envCtx.lookup("jdbc/NamedInTomcat");
                                return ds.getConnection();
                        } catch (NamingException e) {
                                e.printStackTrace();
                }}
                return (ds == null) ? getConnection (false) : ds.getConnection();
        }
        return DriverManager.getConnection(
                "jdbc:mysql://"+ipaddy+":"+dbPort +"/" + dbName, uName, pWord);
}

Chỉnh sửa: Tôi nghĩ rằng chúng tôi đang nhận được kết nối gộp vì chúng tôi không thấy dấu vết ngăn xếp.

Câu trả lời:


121

Khi sử dụng Nhóm kết nối, người ta có nên đóng Kết nối ở cuối không? Nếu vậy, không phải mục đích của việc gộp chung đã mất đi? Và nếu không, làm cách nào DataSource biết khi nào một phiên bản cụ thể của Connection được giải phóng và có thể được sử dụng lại? Tôi hơi bối rối về điều này, bất kỳ con trỏ nào được đánh giá cao.

Có, chắc chắn bạn cũng cần phải đóng kết nối gộp lại. Nó thực sự là một trình bao bọc xung quanh kết nối thực tế. Nó sẽ giải phóng kết nối thực tế trở lại pool. Việc quyết định kết nối thực sự sẽ thực sự bị đóng hay được sử dụng lại cho một getConnection()cuộc gọi mới còn tùy thuộc vào nhóm . Vì vậy, bất kể bạn có đang sử dụng nhóm kết nối hay không, bạn phải luôn đóng tất cả các tài nguyên JDBC theo thứ tự đảo ngược trong finallykhối của trykhối mà bạn đã có được chúng. Trong Java 7, điều này có thể được đơn giản hóa hơn nữa bằng cách sử dụng try-with-resourcescâu lệnh.


Phương pháp sau đây có gì gần với tiêu chuẩn không? Có vẻ như một nỗ lực để lấy kết nối từ nhóm và nếu không thể thiết lập DataSource, hãy sử dụng DriverManager kiểu cũ. Chúng tôi thậm chí không chắc phần nào đang được thực thi trong thời gian chạy. Lặp lại câu hỏi ở trên, người ta có nên đóng Kết nối ra khỏi một phương pháp như vậy không?

Ví dụ là khá đáng sợ. Bạn chỉ cần tra cứu / khởi tạo DataSourcemột lần duy nhất trong quá trình khởi động ứng dụng trong một số phương thức khởi tạo / khởi tạo của một lớp cấu hình DB toàn ứng dụng. Sau đó chỉ cần gọigetConnection() một và cùng một nguồn dữ liệu trong suốt thời gian còn lại của ứng dụng. Không cần đồng bộ hóa hoặc không kiểm tra.

Xem thêm:


Đó là những gì nó đang làm (khởi tạo một lần), phải không? ds là một biến thể hiện và if (ds == null) ... là phần khởi tạo.
Manidip Sengupta

Thực hiện kiểm tra mọi lúc trong một phương thức get-giống như getConnection()là một điều kỳ lạ. Chỉ cần làm điều đó trong c'tor hoặc khối khởi tạo của cùng một lớp, không cần đồng bộ hóa / nullchecks. Nó sẽ chỉ được gọi một lần. Để biết thêm các gợi ý và ví dụ khởi động, bạn có thể thấy bài viết này hữu ích.
BalusC

Bài báo xuất sắc, BalusC. Lớp mà tôi đang xử lý triển khai khá nhiều Lớp dữ liệu, sử dụng DTO. Tôi đồng ý với bạn, khởi tạo nên ở trong hàm tạo. Bây giờ, lớp này có rất nhiều phương thức, mỗi phương thức có conn, stmt và rset là các biến cục bộ, các kết nối nằm trong một khối try và cuối cùng là một lệnh gọi 1 dòng csrClose (conn, stmt, rset), trong đó cả 3 được đóng (theo thứ tự ngược lại). Bây giờ, DTO bạn phát triển trong ví dụ là một hình ảnh phản chiếu của một hàng trong bảng DB. Chúng tôi có các truy vấn SQL phức tạp với các phép nối (và các mệnh đề khác), bạn có bài viết về cách phát triển DAO để có kết quả như vậy không?
Manidip Sengupta

2
@yat: Bạn PHẢI kêu gọi close()tất cả chúng trong finallykhối của cùng một trykhối với nơi bạn mua / tạo chúng. Điều này hoàn toàn không phụ thuộc vào việc đó có phải là kết nối gộp hay không.
BalusC

1
@iJava: hồ bơi đó được viết bởi một người nghiệp dư, người không biết rõ anh ta đang làm gì. Bỏ qua nó và đi đến một thư viện thực sự. Ví dụ: HikariCP.
BalusC

22

Các nhóm thường trả lại cho bạn một đối tượng Kết nối được bọc, trong đó phương thức close () bị ghi đè, thường trả về Kết nối cho nhóm. Gọi close () là OK và có thể vẫn được yêu cầu.

Phương thức close () có thể trông như thế này:

public void close() throws SQLException {
  pool.returnConnection(this);
}

Đối với câu hỏi thứ hai của bạn, bạn có thể thêm một trình ghi nhật ký để cho biết liệu khối dưới cùng có bao giờ chạy hay không. Tôi sẽ tưởng tượng mặc dù bạn chỉ muốn theo cách này hay cách khác cho cấu hình các kết nối cơ sở dữ liệu của mình. Chúng tôi chỉ sử dụng một nhóm để truy cập cơ sở dữ liệu của chúng tôi. Dù bằng cách nào, việc đóng kết nối sẽ khá quan trọng để tránh rò rỉ.


Tôi đồng ý, chúng tôi có một máy ghi nhật ký và nó cũng có thể được sử dụng ở đây. Tôi cần phải nghiên cứu một chút về cách bạn có thể quấn một Object, ghi đè phương pháp của nó close () nhưng vẫn duy trì tên lớp cùng (Connection)
Manidip Sengupta

1
Calling close() is OK and probably still required., Không gọi gần sẽ bị rò rỉ kết nối, trừ trường hợp cụ hồ bơi một số chiến lược phục hồi
Svarog

0

Trên thực tế, cách tiếp cận tốt nhất để quản lý kết nối là không đưa chúng ra bất kỳ mã nào ở bất kỳ đâu.

Tạo một lớp SQLExecutor là vị trí duy nhất mở và đóng các kết nối.

Sau đó, toàn bộ phần còn lại của ứng dụng sẽ bơm các câu lệnh vào trình thực thi thay vì nhận các kết nối từ nhóm và quản lý (hoặc quản lý sai chúng) ở khắp nơi.

Bạn có thể có bao nhiêu trường hợp của trình thực thi tùy thích, nhưng không ai nên viết mã mở và đóng các kết nối thay cho chính nó.

Thuận tiện, điều này cũng cho phép bạn ghi lại tất cả SQL của mình từ một bộ mã duy nhất.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.