Eclipse - GWT - Java - MySQL - 如何正确捕获异常

时间:2014-05-11 01:02:34

标签: java mysql eclipse tomcat gwt

我终于完成了我的应用程序(Eclipse,GWT,Java,MySQL,Tomcat),它已被上传到服务器上(我还有其他人将应用程序上传到服务器上)。但是,服务器安装似乎存在问题,我的代码没有发回任何错误。

例如:创建新帐户时,将显示以下消息"您的帐户已创建。请联系领导,与青年会员联系。"但是数据库没有更新。似乎我没有正确捕捉异常。

我的代码是:

客户端电话:

AsyncCallback<User> callback = new CreationHandler<User>();
rpc.createUser(textBoxAccount.getText(), textBoxPassword.getText(), null, null, null, callback);

服务器端:

public User createUser(String userName, String pass, String level, String pack, java.sql.Date archived) {
    User user = null; // necessary unless you do something in the exception handler
    ResultSet result = null;
    PreparedStatement ps = null;
    String pw_hash = BCrypt.hashpw(pass, BCrypt.gensalt());
    try {
      ps = conn.prepareStatement(
          "INSERT INTO at_accounts (acc_email_address, acc_password, acc_enabled) " +
                  "VALUES (?, ?, ?)");
      ps.setString(1, userName);
      ps.setString(2, pw_hash);
      ps.setString(3, "1");
      ps.executeUpdate();
    }
    catch (SQLException e) {
      //do stuff on fail
        System.out.println("SQLException createUser 1.");
        e.printStackTrace();
        user = null;
    }
    finally {
        if (result != null) {
            try {
                result.close();
            }
            catch (SQLException e) {
                System.out.println("SQLException createUser 2.");
                e.printStackTrace();
            }
        }
        if (ps != null) {
            try {
                ps.close();
            }   
            catch (SQLException e) {
                System.out.println("SQLException createUser 3.");
                e.printStackTrace();
            }
        }
    }
    return user;
}

客户方:

class CreationHandler<T> implements AsyncCallback<User> {
    //Create the account.
    public void onFailure(Throwable ex) {
        Window.alert("RPC call failed - CreationHandler - Notify Administrator.");  
    }
    public void onSuccess(User result) {
        Window.alert("Your account has been created. Please contact a leader to associate youth members to it.");

    }
}

非常感谢任何帮助。

此致

格林

嗨JonK,

这是你的意思吗?

public User createUser(String userName, String pass, String level, String pack, java.sql.Date archived) {
    User user = null; // necessary unless you do something in the exception handler
    ResultSet result = null;
    PreparedStatement ps = null;
    String pw_hash = BCrypt.hashpw(pass, BCrypt.gensalt());
    try {
      ps = conn.prepareStatement(
          "INSERT INTO at_accounts (acc_email_address, acc_password, acc_enabled) " +
                  "VALUES (?, ?, ?)");
      ps.setString(1, userName);
      ps.setString(2, pw_hash);
      ps.setString(3, "1");
      ps.executeUpdate();
    }
    catch (SQLException e) {
      //do stuff on fail
        try {
            conn.rollback();
        } catch (SQLException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }
        System.out.println("SQLException createUser 1.");
        e.printStackTrace();
        user = null;
    }
    finally {
        if (result != null) {
            try {
                result.close();
            }
            catch (SQLException e) {
                try {
                    conn.rollback();
                } catch (SQLException e1) {
                    // TODO Auto-generated catch block
                    e1.printStackTrace();
                }
                System.out.println("SQLException createUser 2.");
                e.printStackTrace();
            }
        }
        if (ps != null) {
            try {
                ps.close();
            }   
            catch (SQLException e) {
                try {
                    conn.rollback();
                } catch (SQLException e1) {
                    // TODO Auto-generated catch block
                    e1.printStackTrace();
                }
                System.out.println("SQLException createUser 3.");
                e.printStackTrace();
            }
        }
    }

    try {
        conn.commit();
    } catch (SQLException e) {
        try {
            conn.rollback();
        } catch (SQLException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }
        System.out.println("SQLException createUser 4 - commit error.");
        e.printStackTrace();
    }
    return user;
}

