Como impedir linhas/registros duplicados em uma JTable ou DefaultTableModel

Olá pessoal!
Sou novo no fórum do GUJ, e no java, e estou com uma dúvida quanto ao respeito do JTable e DefaultTableModel. A dúvida é o seguinte: tenho esses dois componentes trabalhando juntos e os dados que estão inseridos neles envio ao banco de dados, mas acontece que algum usuário na minha aplicação pode acabar adicionando o mesmo item na table duas vezes e isso não pode acontecer. O que gostaria de saber era como impedir de adicionar o mesmo item duas vezes e assim que fosse adicionado, que aparecesse uma mensagem informando que há item repetido e que apagasse esse ultimo item repetido. É só isso, fico muito grato se puderem me ajudar

mostra os atributos da entidade da tabela que esta sendo inserida

Simples, esqueça o default table model e use um Set como coleção dos dados exibidos e sobrescreva os métodos hash e equals da classe cujo objeto é exibido na JTable.

Poderia me dar um exemplo de como fazer?

Abaixa esta o codigo

String colunas[] = {"Nº", "Quantidade", "Descrição", "Categoria", "Total", "Cód sis", "Preço unitário"};
private void jButton3ActionPerformed(java.awt.event.ActionEvent evt) {                                         
        // Botão enviar para a tabela
        if (txtPrecoS.getText().isEmpty() || txtQtd.getText().isEmpty() || txtIDS.getText().isEmpty() || txtCategoriaServico.getText().isEmpty()) {
            JOptionPane.showMessageDialog(null, "Preencha os campos em branco");
        } else {
            double precoDoServico = Double.parseDouble(txtPrecoS.getText());
            double quantidade = Double.parseDouble(txtQtd.getText());
            String categoria = txtCategoriaServico.getText();
            String desc = txtServico.getText();
            double total = precoDoServico * quantidade;
            int id = Integer.parseInt(txtIDS.getText());
            double precoUnitario = Double.parseDouble(txtPrecoS.getText());
            // Insere os dados no DefaultTableModel
            
            modelo.addRow(new String[]{String.valueOf(tabelaOServico.getRowCount() + 1), String.valueOf(quantidade), desc, categoria, String.valueOf(total), String.valueOf(id), String.valueOf(precoUnitario)});

            // Associa o DefaultTableModel ao JTable
            tabelaOServico.setModel(modelo);
            verificaJTable(modelo, 5, id);
            GuiUtils gu = new GuiUtils();
            gu.selectAndScroll(tabelaOServico, tabelaOServico.getRowCount()-1);
            tabelaOServico.getColumnModel().getColumn(5).setMinWidth(0);
            tabelaOServico.getColumnModel().getColumn(5).setMaxWidth(0);
            txtQtd.setText("0");
            txtServico.setText(null);
            txtPrecoS.setText("0");
            txtIDS.setText(null);
            txtCategoriaServico.setText(null);
        }
    }

Como escrevi anteriormente:

Crie seu próprio table model. Para isso, você pode usar uma das milhares de opções disponíveis na internet (aqui mesmo no guj tem vários).

