Java: потокобезопасная реализация набора данных - PullRequest
0 голосов
/ 12 февраля 2019

Я создал пользовательскую реализацию SQLDataset, в которой он принимает запрос SQL и возвращает список LinkedHashmap обратно в контроллер запросов для отображения в JSP или загрузки в формате Excel.

Не могли бы вы сообщить мне, еслиподход является поточно-ориентированным?

SqlDataset.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();
    }
}

Ответы [ 2 ]

0 голосов
/ 12 февраля 2019

Сам по себе SqlDataset.java не является потокобезопасным, поскольку в нем есть переменные экземпляра.

Однако, если вы используете его только в некоторых ваших request controller методах, проблем не будет.Это потому, что Servlet не является потокобезопасным, но методы Servlets таковы.

0 голосов
/ 12 февраля 2019

Это зависит от того, как вы используете этот класс.

С помощью вашего метода doPost в контроллере он является потокобезопасным для нескольких пользователей, поскольку вы каждый раз создаете объект new SqlDataset.

Это означает, что он будет использоваться только тем потоком, который обрабатывает одинзапрос.

Ваш код контроллера является входящим и безопасным для потоков.

Кстати, если вы планируете использовать SqlDataset в качестве синглтона (например, Spring bean или тому подобное) - он не безопасен для потоков,У него есть переменные экземпляра, используемые в процессе - это означает, что SqlDataset методы не являются входящими.

просто подумайте о них ...

  • вам действительно нужно private QueryProcessor qp; когда вы каждый раз создаете новый экземпляр в методе getQueryResult()?

  • вам действительно нужно private ArrayList<String> dataHeader = new ArrayList<>();, пока вы просто возвращаете его из getHeaders() - почему бы просто не создатьnew ArrayList before for loop внутри метода.... и так далее ...

Если вы сделаете все, что передано методам в качестве параметров, и вернете все, что создано внутри методов, это будет полностью поточно-ориентированным.

Singletonsможет иметь только неизменяемые переменные экземпляра (логически почти константы), чтобы сохранить некоторые настройки или свойства, применимые к любым потокам, которые его используют.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...