【问题标题】:Singleton is applicable in servlet/jsp project? [duplicate]单例是否适用于 servlet/jsp 项目? [复制]
【发布时间】:2015-08-31 07:18:02
【问题描述】:

我正在使用以下代码为我的简单 jsp/servlet 登录项目(即单例)连接到数据库。当我第一次登录时,它在我成功注销后工作。现在问题开始了,当我再次尝试登录时出现错误提示“严重:错误消息:连接关闭后不允许操作。” 但是,当我删除代码关闭连接时,它又可以正常工作了。请建议我应该使用它还是避免它。

public class ConnectionMgr {

    private static ConnectionMgr instance = null;

    private static final String USERNAME = "root";
    private static final String PASSWORD = "";
    private static final String M_CONN_STRING = "jdbc:mysql://localhost:3306/generator";
    private static final String H_CONN_STRING = "jdbc:hsqldb:data/generator";

    private DBType dbType = DBType.MYSQL;

    private Connection conn = null;


    private ConnectionMgr() {
    }

    public static ConnectionMgr getInstance() {
        if (instance == null) {
            instance = new ConnectionMgr();
        }
        return instance;
    }

    public void setDBType(DBType dbType) {
        this.dbType = dbType;
    }

    private boolean openConnection() {
        try {
            switch (dbType) {

                case MYSQL:
                    Class.forName("com.mysql.jdbc.Driver");
                    conn = DriverManager.getConnection(M_CONN_STRING, USERNAME, PASSWORD);
                    return true;

                case HSQL:
                    conn = DriverManager.getConnection(H_CONN_STRING, USERNAME, PASSWORD);
                    return true;

                default:
                    return false;
            }
        } catch (SQLException | ClassNotFoundException e) {
            System.err.println(e);
            DBUtil.processException((SQLException) e);
            return false;
        }
    }

    public Connection getConnection() {
        if (conn == null) {
            if (openConnection()) {
                System.out.println("Connection opened");
                return conn;
            } else {
                return null;
            }
        }
        return conn;
    }

    public void processException(SQLException e) {
        System.err.println("Silgleton connection()Error -->");
        System.err.println("Erroe message:" + e.getMessage());
        System.err.println("Error code:" + e.getErrorCode());
        System.err.println("Error State:" + e.getSQLState());
    }

    public void close() {
        System.out.println("Closing connection");
        try {
            conn.close();
            conn = null;
        } catch (Exception e) {
        }
    }
}

【问题讨论】:

  • 我对单例的批评之一是,当没有为应用程序正确设计时,它们会导致完全类似的问题,其中包含对象的生命周期变得未知。从 Web 服务器进行任何数据库访问时,您可能需要与数据库建立多个连接才能处理并发请求。这就是使用 RDBMS 的原因——它们允许您这样做。因为允许客户端代码关闭连接,所以单例实际上失去了控制,随后的代码会破坏它。
  • 此外,您应该为每个数据库事务使用新连接,然后立即关闭它们;这样,您可以建立访问控制,根据需要关闭自动提交(对于单个事务中的多个查询),如果发生错误则回滚事务,并确保合理的原子更新,以及其他细节。通过在没有正确管理其状态的情况下重用连接,您为未来的各种问题打开了大门。

标签: jsp servlets jdbc singleton private-constructor


【解决方案1】:

您的连接管理器不是线程安全的。因此,当一个用户尝试使用单个实例读取数据时,另一个用户的线程可能最终会关闭正在使用的连接。

改用Apache DBCP 之类的东西,它也会给你一个连接池。

如果您仍想使用上面的代码,请将连接管理器更改为常规对象而不是单例。

【讨论】:

    【解决方案2】:

    您可能正在保存对第一个请求的“连接”实例的引用,然后将该引用重新用于您的第二个请求。

    尝试确保每次有新请求到达 servlet 时调用 getConnection()

    在 ConnectionMgr 类的所有方法中添加 System.out.println("your-method-name-")

    【讨论】:

    • 非常感谢先生,现在我很清楚,如果我在桌面应用程序中使用相同的代码会怎样?
    猜你喜欢
    • 1970-01-01
    • 2012-08-02
    • 2018-02-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-29
    • 1970-01-01
    • 2012-05-26
    相关资源
    最近更新 更多