Java servlet与同步

Java servlet与同步,java,servlets,jdbc,synchronization,Java,Servlets,Jdbc,Synchronization,servlet在多个线程中运行,因此我的问题是: 如果我有很多servlet调用一些实用程序类(例如DbUtils) Connection c = DbUtils.getConnection(); //....some action with db here 我是否应该为DbUtils内部的同步执行其他操作 实际上,我想将HttpServlet继承到DatabaseInvokerServlet中: 公共抽象类DatabaseInvokerServlet扩展了HttpServlet 方法: pu

servlet在多个线程中运行,因此我的问题是:

如果我有很多servlet调用一些实用程序类(例如DbUtils)

Connection c = DbUtils.getConnection();
//....some action with db here
我是否应该为DbUtils内部的同步执行其他操作

实际上,我想将HttpServlet继承到DatabaseInvokerServlet中:

公共抽象类DatabaseInvokerServlet扩展了HttpServlet

方法:

public abstract void getResultSets(Connection connection) throws SQLException;
private AbstractUser currentUser;
private HttpServletRequest request;
private HttpServletResponse response;
protected void processData() {}
protected void afterRequestProcessed() throws ServletException, IOException {}
protected void beforeRequestProcessed() throws ServletException, IOException {}

protected void execute() {
    Connection c = null;
    try {
        c = DbUtils.getConnection();
        getResultSets(c);
        processData();
    } catch (SQLException e) {
        e.printStackTrace();
    } finally {
        try {
            if (c != null) {
                c.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

public HttpServletRequest getRequest() {
    return request;
}

public HttpServletResponse getResponse() {
    return response;
}

public AbstractUser getCurrentUser() {
    return currentUser;
}

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    request.setCharacterEncoding("UTF-8");
    response.setContentType("text/html;charset=UTF-8");
    response.setCharacterEncoding("UTF-8");


    this.request = request;
    this.response = response;
    this.currentUser = (AbstractUser) request.getSession().getAttribute("currentUser");

}
然后我将把我的DatabaseInvokerServlet继承到新的Servlet来做定制的事情,原因是在很多地方不使用try-catch-finally复制粘贴数据库调用块


但是,正如我所看到的,由于同步问题,这种方法无法工作。我说得对吗?

如果实用程序类具有state(例如:class或instance变量),那么很可能是的。

如果我猜对了,DBUtils将为每次调用getConnection()返回新实例由于DBUtils类是一个实用程序类,因此它不应该维护任何状态。在这种情况下,不需要任何额外的同步工作。

servlet在多个线程中运行

The J2EE spec says there is only one instance per servlet class running in one web container for non single thread servlet. 
Servlet 2.3规范

servlet容器可以发送 通过 servlet.To的服务方法 处理开发人员的请求 servlet必须提供足够的 并行处理的规定 服务中有多个线程 方法

servlet中的同步

Never have an member variable in a servlet, it is not thread safe.

如果DbUtils在同一线程中创建连接,如:

public static Connection getConnection() throws SQLException {
    return DriverManager.getConnection(url, username, password);
}
private static Connection connection = DriverManager.getConnection(url, username, password);

public static Connection getConnection() throws SQLException {
    return connection;
}
那么它是线程安全的

但如果连接是一个类变量,如:

public static Connection getConnection() throws SQLException {
    return DriverManager.getConnection(url, username, password);
}
private static Connection connection = DriverManager.getConnection(url, username, password);

public static Connection getConnection() throws SQLException {
    return connection;
}
那么它肯定不是线程安全的,因为相同的连接将在所有线程之间共享。另外,当它在一个线程中关闭时,所有后续线程将无法使用该连接,因为它不再打开。此外,当它从未关闭时,DB迟早会超时连接,通常在几个小时之后,并且您的应用程序阳离子不再工作,因为连接不再打开


至于servlet

public abstract class DatabaseInvokerServlet extends HttpServlet {
    private AbstractUser currentUser;
    private HttpServletRequest request;
    private HttpServletResponse response;
    // ...
}
它绝对不是线程安全的。您将当前用户、请求和响应分配为实例变量。从每个servlet类中,在应用程序的生命周期中只有一个实例。在整个应用程序的生命周期中,该实例在所有访问者/会话之间共享。每个HTTP请求在单独的线程中运行d使用相同的实例

想象两个同时访问的访问者:访问者A将设置当前用户、请求和响应。但是,DB过程需要很长时间。在访问者A的响应返回之前,访问者B调用同一个servlet,因此当前用户、请求和响应将被覆盖。然后,访问者A的查询完成,并希望写入响应,而是写入访问者B的响应!访问者B看到了访问者A的查询结果,而访问者A在屏幕上什么也看不到

永远不要将特定于请求/会话的数据分配为servlet的实例变量。应该将它们保持在方法(线程)本地


就整体而言,这种方法很笨拙。数据库访问层应该与servlet无关。它应该在自己的独立类中运行,您可以在其他Java类、任何servlet类或使用
main()的普通应用程序中构造/调用这些独立类
,或其他任何内容。在servlet类中不应该有任何一行
java.sql.
导入(如果没有抽象出来,可能会有
SQLException
),在数据库类中不应该有任何一行
javax.servlet.
导入

另见:

请发布DbUtils.getConnection()的代码;