首页 > 解决方案 > 在包含数据库数据的列表中使用线程

问题描述

我试图在我在数据库中进行的查询中使用一个线程,该线程可以生成许多我不知道是否有必要的记录但是当我尝试实现线程时它没有返回该列表中的值(没有线程它通常返回值)

我的控制器:在这里我调用我的方法,该方法将包含我的 DAO 类数据库列表:

public ObservableList<Requisicao> atualizarTabela() {
    RequisicaoDAO dao = new RequisicaoDAO();
    requisicoes = FXCollections.observableArrayList(dao.getList());
    return requisicoes;
}

我的方法 DAO:

public class RequisicaoDAO {

    private Connection con;
    Alerts alerts = new Alerts();
    public RequisicaoDAO() {
        this.con = new ConnectionFactory().getConnection();
    }

    private static RequisicaoDAO aRequisicaoDAO;

    public static RequisicaoDAO getInstancia() {

        if (aRequisicaoDAO == null) {
            aRequisicaoDAO = new RequisicaoDAO();
        }

        return aRequisicaoDAO;
    }
   public List<Requisicao> getList() {
        List<Requisicao> requisicoes = new ArrayList<>();
        new Thread() {
        @Override
        public void run() {
        String sql = "SELECT * FROM equipamento_requisicao equipreq INNER JOIN equipamento_user equipuser ON (equipreq.idequipamento_user = equipuser.id_equipamento_do_usuario)  INNER JOIN usuario user ON (user.id_usuario=equipuser.idusuario) INNER JOIN equipamentos equip ON (equip.id_equipamentos = equipuser.idequipamentos) INNER JOIN detalhe_status dStatus ON (dStatus.idequipamento_requisicao= equipreq.id_equipamento_requisicao) INNER JOIN status_requisicao statusreq on (statusreq.id_status= dStatus.idstatus) INNER JOIN permissao p ON(user.idpermissao= p.id_permissao) INNER JOIN departamentos dp ON(user.iddepartamento = dp.id_departamentos) INNER JOIN chefe_departamento cp ON(dp.id_chefe = cp.id_chefe) where statusreq.categoria='Ativa' ";
        try {
            PreparedStatement stmt = con.prepareStatement(sql);
            ResultSet rs = stmt.executeQuery();
            while (rs.next()) {       
                Usuario usuario = new Usuario();
                usuario.setNome(rs.getString("user.nome"));
                usuario.setId(rs.getLong("user.id_usuario"));
                usuario.setMatricula(rs.getString("user.matricula"));
                // FIM TABELA USUARIO               
                //equipamento // equipamento user tabelas
                Equipamentos equipamento = new Equipamentos();
                equipamento.setEquipamento_nome(rs.getString("equip.equipamento_nome"));
                equipamento.setSerial_equipamento(rs.getString("equipuser.serial_equipamento"));
                equipamento.setId_equipamento_do_Usuario(rs.getLong("equipreq.idequipamento_user"));
                //status tabela
                Status status = new Status();
                status.setCategoria(rs.getString("statusreq.categoria"));
                status.setIdstatus(rs.getInt("statusreq.id_status"));
                //status detalhes tabela
                Usuario usuarioStatus = new Usuario();//id do usuaro na tabela detalhes status
                usuarioStatus.setId(rs.getLong("dStatus.idusuario"));
                StatusDetalhes statusDetalhes = new StatusDetalhes();
                statusDetalhes.setId_statusdetalhes(rs.getLong("dStatus.id_statusdetalhes"));
                statusDetalhes.setData_status(rs.getTimestamp("dStatus.data"));
                statusDetalhes.setObservacao_status(rs.getString("dStatus.observacao"));
                statusDetalhes.setIdUsuario(usuarioStatus);
                statusDetalhes.setIdStatus(status);
                // Id da requisicao na tabela detalhes status
                Requisicao requisicaoStatus = new Requisicao();
                requisicaoStatus.setId(rs.getLong("dStatus.idequipamento_requisicao"));
                //requisicao tabela
                Requisicao req = new Requisicao();
                req.setId(rs.getLong("equipreq.id_equipamento_requisicao"));
                req.setNome(rs.getString("equipreq.nome"));
                req.setData_criada(rs.getTimestamp("equipreq.data_requisicao"));
                req.setMotivo(rs.getString("equipreq.observacao"));
                req.setReqEquipamento(equipamento);
                req.setReqStatus(status);
                req.setReqUsuario(usuario);
                req.setReqStatus_Detalhes(statusDetalhes);
                requisicoes.add(req);
            }
            stmt.close();
            rs.close();
        } catch (SQLException ex) {
            Logger.getLogger(RequisicaoDAO.class.getName()).log(Level.SEVERE, null, ex);
        }

        }
        }.start();
        return requisicoes;
    }
}

不会产生任何错误,但我没有在我的表格视图中得到这个列表我认为问题出在返回 requisicoes 中;但我无法解决。

标签: javajavafx

解决方案


问题是,您requisicoes在线程向其添加任何内容之前返回值。

因为 Thread 是异步执行的,所以执行看起来像这样:

用两个线程执行

所以查询工作正常(不使用线程时你会看到正确的结果),但是它们被添加到列表中很晚,因为(空)列表已经复制到新的可观察列表中,因此添加了结果不再影响控制器中的可观察列表。

一个解决方案可能是在返回列表之前等待线程的执行requisicoes(通过调用线程的join 方法。但这会导致该方法getList()花费很多时间(因为它正在等待线程),这可能是你想要的通过使用线程来避免。

另一个(可能更好)的解决方案是从方法中删除多线程,getList()并使用任务将多线程添加到控制器中。

解决方案可能如下所示:

public ObservableList<Requisicao> atualizarTabela() {
    RequisicaoDAO dao = new RequisicaoDAO();
    //create an empty list first
    requisicoes = FXCollections.observableArrayList();
    //execute the query in the task
    Task<List<Requisicao>> task = new Task<List<Requisicao>>() {

        @Override
        protected List<Requisicao> call() throws Exception {
            //getList has no thread anymore
            return dao.getList();
        }

    };
    //add the list values to the observable list, when the task succeeds
    task.setOnSucceeded(e -> requisicoes.addAll(task.getValue()));
    task.setOnFailed(e -> System.out.println("Task failed"));//better do some execption handling here...

    //start the task in a new thread
    Thread executor = new Thread(task, "get_list_task_thread");
    executor.start();

    //return the (empty) list, which will be filled when the task (that includes the query) has finished
    return requisicoes;
}

如果您像这样更改代码(并从方法中删除线程,getList()它应该首先返回一个空的ObservableList,在任务(包括查询)完成后显示和填充。这个解决方案的优点是,它没有t 在执行查询时停止执行 FX-Thread,因此 UI 不会停止。


推荐阅读