这是带有建议错误处理的更新代码:

package org.AwardTracker.server;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.sql.Connection;
import java.sql.Date;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

import com.google.gwt.user.server.rpc.RemoteServiceServlet;

import org.AwardTracker.client.BCrypt;

import org.AwardTracker.client.Account;
import org.AwardTracker.client.AccountAndCubs;
import org.AwardTracker.client.AccountCubAssociation;
import org.AwardTracker.client.AwardAward;
import org.AwardTracker.client.AwardDescription;
import org.AwardTracker.client.AwardStockDtls;
import org.AwardTracker.client.DBConnection;
import org.AwardTracker.client.SectionDetails;
import org.AwardTracker.client.Stock;
import org.AwardTracker.client.User;
import org.AwardTracker.client.ViewData;
import org.AwardTracker.client.YMATask;
import org.AwardTracker.client.YMAwards;
import org.AwardTracker.client.YMandAward;
import org.AwardTracker.client.YMAwardDetails;
import org.AwardTracker.client.YouthMember;
import org.AwardTracker.client.YouthMemberAwards;
import org.AwardTracker.client.YthMmbrSectDtls;

import org.AwardTracker.server.Base64Encode2;

public class MySQLConnection extends RemoteServiceServlet implements DBConnection {
//TODO
//  •Use JNDI to bind the data source.
//  •Close the connection as soon as its done in finally block.
//  •Manage the connection in single class for whole application.
//  •Initialise the data source at application start up single time.
//  •Store the database configuration outside the JAVA code somewhere in properties file or web.xml.
//  •Create an abstract class for AsyncCallback that will handle all the failures happened while performing any RPC calls.
//  •Extend this abstract class for all RPC AsyncCallback but now you have to just provide implementation of onSuccess() only.
//  •Don't handle any exception in service implementation just throw it to client or if handled then re-throw some meaning full exception back to client.
//  •Add throws in all the methods for all the RemoteService interfaces whenever needed.

private static final long serialVersionUID = 1L;
private Connection conn = null;
private String url = "jdbc:mysql://localhost/awardtracker";
private String user = "awtrack";
private String pass = "************";

public MySQLConnection() {
    try {
        Class.forName("com.mysql.jdbc.Driver");
        conn = DriverManager.getConnection(url, user, pass);
    } catch (Exception e) {
        //NEVER catch exceptions like this

        System.out.println("Error connecting to database - not good eh");
        e.printStackTrace();
    }
}

//Store and retrieve data used by Views within the application
//This allows us to securely pass parameters between Views.
private ViewData viewData = null;

public ViewData setViewData(String accountId, String accountLevel,
        String ymId, String awId, String adGroup) {

    viewData = new ViewData();

    viewData.setaccountId(accountId);
    viewData.setaccountLevel(accountLevel);
    viewData.setymId(ymId);
    viewData.setawId(awId);
    viewData.setadGroup(adGroup);

    return viewData;
}

public ViewData getViewData() {
    return viewData;
}


public User authenticateUser(String accID, String userName, String pass, String level, String pack, Integer enabled, java.sql.Date archived) {

    User user = null; // necessary unless you do something in the exception handler
    ResultSet result = null;
    PreparedStatement ps = null;
    String stored_hash = null;

    try {
        ps = conn.prepareStatement(
          "SELECT * " +
          "FROM at_accounts " +
          "WHERE acc_email_address = ?");

        ps.setString(1, userName);

        result = ps.executeQuery();

        while (result.next()) {
            user = new User(result.getString(1), result.getString(2), result.getString(3), result.getString(4), result.getString(5), result.getInt(6), result.getDate(7));
            stored_hash = result.getString(3);
        }
    }
    catch (SQLException e) {
        try {
            conn.rollback();
        } 
        catch (SQLException e2) {
            System.out.println("Error rolling back transaction for authenticateUser.");
            e2.printStackTrace();
        }
        System.out.println("SQLException in authenticateUser.");
        e.printStackTrace();
    }

    if (stored_hash != null) {
        if (BCrypt.checkpw(pass, stored_hash))  {
        } else {
            user = null;
        }
    }else{
        user = null;
    }

    return user;
}

//Disable or enable Account
public User disableUser(String user, Integer enabled) {
    PreparedStatement ps = null;

    try {
      ps = conn.prepareStatement(
              "UPDATE at_accounts " +
              "SET acc_enabled=? " +
              "WHERE acc_email_address=?");

      ps.setInt(1, enabled);
      ps.setString(2, user);
      ps.executeUpdate();
      conn.commit();
    }
    catch (SQLException e) {
        try {
            conn.rollback();
        } 
        catch (SQLException e2) {
            System.out.println("Error rolling back transaction for createUser.");
            e2.printStackTrace();
        }
        System.out.println("SQLException in createUser.");
        e.printStackTrace();
    }

    return null;
}

public User duplicateUser(String userName, String pass, String level, String pack, java.sql.Date archived) {
    User user = null; // necessary unless you do something in the exception handler
    ResultSet result = null;
    PreparedStatement ps = null;
    try {
      ps = conn.prepareStatement(
          "SELECT * " +
          "FROM at_accounts " +
          "WHERE acc_email_address = ?");

      ps.setString(1, userName);

      result = ps.executeQuery();
      while (result.next()) {
         user = new User(null, result.getString(2), null, null, null, null, null);
      }
    }
    catch (SQLException e) {
        try {
            conn.rollback();
        } 
        catch (SQLException e2) {
            System.out.println("Error rolling back transaction for duplicateUser.");
            e2.printStackTrace();
        }
        System.out.println("SQLException in duplicateUser.");
        e.printStackTrace();
    }
    return user;
}

public User createUser(String userName, String pass, String level, String pack, java.sql.Date archived) {
    PreparedStatement ps = null;
    String pw_hash = BCrypt.hashpw(pass, BCrypt.gensalt());
    try {
      ps = conn.prepareStatement(
          "INSERT INTO at_accounts (acc_email_address, acc_password, acc_enabled) " +
                  "VALUES (?, ?, ?)");
      ps.setString(1, userName);
      ps.setString(2, pw_hash);
      ps.setString(3, "1");
      ps.executeUpdate();
      conn.commit();
    }
    catch (SQLException e) {
        try {
            conn.rollback();
        } 
        catch (SQLException e2) {
            System.out.println("Error rolling back transaction for createUser.");
            e2.printStackTrace();
        }
        System.out.println("SQLException in createUser.");
        e.printStackTrace();
    }

    return null;
}

2 个答案:

答案 0 :(得分:1)

您没有将事务提交到数据库。为了使ps.executeUpdate();所做的更改成为永久更改,您需要在更新后致电conn.commit();

同样,在catch块中,您应该调用conn.rollback();,以避免将dud数据插入数据库。

我看不到conn的声明,所以我认为它是一个成员变量,无论类createUser属于哪个。您可能需要考虑将Connection更改为方法中的本地,这样您就不会忘记在不再需要它时将其关闭(应该一旦你是提交)。

最后,如果您使用的是Java 7+,则可以利用try-with-resources为您处理PreparedStatementResultSetConnection的关闭(虽然您似乎没有使用ResultSet进行任何操作,但请考虑将其从方法中删除。)


以下是我的意思的两个例子(一个用于Java 6及以下,一个用于Java 7,后来用于try-with-resources

Java 6 -

public void createUser(String userName, String pass) {
    PreparedStatement ps = null;
    Connection conn = null;
    String pw_hash = BCrypt.hashpw(pass, BCrypt.gensalt());
    try {
        // Acquire a Connection here rather than using a member variable
        // NOTE: See Braj's answer for a better way of doing this
        // using his ConnectionUtil class.
        conn = DriverManager.getConnection(
                    "jdbc:mysql://localhost/awardtracker", "awtrack", 
                    "**************");

        ps = conn.prepareStatement(
                "INSERT INTO at_accounts (acc_email_address, acc_password,"
                  + " acc_enabled) "
              + "VALUES (?, ?, ?)");
        ps.setString(1, userName);
        ps.setString(2, pw_hash);
        ps.setString(3, "1");
        ps.executeUpdate();
        conn.commit();
    } catch (SQLException e) {
        try {
            conn.rollback();
        } catch (SQLException e2) {
            System.out.println("Error rolling back transaction.");
            e2.printStackTrace();
        }
        System.out.println("SQLException createUser 1.");
        e.printStackTrace();
    } finally {
        if (ps != null) {
            try {
                ps.close();
            } catch (SQLException e) {
                System.out.println("SQLException createUser 3.");
                e.printStackTrace();
            }
        }

        if (conn != null) {
            try {
                conn.close();
            } catch (SQLException e) {
                System.out.println("Error closing Connection.");
                e.printStackTrace();
            }
        }
    }
}

Java 7 +

private static final String INSERT_STATEMENT =
        "INSERT INTO at_accounts (acc_email_address, acc_password, "
      + "acc_enabled) VALUES (?, ?, ?)";

public void createUser(String userName, String pass) {
    String pw_hash = BCrypt.hashpw(pass, BCrypt.gensalt());

    // NOTE: See Braj's answer for a better way of getting Connections.
    try (Connection conn = DriverManager.getConnection(
            "jdbc:mysql://localhost/awardtracker", "awtrack",
            "**************");
         PreparedStatement ps = conn.prepareStatement(INSERT_STATEMENT);) {

        try {
            ps.setString(1, userName);
            ps.setString(2, pw_hash);
            ps.setString(3, "1");
            ps.executeUpdate();
            conn.commit();
        } catch (SQLException e) {
            try {
                conn.rollback();
            } catch (SQLException e2) {
                System.out.println("Error rolling back transaction.");
                e2.printStackTrace();
            }
            System.out.println("SQLException createUser 1.");
            e.printStackTrace();
        }
    } catch (SQLException e) {
        System.out.println("Error connecting to DB.");
        e.printStackTrace();
    }
}

在这两个例子中,我删除了未使用的方法参数(如果你对它们什么都不做,为什么要把它们放在那里?)并将返回类型改为void。我这样做是因为在当前形式下,您的方法总是 return null(您将User对象初始化为null,然后对其进行任何操作以更改其值,然后在结束时返回)。

您还应该考虑使用log4j等日志记录框架来处理异常日志记录,而不是依赖printStackTrace()。有关未建议printStackTrace()的原因的详细信息,请参阅Why is exception.printStackTrace() considered bad practice?

答案 1 :(得分:1)

记住要点:

  • 使用JNDI绑定数据源。
  • finally阻止中完成连接后立即关闭连接。
  • 管理整个应用程序的单个类连接。
  • 在应用程序启动时单次初始化数据源。
  • 将数据库配置存储在属性文件或web.xml中的JAVA代码之外。

我已经分享了 ConnectionUtil 类的示例代码,其唯一目的是使用 JNDI查找管理单个类中的连接,并且它可以记录在应用程序中的什么时间打开了多少个连接?

请看下面的帖子:


  

GWT - 如何正确捕获异常?

  • AsyncCallback创建一个抽象类,它将处理执行任何RPC调用时发生的所有失败。
  • 为所有RPC AsyncCallback扩展此抽象类,但现在您只需提供onSuccess()的实现。
  • 不要处理服务植入中的任何异常,只需将其丢给客户端,或者如果处理,则将一些意义完全异常重新抛回客户端。
  • 在需要时为所有throws接口的所有方法添加RemoteService

示例代码:

// single class to handle all the AsyncCallback failure
public abstract class MyAsyncCallback<T> implements AsyncCallback<T> {

    @Override
    public void onFailure(Throwable caught) {
        // all the failure are catched here
        // prompt user if needed
        // on failure message goes to here
        // send the failure message back to server for logging
    }

}

// do it for all the RPC AsyncCallback
public class CreationHandler<T> extends MyAsyncCallback<T> {
    //Create the account.
    public void onSuccess(T result) {
        // on success message goes to here
    }
}

// use in this way
AsyncCallback<User> callback = new CreationHandler<User>();