Tôi có một ứng dụng Java EE chạy trên Glassfish và kết nối với MSSQL Server 2008 thông qua jTDS. Đối với một số lý do không rõ, kết nối cơ sở dữ liệu trở nên bất ngờ bị đóng trong các yêu cầu. Ứng dụng này rất lớn, nhưng dưới đây là tóm tắt về cách lỗi xảy ra:Kết nối cơ sở dữ liệu bất ngờ bị đóng với Glassfish, jTDS và SQL Server 2008
Trong khi thiết lập Glassfish, tạo hồ bơi kết nối với asadmin create-jdbc-connection-pool
và asadmin create-jdbc-resource
. Lớp nguồn dữ liệu là net.sourceforge.jtds.jdbcx.JtdsDataSource
.
Khi Glassfish tăng lên, nó gọi thực hiện ServletContextListener.contextInitialized() của chúng tôi, nơi chúng tôi tìm nạp nguồn dữ liệu từ JNDI. Nguồn dữ liệu được lưu trữ trên một biến tĩnh.
Trong một thời gian, mọi thứ diễn ra tốt đẹp. Tất cả các yêu cầu được xử lý và không có kết nối nào bị đóng. Ứng dụng của chúng tôi thực hiện việc xử lý bằng cách sử dụng các EJB thời gian và MDB (Message Driven Bean).
Đây là một thực hiện mẫu onMessage()
:
public void onMessage(Message message) {
this.message = message;
this.connection = dataSource.getConnection(userName, password);
try {
doQuery1();
doTransaction1();
doTransaction2();
doQuery2();
doQuery3();
} finally {
this.connection.close();
this.connection = null;
}
}
Cuối cùng, chúng tôi bắt đầu để có được những ngoại lệ sau đây (xảy ra khoảng 100 lần trong một giờ):
java.sql.SQLException: Invalid state, the Connection object is closed.
at net.sourceforge.jtds.jdbc.ConnectionJDBC2.checkOpen(ConnectionJDBC2.java)
at net.sourceforge.jtds.jdbc.ConnectionJDBC2.prepareStatement(ConnectionJDBC2.java)
at net.sourceforge.jtds.jdbc.ConnectionJDBC2.prepareStatement(ConnectionJDBC2.java)
at com.sun.gjc.spi.base.ConnectionHolder.prepareStatement(ConnectionHolder.java:475)
at com.acme.myejbs.MyMDB.doQuery2(MyMDB.java:123)
at com.acme.myejbs.MyMDB.onMessage(MyMDB.java:614)
at sun.reflect.GeneratedMethodAccessor115.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java)
at java.lang.reflect.Method.invoke(Method.java)
at com.sun.enterprise.security.application.EJBSecurityManager.runMethod(EJBSecurityManager.java:1011)
...
at $Proxy92.onMessage(Unknown Source)
at com.sun.messaging.jms.ra.OnMessageRunner.run(OnMessageRunner.java)
at com.sun.enterprise.connectors.work.OneWork.doWork(OneWork.java:77)
at com.sun.corba.ee.impl.orbutil.threadpool.ThreadPoolImpl$WorkerThread.run(ThreadPoolImpl.java:555)
Trường hợp ngoại lệ xảy ra tại JDBC ngẫu nhiên cuộc gọi. Đôi khi là trong lần lặp ResultSet, các thời điểm khác trong khi thực hiện truy vấn.
Trong những trường hợp rất hiếm (7 lần trong một giờ), chúng tôi có được ngoại lệ này:
java.sql.SQLException: Error in allocating a connection. Cause: This Managed Connection is not valid as the phyiscal connection is not usable
at com.sun.gjc.spi.base.DataSource.getConnection(DataSource.java:136)
at com.acme.myejbs.MyMDB.onMessage(MyMDB.java:614)
at sun.reflect.GeneratedMethodAccessor115.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java)
at java.lang.reflect.Method.invoke(Method.java)
at com.sun.enterprise.security.application.EJBSecurityManager.runMethod(EJBSecurityManager.java:1011)
...
at $Proxy92.onMessage(Unknown Source)
at com.sun.messaging.jms.ra.OnMessageRunner.run(OnMessageRunner.java)
at com.sun.enterprise.connectors.work.OneWork.doWork(OneWork.java:77)
at com.sun.corba.ee.impl.orbutil.threadpool.ThreadPoolImpl$WorkerThread.run(ThreadPoolImpl.java:555)
Cũng trong trường hợp rất hiếm (5 lần trong một giờ), chúng tôi có được ngoại lệ này:
java.sql.SQLException: I/O Error: Connection reset by peer: socket write error
at net.sourceforge.jtds.jdbc.TdsCore.executeSQL(TdsCore.java)
at net.sourceforge.jtds.jdbc.JtdsStatement.executeSQLQuery(JtdsStatement.java)
at net.sourceforge.jtds.jdbc.JtdsPreparedStatement.executeQuery(JtdsPreparedStatement.java)
at com.acme.myejbs.MyMDB.doQuery2(MyMDB.java:126)
at com.acme.myejbs.MyMDB.onMessage(MyMDB.java:614)
...
Caused by: java.net.SocketException: Connection reset by peer: socket write error
at java.net.SocketOutputStream.socketWrite0(Native Method)
at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java)
at java.net.SocketOutputStream.write(SocketOutputStream.java)
at java.io.DataOutputStream.write(DataOutputStream.java)
at net.sourceforge.jtds.jdbc.SharedSocket.sendNetPacket(SharedSocket.java)
at net.sourceforge.jtds.jdbc.RequestStream.putPacket(RequestStream.java)
at net.sourceforge.jtds.jdbc.RequestStream.flush(RequestStream.java)
... 44 more
Trong trường hợp hiếm hoi, chúng tôi có được ngoại lệ này đáng sợ (NPE bên jTDS):
java.lang.NullPointerException
at net.sourceforge.jtds.jdbc.JtdsPreparedStatement.executeQuery(JtdsPreparedStatement.java)
at com.acme.myejbs.MyMDB.doQuery2(MyMDB.java:126)
at com.acme.myejbs.MyMDB.onMessage(MyMDB.java:614)
...
chúng tôi không thể tìm thấy lý do tại sao điều này xảy ra. Các kết nối được sử dụng không bao giờ trở nên không hoạt động trong hơn một giây trong khi yêu cầu. Chúng tôi không biết ai đang bỏ kết nối. Nó có thể là mạng không ổn định, nhưng sau đó tôi đoán jTDS nên năng suất chỉ có ngoại lệ liên quan đến mạng, phải không?
Một tùy chọn khác là một số chính sách hoặc cấu hình của hồ bơi kết nối Glassfish (có lẽ Glassfish đang đóng kết nối vật lý sớm), nhưng làm thế nào chúng ta có thể theo dõi nó?
Cuối cùng, MS SQL Server 2008 có thể từ xa bỏ kết nối, nhưng làm cách nào chúng tôi có thể theo dõi phía máy chủ để biết điều đó có xảy ra không?
Đừng những vấn đề cũng xảy ra khi sử dụng trình điều khiển JDBC Microsofts? – extraneon
@extraneon Chúng tôi đã không kiểm tra trình điều khiển Microsoft JDBC. Có một lớp toàn bộ persistence dựa trên jTDS và chuyển sang MS sẽ mất một vài ngày để hoàn thành. – fernacolo
Mã của bạn có đang bắt/bỏ qua SQLExceptions không? Bạn đang sử dụng một DataSource cơ bản hoặc một kết nối? –