5

我仍在处理此处提到的相同问题。它似乎工作正常,尤其是在创建如下所示的 AbstractModel 类之后:

public abstract class AbstractModel {

    protected static Connection myConnection = SingletonConnection.instance().establishConnection();
    protected static Statement stmt;
    protected static ResultSet rs;

    protected boolean loginCheck;                   // if userId and userLoginHistoryId are valid - true, else false
    protected boolean userLoggedIn;                 // if user is already logged in - true, else false

    public AbstractModel (int userId, Long userLoginHistoryId){
        createConnection();                                 // establish connection
            loginCheck = false;
        userLoggedIn = false;
        if (userId == 0 && userLoginHistoryId == 0){        // special case for login
            loginCheck = true;                              // 0, 0, false, false
            userLoggedIn = false;                           // set loginCheck to true, userLogged in to false
        } else {
            userLoggedIn = true;
            try{
                String query = "select \"user_login_session_check\"(" + userId + ", " + userLoginHistoryId + ");";
                System.out.println("query: " + query);
                stmt = myConnection.createStatement();
                rs = stmt.executeQuery(query);
                while (rs.next()){
                    loginCheck = rs.getBoolean(1);
                }
            } catch (SQLException e){
                System.out.println("SQL Exception: ");
                e.printStackTrace();
            }
        }

    }
    // close connection
    public void closeConnection(){
        try{
            myConnection.close();
        } catch (SQLException e){
            System.out.println("SQL Exception: ");
            e.printStackTrace();
        }

    }
    // establish connection
    public void createConnection(){
        myConnection = SingletonConnection.instance().establishConnection();
    }

    // login session check
    public boolean expiredLoginCheck (){
        if (loginCheck == false && userLoggedIn == true){
            closeConnection();
            return false;
        } else {
            return true;
        }
    }

}

我已经在上面前面问题的链接中发布了存储过程和单例模式实现。

我的印象是我不需要在每个数据事务之后关闭与数据库的连接,因为它只会减慢应用程序的速度。我正在为我正在构建的这个系统寻找大约 30 个用户,因此性能和可用性很重要。

延长至少 3-4 次数据事务的连接是否正确?例如。对用户输入的某种形式的验证检查,或者类似于谷歌的自动建议的东西......这些都是基于用户输入的单独存储的函数调用。我可以使用一个连接实例,而不是在每次数据事务后连接和断开连接吗?哪个更有效率?

如果我的假设是正确的(使用一个连接实例更有效),那么应该在控制器中处理连接的打开和关闭,这就是我创建 createConnection() 和 closeConnection() 方法的原因。

谢谢。

4

4 回答 4

5

您的代码不应该依赖于这样一个事实,即您的应用程序当前是数据库的唯一客户端,或者您只有 30 个用户。所以你应该处理数据库连接,比如文件、套接字和所有其他类型的稀缺资源,你可能会用完。

因此,您应该始终清理自己。无论你做什么。打开连接,做你的事情(一个或 SQL 语句)并关闭连接。总是!

在您的代码中,您创建连接并将其保存到静态变量中 - 只要您的 AbstractModel 类存在,此连接就会持续存在,可能永远存在 - 这很糟糕。与所有类似情况一样,将您的代码放在 try/finally 中,以确保连接始终关闭。

我已经看到由于 Web 应用程序没有关闭连接而导致应用程序服务器运行连接不足。或者因为他们在注销时关闭并且有人说“我们永远不会同时拥有那么多用户”,但它只是稍微扩大了一点。

现在,当您运行代码并正确关闭连接时,添加连接池,就像 zaske 说的那样。这将解决打开/关闭数据库连接的性能问题,这确实是昂贵的。在逻辑层(您的应用程序)上,您不想知道何时打开/关闭物理连接,数据库层(数据库池)将为您处理它。

然后,您甚至可以为整个会话模型设置单个连接,DBCP 也支持该连接 - 这没有危险,因为您可以在需要时重新配置池,而无需接触客户端代码。

