Java:线程安全数据集实现

问题描述 投票:0回答:2

我创建了一个自定义SQLDataset实现,它接受SQL查询并将LinkedHashmap的List返回给请求控件,以便在JSP中显示或以Excel格式下载。

如果方法是线程安全的,请告诉我?

SQL DataSet.Java

package com.sqle.core;

import com.util.QueryProcessor;

import java.io.Serializable;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

public class SqlDataset implements Serializable {
    private String query;
    private QueryProcessor qp;
    private ResultSet rsSet;
    private List<LinkedHashMap<String, Object>> rsList = new ArrayList<>();
    private ArrayList<String> dataHeader = new ArrayList<>();

    public SqlDataset() {}

    public SqlDataset(String uquery) {
        this.query = uquery;
    }

    private ResultSet getQueryResult() throws Exception {
        qp = new QueryProcessor(query);
        this.rsSet = qp.getQueryResultSet();
        return this.rsSet;
    }

    public List<LinkedHashMap<String, Object>> getResult() throws Exception {
        return this.getValues(this.getQueryResult());
    }

    public List<LinkedHashMap<String, Object>> getResult(String query) throws Exception {
        this.query = query;
        return this.getValues(this.getQueryResult());
    }

    public int getRowCount() {
        return this.rsList.size();
    }

    public ArrayList getHeaders() {
        for (LinkedHashMap<String, Object> aRsList : this.rsList) {
            for (Map.Entry<String, Object> dh : aRsList.entrySet()) {
                if (!this.dataHeader.contains(dh.getKey()))
                    this.dataHeader.add(dh.getKey());
            }
        }
        return this.dataHeader;
    }

    private List<LinkedHashMap<String, Object>> getValues(ResultSet rs) throws SQLException {
        ResultSetMetaData rmd = rs.getMetaData();
        int columns = rmd.getColumnCount();

        while (rs.next()) {
            LinkedHashMap<String, Object> row = new LinkedHashMap<>(columns);
            for (int i = 1; i <= columns; ++i) {
                row.put(rmd.getColumnName(i), rs.getObject(i));
            }
            this.rsList.add(row);
        }
        return this.rsList;
    }
}

下面是请求控制器中编写的代码:

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    String act = request.getParameter("act").toLowerCase();
    RequestDispatcher rd = request.getRequestDispatcher("sqleditor.jsp");

    try {
        if (act.equalsIgnoreCase("exec")) {
            String uqry = request.getParameter("isql");
            if (!uqry.isEmpty()) {
                SqlDataset sd = new SqlDataset(uqry);
                rslist = sd.getResult();
                if (sd.getRowCount() > 0) {
                    headRow = sd.getHeaders();
                    request.setAttribute("resHead", headRow);
                    request.setAttribute("result", rslist);
                } else {
                    throw new NoDataException("No data found to display");
                }
            } else {
                throw new NoDataException("Please enter a query");
            }
            rd.forward(request, response);
        } else if (act.equalsIgnoreCase("excel")) {
            String uqry = request.getParameter("isql");
            if (!uqry.isEmpty()) {
                try {
                    SqlDataset sd = new SqlDataset();
                    rslist = sd.getResult(uqry);
                    if (sd.getRowCount() > 0) {
                        headRow = sd.getHeaders();
                        response.reset();
                        response.setContentType("application/vnd.ms-excel");
                        response.setHeader("Content-Disposition", "attachment; filename=\"" + FILENAME + "\"");
                        ExcelWriter ew = new ExcelWriter();
                        ew.initExcelfile(rslist, headRow, response.getOutputStream());
                    } else {
                        throw new NoDataException("No data found to download");
                    }
                } catch (Exception evar1) {
                    throw new AppException(evar1.getMessage());
                }
            } else {
                throw new NoDataException("Please enter a query");
            }
        }
    } catch (SQLException evar2) {
        request.setAttribute("errormsg", evar2.getMessage());
        rd.forward(request, response);
    } catch (NullPointerException evar3) {
        request.setAttribute("errormsg", evar3.getMessage());
        rd.forward(request, response);
    } catch (Exception evar4) {
        request.setAttribute("errormsg", evar4.getMessage());
        rd.forward(request, response);
    }
}

这个代码是否有效,多个用户是否使用此应用程序并连续运行不同的查询?

修改后的SQLdataset类:

package com.sqle.core;

import com.util.QueryProcessor;

import java.io.Serializable;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

public class SqlDataset implements Serializable {

    private List<LinkedHashMap<String, Object>> rsList = new ArrayList<>();

    public SqlDataset() {}

    private ResultSet getQueryResult(String query) throws Exception {
        QueryProcessor qp = new QueryProcessor(query);
        ResultSet rsSet = qp.getQueryResultSet();
        return rsSet;
    }

    public List<LinkedHashMap<String, Object>> getResult(String query) throws Exception {
        return this.getValues(this.getQueryResult(query));
    }

    public ArrayList getHeaders() {
        ArrayList<String> dataHeader = new ArrayList<>();

        for (LinkedHashMap<String, Object> aRsList : this.rsList) {
            for (Map.Entry<String, Object> dh : aRsList.entrySet()) {
                if (!dataHeader.contains(dh.getKey()))
                    dataHeader.add(dh.getKey());
            }
        }
        return dataHeader;
    }

    private List<LinkedHashMap<String, Object>> getValues(ResultSet rs) throws SQLException {
        ResultSetMetaData rmd = rs.getMetaData();
        int columns = rmd.getColumnCount();

        while (rs.next()) {
            LinkedHashMap<String, Object> row = new LinkedHashMap<>(columns);
            for (int i = 1; i <= columns; ++i) {
                row.put(rmd.getColumnName(i), rs.getObject(i));
            }
            this.rsList.add(row);
        }
        return this.rsList;
    }

    public int getRowCount() {
        return this.rsList.size();
    }
}
java java-ee
2个回答
1
投票

这取决于你如何使用这个类。

使用控制器中的doPost方法,它对多个用户来说是线程安全的,因为每次都会创建new SqlDataset对象。

这意味着它只能由处理单个请求的线程使用。

您的Controller代码是可重入且线程安全的。

如果您计划使用SqlDataset作为单例(例如Spring bean等),则BTW - 它不是线程安全的。它具有在过程中使用的实例变量 - 这意味着SqlDataset方法不可重入。

想想他们......

  • private QueryProcessor qp;方法中每次创建新实例时,你真的需要getQueryResult()吗?
  • 你真的需要private ArrayList<String> dataHeader = new ArrayList<>();,而你只是从getHeaders()返回它 - 为什么不在ArrayList循环方法之前创建新的for。 ...等等...

如果将所有内容作为参数传递给方法并返回在方法内创建的所有内容,则它将完全是线程安全的。

单例可能只有不可变的实例变量(逻辑上几乎是常量),以保持一些设置或属性适用于任何使用它的线程。


1
投票

SqlDataset.java本身不是线程安全的,因为你有实例变量。

但是,如果你只在你的一些request controller的方法中使用它,那么就没有问题了。这是因为Servlet不是线程安全的,但Servlets方法就是这样。

© www.soinside.com 2019 - 2024. All rights reserved.