正常查询关闭java和MySql之间的连接

时间:2017-06-11 19:42:34

标签: java mysql eclipse

我不明白为什么当我尝试执行正常查询时创建动态这样的

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)

1 个答案:

答案 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();

更多信息:How does Java's PreparedStatement work?