于 2012-06-26T07:23:34.273 回答
4

就像 Tomasz 所说,你永远不 应该依赖于你的应用程序将被少数客户使用的事实。驱动程序将在一定时间后超时这一事实并不能保证您将有足够的可用连接。想象一下:很多数据库都预先配置了最大连接数设置为(比如说)15 和超时(比如说)10-15 分钟。如果您有 30 个客户端并且每个客户端都执行一项操作,那么您将在中途某处出现连接不足的情况。

您应该通过以下方式处理连接、文件、流和其他资源:

public void doSomething()
{
    Connection connection = null;
    Statement stmt = null;
    ResultSet rs = null;

    final String sql = "SELECT ....");

    try
    {
        connection = getConnection();
        stmt = connection.createStatement();

        rs = stmt.executeQuery(sql);
        if (rs.next())
        {
            // Do something here...
        }
    }
    catch (SQLException e)
    {
        e.printStackTrace();
    }
    finally
    {
        closeResultSet(rs);
        closeStatement(stmt);
        closeConnection(connection);
    }
}

try/catch/finally 保证无论结果如何,连接都会关闭。如果出现某种故障,finally 块仍将关闭连接,就像它会做的那样,如果一切正常的话。

同样,对于文件和流,您需要做同样的事情。将相应的对象初始化为null您的 try/catch/finally 之外,然后按照上面的方法。

这种误解使得许多 Java 应用程序在 Windows 下行为不端,人们不会关闭文件(流到文件等)并且这些文件被锁定,迫使你要么杀死 JVM,甚至重新启动你的机器。

您也可以使用连接池,例如 Apache 的 DBCP,但即便如此,您也应该注意关闭资源,尽管在内部,不同的连接池实现不一定会关闭连接。

于 2012-06-26T07:47:44.640 回答
0

这是我将所有模型中的 myConenction 字段初始化为的单例模式:

public class DatabaseConnection {
    private static final String uname = "*******";
    private static final String pword = "*******";
    private static final String url = "*******************************";

    Connection connection;
    // load jdbc driver
    public DatabaseConnection(){
        try{
            Class.forName("org.postgresql.Driver");
            establishConnection();
        } catch (ClassNotFoundException ce) {
            System.out.println("Could not load jdbc Driver: ");
            ce.printStackTrace();
        }
    }
    public Connection establishConnection() {
        // TODO Auto-generated method stub
        try{
            connection = DriverManager.getConnection(url, uname, pword);
        } catch (SQLException e){
            System.out.println("Could not connect to database: ");
            e.printStackTrace();
        }
        return connection;
    }
}

public class SingletonConnection {

    private static DatabaseConnection con;

    public SingletonConnection(){}

    public static DatabaseConnection instance(){

        assert con == null;
            con = new DatabaseConnection();
        return con;
    }
}

当然,从应用程序到数据库的每个连接都通过一个模型。

于 2012-06-26T09:46:59.807 回答
0

你是对的,你不需要在每次通话后关闭连接。
请记住,现代数据库实现了内部连接池,但是您的应用程序仍然需要连接和检索连接对象,这就是它现在所做的。
您应该考虑使用数据库连接池 - 有各种 Java 框架可以为您提供这样的解决方案,并且它们将定义(您当然可以配置)何时关闭数据库连接池。

一般来说——你应该问自己你的数据库是只为你的应用程序服务,还是它也为其他应用程序服务——如果它不为其他应用程序服务,你可能会更加“贪婪”并保持连接打开一段时间更长的时间。
我还建议您的应用程序在启动时创建固定数量的连接(在您的配置中使用“最小连接数”值定义它),如果需要,您可以让它增长到最大连接数。

正如我之前提到的——建议的想法已经被各种框架实现,例如——Apache 的DBCP项目。

于 2012-06-26T07:05:31.620 回答