我不明白为什么当我尝试执行正常查询时创建动态这样的
INSERT INTO messaggio(Nickname,DataConnesione,DataMessaggio,messaggio) VALUES ('Anonymous','2017.06.11 20:56:02','2017.06.11 20:56:06','Hello!');
此查询是在此Java代码中创建的:
QUERY = "INSERT INTO messaggio(Nickname,DataConnesione,DataMessaggio,messaggio) VALUES ('"+username+"','"+dateConnections+"','"+time+"','"+message+"');";
当我尝试执行此更新时
try {
ps = conn.prepareStatement(QUERY);
ps.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}
我有这个例外:
com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: No operations allowed after connection closed.
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source)
at java.lang.reflect.Constructor.newInstance(Unknown Source)
at com.mysql.jdbc.Util.handleNewInstance(Util.java:425)
at com.mysql.jdbc.Util.getInstance(Util.java:408)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:918)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:897)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:886)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:860)
at com.mysql.jdbc.ConnectionImpl.throwConnectionClosedException(ConnectionImpl.java:1198)
at com.mysql.jdbc.ConnectionImpl.checkClosed(ConnectionImpl.java:1193)
at com.mysql.jdbc.ConnectionImpl.prepareStatement(ConnectionImpl.java:4046)
at com.mysql.jdbc.ConnectionImpl.prepareStatement(ConnectionImpl.java:4015)
at Server$ClientThread.run(Server.java:289)
我发布了完整的代码,因为我真的不知道可能存在什么问题。
/*
* server constructor that receive the port to listen to for connection as parameter
* in console
*/
public Server(int port) {
this(port, null);
}
public Server(int port, ServerGUI sg) {
// GUI or not
this.sg = sg;
// the port
this.port = port;
// to display hh:mm:ss
sdf = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss");
// ArrayList for the Client list
al = new ArrayList<ClientThread>();
}
public void start() {
keepGoing = true;
/* create socket server and wait for connection requests */
try
{
// the socket used by the server
ServerSocket serverSocket = new ServerSocket(port);
// infinite loop to wait for connections
while(keepGoing)
{
// format message saying we are waiting
display("Server waiting for Clients on port " + port + ".");
Socket socket = serverSocket.accept(); // accept connection
// if I was asked to stop
if(!keepGoing)
break;
ClientThread t = new ClientThread(socket); // make a thread of it
al.add(t); // save it in the ArrayList
t.start();
}
// I was asked to stop
try {
serverSocket.close();
for(int i = 0; i < al.size(); ++i) {
ClientThread tc = al.get(i);
try {
tc.sInput.close();
tc.sOutput.close();
tc.socket.close();
}
catch(IOException ioE) {
// not much I can do
}
}
}
catch(Exception e) {
display("Exception closing the server and clients: " + e);
}
}
// something went bad
catch (IOException e) {
String msg = sdf.format(new Date()) + " Exception on new ServerSocket: " + e + "\n";
display(msg);
}
}
/*
* For the GUI to stop the server
*/
protected void stop() {
keepGoing = false;
// connect to myself as Client to exit statement
// Socket socket = serverSocket.accept();
try {
new Socket("localhost", port);
}
catch(Exception e) {
// nothing I can really do
}
}
/*
* Display an event (not a message) to the console or the GUI
*/
private void display(String msg) {
String time = sdf.format(new Date()) + " " + msg;
if(sg == null)
System.out.println(time);
else
sg.appendEvent(time + "\n");
}
/*
* to broadcast a message to all Clients
*/
private synchronized void broadcast(String message) {
// add HH:mm:ss and \n to the message
time = sdf.format(new Date());
String messageLf = time + " " + message + "\n";
// display message on console or GUI
if(sg == null)
System.out.print(messageLf);
else
sg.appendRoom(messageLf); // append in the room window
// we loop in reverse order in case we would have to remove a Client
// because it has disconnected
for(int i = al.size(); --i >= 0;) {
ClientThread ct = al.get(i);
// try to write to the Client if it fails remove it from the list
if(!ct.writeMsg(messageLf)) {
al.remove(i);
display("Disconnected Client " + ct.username + " removed from list.");
}
}
}
// for a client who logoff using the LOGOUT message
synchronized void remove(int id) {
// scan the array list until we found the Id
for(int i = 0; i < al.size(); ++i) {
ClientThread ct = al.get(i);
// found it
if(ct.id == id) {
al.remove(i);
return;
}
}
}
/*
* To run as a console application just open a console window and:
* > java Server
* > java Server portNumber
* If the port number is not specified 1500 is used
*/
public static void main(String[] args)throws SQLException {
try {
conn = DriverManager.getConnection(DB_URL, USER, PASS );
System.out.println("Connesione al DB effettuata");
}catch( Exception ex ) {
ex.printStackTrace();
}
finally {
if ( ps != null ) {
ps.close();
}
if ( rs != null ) {
rs.close();
}
if ( conn != null ) {
conn.close();
}
}
// start server on port 1500 unless a PortNumber is specified
int portNumber = 1500;
switch(args.length) {
case 1:
try {
portNumber = Integer.parseInt(args[0]);
}
catch(Exception e) {
System.out.println("Invalid port number.");
System.out.println("Usage is: > java Server [portNumber]");
return;
}
case 0:
break;
default:
System.out.println("Usage is: > java Server [portNumber]");
return;
}
// create a server object and start it
Server server = new Server(portNumber);
server.start();
}
/** One instance of this thread will run for each client */
class ClientThread extends Thread {
// the socket where to listen/talk
Socket socket;
ObjectInputStream sInput;
ObjectOutputStream sOutput;
// my unique id (easier for deconnection)
int id;
// the Username of the Client
String username;
// the only type of message a will receive
ChatMessage cm;
// the date I connect
Date date;
// Constructore
ClientThread(Socket socket) {
// a unique id
id = ++uniqueId;
this.socket = socket;
/* Creating both Data Stream */
System.out.println("Thread trying to create Object Input/Output Streams");
try
{
// create output first
sOutput = new ObjectOutputStream(socket.getOutputStream());
sInput = new ObjectInputStream(socket.getInputStream());
// read the username
username = (String) sInput.readObject();
display(username + " just connected.");
}
catch (IOException e) {
display("Exception creating new Input/output Streams: " + e);
return;
}
// have to catch ClassNotFoundException
// but I read a String, I am sure it will work
catch (ClassNotFoundException e) {
}
date = new Date();
}
// what will run forever
public void run() {
String QUERY = null;
//Date when the user log
String dateConnections=sdf.format(date);
// to loop until LOGOUT
boolean keepGoing = true;
while(keepGoing) {
// read a String (which is an object)
try {
cm = (ChatMessage) sInput.readObject();
}
catch (IOException e) {
display(username + " Exception reading Streams: " + e);
break;
}
catch(ClassNotFoundException e2) {
break;
}
// the messaage part of the ChatMessage
String message = cm.getMessage();
// Switch on the type of message receive
switch(cm.getType()) {
case ChatMessage.MESSAGE:
broadcast(username + ": " + message);
QUERY = "INSERT INTO messaggio(Nickname,DataConnesione,DataMessaggio,messaggio) VALUES ('"+username+"','"+dateConnections+"','"+time+"','"+message+"');";
System.out.println(QUERY);
try {
ps = conn.prepareStatement(QUERY);
ps.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}
break;
case ChatMessage.LOGOUT:
display(username + " disconnected with a LOGOUT message.");
keepGoing = false;
break;
case ChatMessage.WHOISIN:
writeMsg("List of the users connected at " + sdf.format(new Date()) + "\n");
// scan al the users connected
for(int i = 0; i < al.size(); ++i) {
ClientThread ct = al.get(i);
writeMsg((i+1) + ") " + ct.username + " since " + ct.date);
}
break;
}
}
// remove myself from the arrayList containing the list of the
// connected Clients
remove(id);
close();
}
// try to close everything
private void close() {
// try to close the connection
try {
if(sOutput != null) sOutput.close();
}
catch(Exception e) {}
try {
if(sInput != null) sInput.close();
}
catch(Exception e) {};
try {
if(socket != null) socket.close();
}
catch (Exception e) {}
}
/*
* Write a String to the Client output stream
*/
private boolean writeMsg(String msg) {
// if Client is still connected send the message to it
if(!socket.isConnected()) {
close();
return false;
}
// write the message to the stream
try {
sOutput.writeObject(msg);
}
// if an error occurs, do not abort just inform the user
catch(IOException e) {
display("Error sending message to " + username);
display(e.toString());
}
return true;
}
}
我使用Eclipse Kepler和mysql-connector-java-5.1.41-bin 感谢所有人,抱歉我的英语不好,我是编程初学者。
编辑:我尝试在run()方法中填写所有内容:
public void run() {
String QUERY = null;
//Date when the user log
String dateConnections=sdf.format(date);
// to loop until LOGOUT
boolean keepGoing = true;
while(keepGoing) {
// read a String (which is an object)
try {
cm = (ChatMessage) sInput.readObject();
}
catch (IOException e) {
display(username + " Exception reading Streams: " + e);
break;
}
catch(ClassNotFoundException e2) {
break;
}
// the messaage part of the ChatMessage
String message = cm.getMessage();
// Switch on the type of message receive
switch(cm.getType()) {
case ChatMessage.MESSAGE:
broadcast(username + ": " + message);
try (Connection conn = DriverManager.getConnection(DB_URL, USER, PASS )) {
QUERY = "INSERT INTO messaggio(Nickname,DataConnesione,DataMessaggio,messaggio) VALUES ('"+username+"','"+dateConnections+"','"+time+"','"+message+"');";
System.out.println(QUERY);
ps = conn.prepareStatement(QUERY);
ps.executeUpdate();
conn.close();
ps.close();
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
break;
case ChatMessage.LOGOUT:
display(username + " disconnected with a LOGOUT message.");
keepGoing = false;
break;
case ChatMessage.WHOISIN:
writeMsg("List of the users connected at " + sdf.format(new Date()) + "\n");
// scan al the users connected
for(int i = 0; i < al.size(); ++i) {
ClientThread ct = al.get(i);
writeMsg((i+1) + ") " + ct.username + " since " + ct.date);
}
break;
}
}
// remove myself from the arrayList containing the list of the
// connected Clients
remove(id);
close();
}
但是不行:
Exception in thread "Thread-0" java.lang.NullPointerException
at Server$ClientThread.run(Server.java:274)
答案 0 :(得分:0)
您在获得Connection
条款后立即关闭finally
:
if ( conn != null ) {
conn.close();
}
关闭它之后,你就不能再使用了它,这就是你得到例外的原因。
你在这里使用的成语(“使用后保证关闭”)通常如下所示:
Connection conn = null;
try {
conn = ... // open connection
doSomeWorkOnConnection(conn);
} finally {
if (conn != null) {
conn.close();
}
}
在这种情况下,Connection
仅在完成所有工作后关闭(并且仅在doSomeWorkOnConnection()
方法中完成工作)。但在你的情况下,你的Connection
似乎是全局的(这只是一个假设,因为我们没有看到conn
声明),所以它应该只在程序的最后关闭(当然不是在连接建立后立即。)
顺便说一句,有一种更现代的形式相同的成语(尝试资源):
try (final Connection conn = openConnection()) {
doSomeWorkOnConnection(conn);
}
这将在剩余Connection
阻止时自动关闭try
。
如何解决问题
解决这个问题的一种方法是每个客户端使用Connection
,然后就可以使用try-with-resources习惯用法。但是在这种情况下,如果Client
仅存在一段时间,则可能会对性能造成影响(对于连接初始化)。 Alghouth,连接池可以克服这种惩罚。
另一种方法是将Connection
全局保留为Server
。这意味着您需要将其设置为非静态,在Server
类中声明它(如果它未在那里声明)并在Server
构造函数(或初始化方法)中初始化它。然后,您可以在完成conn.close()
生命周期的某种方法中调用Server
(例如,在stop()
方法中)。
更新PreparedStatement
此外,您不会以预期的方式使用PreparedStatement
。 (例如,这样的连接使您容易受到SQL注入攻击。)我们的想法是避免使用stringn连接并使用占位符来允许驱动程序/数据库绑定实际的查询参数。
所以
// use placeholders in the query (marked with ? sign)
QUERY = "INSERT INTO messaggio(Nickname,DataConnesione,DataMessaggio,messaggio) VALUES (?,?,?,?);";
ps = conn.prepareStatement(QUERY);
// now bind the variables
ps.setString(1, username);
ps.setString(2, dateConnections);
ps.setString(3, time);
ps.setString(4, message);
// and only now execute the query
ps.executeUpdate();