Erro ao Alterar Dados gravados em Banco de Dados

Olá, estou com um problema ao tentar alterar cadastros gravados no banco de dados, poderiam me ajudar ?

Tenho esse código para alterar os dados no banco de dados:

public void alterarNome(Agenda obj){ Connection c = new Conexao().criarConexao(); String sql = "UPDATE agenda SET nome= ?, email = ?, cpf = ? WHERE nome = ?"; try { PreparedStatement p = c.prepareStatement(sql); p.setString(1, obj.getNome()); p.setString(2, obj.getEmail()); p.setString(3, obj.getCpf()); p.executeUpdate(); } catch (SQLException ex) { Logger.getLogger(GerenciaAgenda.class.getName()).log(Level.SEVERE, null, ex); } finally{ new Conexao().fecharConexao(c); } }

E esse aqui da tela de de Pesquisas:

JButton btnPesquisar = new JButton("Pesquisar"); btnPesquisar.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent arg0) { if (cbxEditar.getSelectedItem().equals("")){ JOptionPane.showMessageDialog(null, "Escolha um filtro!"); }if (txtPesquisar.getText().isEmpty()){ JOptionPane.showMessageDialog(null, "Informe um Nome, E-Mail ou Cpf"); }else if (cbxEditar.getSelectedItem().equals("Nome")){ GerenciaAgenda ga = new GerenciaAgenda(); txtNome.setEditable(true); txtEmail.setEditable(true); txtCpf.setEditable(true); Agenda a = ga.selecionarNome(txtPesquisar.getText()); txtNome.setText(a.getNome()); txtEmail.setText(a.getEmail()); txtCpf.setText(a.getCpf()); }else if (cbxEditar.getSelectedItem().equals("E-Mail")){ GerenciaAgenda ga = new GerenciaAgenda(); txtNome.setEditable(true); txtEmail.setEditable(true); txtCpf.setEditable(true); Agenda a = ga.selecionarEmail(txtPesquisar.getText()); txtNome.setText(a.getNome()); txtEmail.setText(a.getEmail()); txtCpf.setText(a.getCpf()); }else if (cbxEditar.getSelectedItem().equals("Cpf")){ GerenciaAgenda ga = new GerenciaAgenda(); txtNome.setEditable(true); txtEmail.setEditable(true); txtCpf.setEditable(true); Agenda a = ga.selecionarCpf(txtPesquisar.getText()); txtNome.setText(a.getNome()); txtEmail.setText(a.getEmail()); txtCpf.setText(a.getCpf()); } } });

E esse outro para o Jbutton Alterar:

JButton btnConfirmar = new JButton("Alterar"); btnConfirmar.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { if (txtNome.getText().isEmpty() || txtEmail.getText().isEmpty() || txtCpf.getText().isEmpty()) { JOptionPane.showMessageDialog(null, "Nenhum cadastro selecionado!"); }else{ int i=JOptionPane.showOptionDialog(null,"Deseja alterar esse cadastro ?","Editar",JOptionPane.YES_NO_OPTION,JOptionPane.QUESTION_MESSAGE,null,options,options[0]); if (i==JOptionPane.YES_OPTION){ GerenciaAgenda ga = new GerenciaAgenda(); Agenda a = new Agenda(); a.setNome(txtNome.getText()); a.setEmail(txtEmail.getText()); a.setCpf(txtCpf.getText()); ga.alterarNome(a); JOptionPane.showMessageDialog(null, "Operação Realizada!"); } } } }); btnConfirmar.setBounds(221, 230, 97, 23); JFeditar.add(btnConfirmar);

Quando eu executo o programa e clico no botão alterar aparece esse erro:

Nov 08, 2014 11:16:38 AM GerenciaAgenda alterarNome SEVERE: null java.sql.SQLException: No value specified for parameter 4 at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1056) at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:957) at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:927) at com.mysql.jdbc.PreparedStatement.fillSendPacket(PreparedStatement.java:2179) at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:1996) at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:1940) at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:1925) at GerenciaAgenda.alterarNome(GerenciaAgenda.java:65) at Editar$3.actionPerformed(Editar.java:154) at javax.swing.AbstractButton.fireActionPerformed(Unknown Source) at javax.swing.AbstractButton$Handler.actionPerformed(Unknown Source) at javax.swing.DefaultButtonModel.fireActionPerformed(Unknown Source) at javax.swing.DefaultButtonModel.setPressed(Unknown Source) at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(Unknown Source) at java.awt.Component.processMouseEvent(Unknown Source) at javax.swing.JComponent.processMouseEvent(Unknown Source) at java.awt.Component.processEvent(Unknown Source) at java.awt.Container.processEvent(Unknown Source) at java.awt.Component.dispatchEventImpl(Unknown Source) at java.awt.Container.dispatchEventImpl(Unknown Source) at java.awt.Component.dispatchEvent(Unknown Source) at java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source) at java.awt.LightweightDispatcher.processMouseEvent(Unknown Source) at java.awt.LightweightDispatcher.dispatchEvent(Unknown Source) at java.awt.Container.dispatchEventImpl(Unknown Source) at java.awt.Window.dispatchEventImpl(Unknown Source) at java.awt.Component.dispatchEvent(Unknown Source) at java.awt.EventQueue.dispatchEventImpl(Unknown Source) at java.awt.EventQueue.access$200(Unknown Source) at java.awt.EventQueue$3.run(Unknown Source) at java.awt.EventQueue$3.run(Unknown Source) at java.security.AccessController.doPrivileged(Native Method) at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source) at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source) at java.awt.EventQueue$4.run(Unknown Source) at java.awt.EventQueue$4.run(Unknown Source) at java.security.AccessController.doPrivileged(Native Method) at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source) at java.awt.EventQueue.dispatchEvent(Unknown Source) at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source) at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source) at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source) at java.awt.EventDispatchThread.pumpEvents(Unknown Source) at java.awt.EventDispatchThread.pumpEvents(Unknown Source) at java.awt.EventDispatchThread.run(Unknown Source)

Consegui descobri o que era. Faltava o ultimo parâmetro do comando sql.

public void alterarNome(Agenda obj){ Connection c = new Conexao().criarConexao(); String sql = "UPDATE agenda SET nome= ?, email = ?, cpf = ? WHERE nome = ?"; try { PreparedStatement p = c.prepareStatement(sql); p.setString(1, obj.getNome()); p.setString(2, obj.getEmail()); p.setString(3, obj.getCpf()); p.setInt(4, obj.getId()); // aqui p.executeUpdate(); } catch (SQLException ex) { Logger.getLogger(GerenciaAgenda.class.getName()).log(Level.SEVERE, null, ex); } finally{ new Conexao().fecharConexao(c); } }