Eu criei o meu próprio model conforme este link aqui:
[https://devsv.wordpress.com/2012/07/08/como-implementar-um-tablemodel/] (http://Como implementar um tablemodel)
Meu código

private List<TMServico> criaServico() {
        List<TMServico> servicos = new ArrayList<TMServico>();
        TMServico tmservico = new TMServico();
        tmservico.setQuantidade(Integer.parseInt(txtQtd.getText()));
        tmservico.setDescricao(txtServico.getText());
        tmservico.setCategoria(txtCategoriaServico.getText());
        tmservico.setTotal(Double.parseDouble(txtPrecoS.getText()) * Double.parseDouble(txtQtd.getText()));
        tmservico.setPrecoUnitario(Double.parseDouble(txtPrecoS.getText()));
        servicos.add(tmservico);
        return servicos;
    }

Agora a minha dúvida é que ele só adiciona um elemento ao jtable(botei esse metodo em actionperformed de um botão)
já tentei de várias maneiras para inserir mais de um elemento ao jtable mas nao consigo, quando tento usar estruturas de repetição o programa simplesmente trava.
Saberia como eu poderia adicionar mais de um elemento ao meu jtable? pois com este meu método ele só adiciona um elemento só

Mostre o que fez e diga por que não consegue. Só escrever isso é o mesmo que dizer que não fez nada.

Primeiro desculpe pela demora a responder, poi estava sem internet e estava tentando fazer.
Agora vou mostrar o que eu conseguir fazer seguindo as dicas que me passou

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package br.com.projeto.model;

import java.util.Objects;

/**
 *
 * @author pc01
 */
public class TServico {
    private int n;
    private double quantidade;
    private String descricao;
    private String categoria;
    private double total;
    private int id;
    private double precoUnitario;

    public int getN() {
        return n;
    }

    public void setN(int n) {
        this.n = n;
    }

    public double getQuantidade() {
        return quantidade;
    }

    public void setQuantidade(double quantidade) {
        this.quantidade = quantidade;
    }

    public String getDescricao() {
        return descricao;
    }

    public void setDescricao(String descricao) {
        this.descricao = descricao;
    }

    public String getCategoria() {
        return categoria;
    }

    public void setCategoria(String categoria) {
        this.categoria = categoria;
    }

    public double getTotal() {
        return total;
    }

    public void setTotal(double total) {
        this.total = total;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public double getPrecoUnitario() {
        return precoUnitario;
    }

    public void setPrecoUnitario(double precoUnitario) {
        this.precoUnitario = precoUnitario;
    }
    
    @Override
    public int hashCode() {
        return Objects.hash(n,quantidade,descricao,categoria,total,id,precoUnitario);
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        TServico other = (TServico) obj;
        if (n != other.n)
            return false;
        if(quantidade != other.quantidade)
            return false;
        if (!Objects.equals(descricao, other.descricao))
            return false;
        if (!Objects.equals(categoria, other.categoria))
            return false;
        if (total != other.total)
            return false;
        if (id != other.id)
            return false;
        if (precoUnitario != other.precoUnitario)
            return false;
        return true;
    }
}

A classe do serviço com os métodos get e set e também o equals e o hash code sobrescritos

Criei um método para poder adicionar os serviços ao hashset

public Set<TServico> addServico() {
        // Criar a lista que irá receber os serviços
        Set<TServico> servicoAdd;
        servicoAdd = new HashSet<TServico>();
        //Criar o objeto TServico
       
            TServico tServico = new TServico();

            tServico.setN(tabelaOServico.getRowCount() + 1);
            tServico.setQuantidade(Double.parseDouble(txtQtd.getText()));
            tServico.setDescricao(txtServico.getText());
            tServico.setCategoria(txtCategoriaServico.getText());
            tServico.setTotal(Double.parseDouble(txtQtd.getText()) * Double.parseDouble(txtPrecoS.getText()));
            tServico.setPrecoUnitario(Double.parseDouble(txtPrecoS.getText()));
            servicoAdd.add(tServico);
        

        return servicoAdd;

    }

E criei outro método para mostrar a lista na tabela segue ae:

public void mostrar(Set<TServico> ts) {
        modelo = (DefaultTableModel) tabelaOServico.getModel();
        modelo.setNumRows(0);
        Iterator<TServico> servicoIterator = ts.iterator();
        while (servicoIterator.hasNext()) {
            TServico tgs = servicoIterator.next();
            modelo.addRow(new String[]{
                String.valueOf(tabelaOServico.getRowCount() + 1),
                String.valueOf(tgs.getQuantidade()),
                tgs.getDescricao(),
                tgs.getCategoria(),
                String.valueOf(tgs.getQuantidade() * tgs.getPrecoUnitario()),
                String.valueOf(tgs.getId()),
                String.valueOf(tgs.getPrecoUnitario())
            });
        }
    }

E também fiz um evento chamando os métodos acima

mostrar(addServico());

E o problema é que ele não adiciona mais de um elemento a tabela e sim substitui o primeiro elemento que foi adicionado. No método addServico(), tentei usar while, for, do while e nada de adicionar elementos diferentes a tabela o programa simplesmente trava ou quando uso o for ele adiciona x vezes o mesmo elemento.

Será que agora ficaria melhor para você continuar a me ajudar?
Grato

Não criou não, seu código está assim:

modelo = (DefaultTableModel) tabelaOServico.getModel();

Este era outro, eu estava tentando passar os dados do meu set para o defaulttablemodel

E por qual motivo?

Para não fazer tantas implementações.
O problema de enviar do set para o DefaultTableModel é que ele só envia um item, e quando você tenta enviar outro item ele simplesmente atualiza o produto que já estava na tabela e não adiciona, é como se ele sobrescrevesse o item já existente no DefaultTableModel ao invés de ter de mais de um item

Mas qual o problema com implementações? Preguiça?
Cara, você está vendo que o dtm é péssimo, nada flexível e difícil de manter. Se tivesse criado seu próprio table model, como sugerido, teria perdido 30 minutos e já teria resolvido o problema.
Note que todas as respostas sugerem remover o dtm e você insiste em fazer uso dele. Se não quer sugestões, não tem que perguntar. Basta fazer do teu jeito e pronto.

Mas eu fiz o meu próprio model, está era uma alternativa que tinha feito, tanto é que vou postar meu Código de acordo com a sua sugestão, estou trabalhando em paralelo tanto com dtm como com o próprio model. segue abaixo os códigos

O model

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package br.com.projeto.tablemodel;

import br.com.projeto.model.TMServico;
import java.util.ArrayList;
import java.util.List;
import javax.swing.table.AbstractTableModel;

/**
 *
 * @author pc01
 */
public class ServicoTableModelOS extends AbstractTableModel {

    // Lista de Serviços a serem exibidos na tabela
    private List<TMServico> linhas;

    // Cria um ServicoTableModelOS sem nenhuma linha
    public ServicoTableModelOS() {
        linhas = new ArrayList<TMServico>();
    }

    // Cria um ServicoTableModelOS contendo a lista recebida por parametro
    public ServicoTableModelOS(List<TMServico> listaDeServicos) {
        linhas = new ArrayList<TMServico>(listaDeServicos);
    }

    // Array com o nome das colunas
    private String[] colunas = new String[]{"Nº", "Quantidade", "Descrição", "Categoria", "Total", "id", "Preço Unitário"};

    // Constantes recebendo os indices das colunas
    private static final int N = 0;
    private static final int QUANTIDADE = 1;
    private static final int DESCRICAO = 2;
    private static final int CATEGORIA = 3;
    private static final int TOTAL = 4;
    private static final int ID = 5;
    private static final int PRECOUNITARIO = 6;

    @Override
    public int getRowCount() {
        return linhas.size();
    }

    @Override
    public int getColumnCount() {
        return colunas.length;
    }

    @Override
    public String getColumnName(int columnIndex) {
        return colunas[columnIndex];
    }

    @Override
    public Class<?> getColumnClass(int columnIndex) {
        switch (columnIndex) {
            case N:
                return int.class;
            case QUANTIDADE:
                return int.class;
            case DESCRICAO:
                return String.class;
            case CATEGORIA:
                return String.class;
            case TOTAL:
                return double.class;
            case ID:
                return int.class;
            case PRECOUNITARIO:
                return double.class;
            default:
                // Não deve ocorrer pois só existem 7 colunas
                throw new IndexOutOfBoundsException("columnIndex out of bounds");
        }
    }

    @Override
    public boolean isCellEditable(int rowIndex, int columnIndex) {
        return false;
    }

    @Override
    public Object getValueAt(int rowIndex, int columnIndex) {
        // Pega o serviço referente a linha especificada.
        TMServico tmservico = linhas.get(rowIndex);
        switch (columnIndex) {
            case N:
                return this.getRowCount();
            case QUANTIDADE:
                return tmservico.getQuantidade();
            case DESCRICAO:
                return tmservico.getDescricao();
            case CATEGORIA:
                return tmservico.getCategoria();
            case TOTAL:
                return tmservico.getTotal();
            case ID:
                return tmservico.getId();
            case PRECOUNITARIO:
                return tmservico.getPrecoUnitario();
            default:
                throw new IndexOutOfBoundsException("columnIndex out of bounds");
        }
    }

    @Override
    public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
        //Pega o serviço referente a linha selecionada
        TMServico tmservico = linhas.get(rowIndex);
        switch (columnIndex) {
            case N:
                ;
            case QUANTIDADE:
                tmservico.setQuantidade(Integer.parseInt(aValue.toString()));
            case DESCRICAO:
                tmservico.setDescricao(aValue.toString());
            case CATEGORIA:
                tmservico.setCategoria(aValue.toString());
            case TOTAL:
                tmservico.setTotal(Double.parseDouble(aValue.toString()));
            case ID:
                tmservico.setId(Integer.parseInt(aValue.toString()));
            case PRECOUNITARIO:
                tmservico.setPrecoUnitario(Double.parseDouble(aValue.toString()));
                break;
            default:
                //Não deve ocorrer pois só existem 4 colunas
                throw new IndexOutOfBoundsException("columnIndex out of bounds");
        }
        fireTableCellUpdated(rowIndex, columnIndex); // Notifica a atualização da célula
    }

    // Métodos para manipular dadados
    // Retorna o serviço referente a linha especificada
    public TMServico getTMServico(int indiceLinha) {
        return linhas.get(indiceLinha);
    }

    // Adiciona o serviço especificado ao modelo
    public void addServico(TMServico tmservico) {
        // Adiciona o registro.
        linhas.add(tmservico);

        // Pega a quantidade de registros e subtrai 1 para
        // acahar o último índice. A subtração é necessária
        // porque os índices começam em zero.
        int ultimoIndice = getRowCount() - 1;

        // Notifica a mudança
        fireTableRowsInserted(ultimoIndice, ultimoIndice);
    }

    public void removeServico(int indiceLinha) {
        // Remove o registro
        linhas.remove(indiceLinha);

        // Notifica a mudança
        fireTableRowsDeleted(indiceLinha, indiceLinha);
    }

    // Adiciona uma lista de serviços no final da lista
    public void addListaDeServicos(List<TMServico> tmservico) {
        // Pega o tamanho antiga da tabela, que servirá
        // como índice para o primeiro dos novos registros
        int indice = getRowCount();

        // Adiciona os registros
        linhas.addAll(tmservico);

        // Notifica a mudança
        fireTableRowsInserted(indice, indice + tmservico.size());
    }

    // Remove todos os registros
    public void limpar() {
        // Remove todos os elementos da lista de sócios.
        linhas.clear();

        // Notifica a mudança
        fireTableDataChanged();
    }
}

os métodos de implementação do model

private ServicoTableModelOS tableModel;
    private ServicoTableModelOS getTableModel() {
            if (tableModel == null) {
                tableModel = new ServicoTableModelOS(criaServico());
            }
            return tableModel;
        }

        //Cria uma lista de servicos
        private List<TMServico> criaServico() {
    //        List<TMServico> servicos = new ArrayList<TMServico>();
    //        TMServico tmservico = new TMServico();
    //        tmservico.setQuantidade(Integer.parseInt(txtQtd.getText()));
    //        tmservico.setDescricao(txtServico.getText());
    //        tmservico.setCategoria(txtCategoriaServico.getText());
    //        tmservico.setTotal(Double.parseDouble(txtPrecoS.getText()) * Double.parseDouble(txtQtd.getText()));
    //        tmservico.setPrecoUnitario(Double.parseDouble(txtPrecoS.getText()));
    //        servicos.add(tmservico);
    //        return servicos;

            List<TMServico> lista = new ArrayList<>();
            for(int i = 0; i <= 2; i++){
                TMServico servico  = new TMServico();
                servico.setQuantidade(Integer.parseInt(txtQtd.getText()));
                servico.setDescricao(txtServico.getText());
                servico.setCategoria(txtCategoriaServico.getText());
                servico.setTotal(Double.parseDouble(txtPrecoS.getText()) * Double.parseDouble(txtQtd.getText()));
                servico.setPrecoUnitario(Double.parseDouble(txtPrecoS.getText()));
                lista.add(servico);
            }
            return lista;
            

        }

e classe com os metodos get e set

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package br.com.projeto.model;

import java.util.Objects;

/**
 *
 * @author pc01
 */
public class TServico {
    private int n;
    private double quantidade;
    private String descricao;
    private String categoria;
    private double total;
    private int id;
    private double precoUnitario;

    public int getN() {
        return n;
    }

    public void setN(int n) {
        this.n = n;
    }

    public double getQuantidade() {
        return quantidade;
    }

    public void setQuantidade(double quantidade) {
        this.quantidade = quantidade;
    }

    public String getDescricao() {
        return descricao;
    }

    public void setDescricao(String descricao) {
        this.descricao = descricao;
    }

    public String getCategoria() {
        return categoria;
    }

    public void setCategoria(String categoria) {
        this.categoria = categoria;
    }

    public double getTotal() {
        return total;
    }

    public void setTotal(double total) {
        this.total = total;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public double getPrecoUnitario() {
        return precoUnitario;
    }

    public void setPrecoUnitario(double precoUnitario) {
        this.precoUnitario = precoUnitario;
    }
    
    @Override
    public int hashCode() {
        return this.id;
    }

    @Override
    public boolean equals(Object obj) {
        //se nao forem objetos da mesma classe sao objetos diferentes
        if(!(obj instanceof TServico)) return false; 
        
        //se forem o mesmo objeto, retorna true
        if(obj == this) return true;
        
        // aqui o cast é seguro por causa do teste feito acima
        TServico servico = (TServico) obj;
        
        //aqui você compara a seu gosto, o ideal é comparar atributo por atributo
        return this.id == servico.getId();
                
    }
}

e outra classe com metodos get e set usada em outra alternativa

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package br.com.projeto.model;

/**
 *
 * @author pc01
 */
public class TMServico {
    private int quantidade;
    private String descricao;
    private String categoria;
    private double total;
    private int id;
    private double precoUnitario;

    public int getQuantidade() {
        return quantidade;
    }

    public void setQuantidade(int quantidade) {
        this.quantidade = quantidade;
    }

    public String getDescricao() {
        return descricao;
    }

    public void setDescricao(String descricao) {
        this.descricao = descricao;
    }

    public String getCategoria() {
        return categoria;
    }

    public void setCategoria(String categoria) {
        this.categoria = categoria;
    }

    public double getTotal() {
        return total;
    }

    public void setTotal(double total) {
        this.total = total;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public double getPrecoUnitario() {
        return precoUnitario;
    }

    public void setPrecoUnitario(double precoUnitario) {
        this.precoUnitario = precoUnitario;
    }
    
    
}

como podem ver eu tentei eu só não sei porque não adiciona mais de um a tabela