registro repetido jsp + mysql

Hola que tal.. les cuento que estoy desarrollando una apliccion web con jsp y mysql desplegada en tomcat, tengo entre 6 y 8 usuarios diarios enviando y consultando informacion en simultaneo desde cualquier punto d la ciudad... desde smartphones y pcs...
he resuelto lo del sincronismo solo a los metodos de acceso y modificacion de la database..., y todo funciona ok, con velocidad ok, respetando cada susario sus sesiones..., pero de vez en cuando me sucede lo de asunto...,si... se repite el registro a algun usuario(cada do o tres dias a uno o dos usuarios les sucede) con el mismo cliente y el mismo valor como lo pueden ver en el registro 29 y 30 en el adjunto llamado reporte de registro repetido(el valor en este archivo es de 550 porque lo modifique pero era el mismo). (registro ·#29))A las 2:17:54 el usuario hace el registro desde su celular...(para esto utilizo un jsp llamado registrarPEDIDO.jsp y si pasa algo controlo con try catch retornandolo al login.jsp) el usuario reporta que el sistema lo saca y lo lleva al page de login.jsp(pues asi lo tengo configurado en las directivas de la pagina), y cuando vuelve a entrar, vuelve a montar la solicitud y la envia... y es ahi cuando aparece el registro repetido..., (registro #30)a las 2:19:17 ...; adjunto log_tomcat.jpg para que aprecien el seguimiento de acceso del tomcat.
Nota: cuando el sistema saca al usuario lo lleva al login.jsp y alli capturo session(request.getSesion()) y luego la sesion.invalidate() pensando en matar toda sesion que venga perdida pero parece no funcione porque se repiten registros todavia...
No se si queda la sesion viva todavia y cuando el usuario entra nuevamente y vuelve a armar la solicitud y la envia, se reenvia la que estava perdida... o no se que pueda ser...
Agradezco su atencion y colaboracion a este problema que no le veo por donde...

AdjuntoTamaño
reporte registro repetidos.jpg349.6 KB
log_tomcat.jpg359.09 KB

Opciones de visualización de comentarios

Seleccione la forma que prefiera para mostrar los comentarios y haga clic en «Guardar las opciones» para activar los cambios.

Pues depende de lo que tu

Pues depende de lo que tu aplicación esté haciendo ( tu código )

Al parecer hay algún error de comunicación entre alguna de las partes ( del browser del usuario a tu servidor, o de tu servidor a la base de datos ) pero la petición le llega a tu servidor e inserta el registro. Luego tu aplicación cuando hay algún error en vez de darle rollback a la transacción ( no insertarla ) o de avisarle al usuario que su petición está completa, lo único que hace es mostrarle la pantalla de login. El usuario se vuelve a registrar (creando una nueva sesión) y de ahí vuelve a hacer su trabajo que es enviar de nuevo el pedido, obvio por la misma cantidad y el mismo cliente.

Entonces tienes dos registros, porque el usuario lo está insertando dos veces. Lo más probable es que su red se caiga y por un momento parece que no termina la petición, es por eso que cuando se reconecta lo ves con otra IP, pero si miras el rango está en la misma red.

Lo que tienes que hacer es o A) No insertar la información hasta que esté todo correcto o B) Decirle al usuario que su información fue correctamente insertada.

Para saber que está haciendo tu aplicación revisa tu código con viendo si este escenario se está dando.

Imagen de tav

gracias por el aporte...

Hola OscarRyz gracia por el aporte... te envio el codigo para registrar el pedido..., maneja transaccines desde la conexion:
le paso el pedido y la lista de productos.... hago manejo de transacciones desde la conx... Gracias...

public synchronized boolean registrarPEDIDO1(Pedido p, ArrayList lr) throws SQLException{
    boolean b=false; Connection conx=null; Statement estx=null;
       try{      
            String vf=fecha_actualamd();;
            String vh=hora_actualhms();
            String vfe=p.fe;
            Class.forName(controlador);            
             conx= DriverManager.getConnection(vdb1,vdb2,vdb3);
              conx.setAutoCommit(false);    //manejo de transaccion
              estx=conx.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_READ_ONLY);
           
             String sql= "insert into pedidos (f,h,fe,trabajador,negocio,estado) VALUES('"+ vf + "','" + vh + "','" + vfe + "'," + p.vendedor +  "," + p.negocio + ","+ p.estado +")";            
           //  javax.swing.JOptionPane.showMessageDialog(null,sql);
                  int h=estx.executeUpdate(sql);
                 if(h==1){
                     b=true;
                      p.id0=ultimoPedido1(conx);
                      upListaReq(lr,p.id0);
                      if (registrarLISTAPEDIDO1(lr,conx)){
                         //
                      }
                 }else{
                     b=false;
                     }
                 conx.commit();conx.setAutoCommit(true);//
             conx.close();estx.close();
        }catch(Exception e){
            conx.rollback(); // rollback...
         }finally{    
              if (conx!=null){conx.close();estx.close();}  
          }
      return b;
 }

Ese código no muestra cuando

Ese código no muestra cuando diriges a tu usuario a la página de login, así que debe de estar en otro lado.

Más aún este método confirma que al momento de salva todo sale bien ( por lo que se insertar el primer registro) pero "luego" ( en algún otro lugar de tu aplicación ) "algo" sale mal y mandas al usuario a la pantalla de login donde después de firmarse vuelve a insertar el registro porque no sabe que ya fue insertado ( ahí está el "duplicado").

En resumen, tienes registros duplicados porque tu usuario los está insertando dos veces! No es culpa del usuario es responsabilidad de tu aplicación hacer que le quede claro.

Observaciones extra: es muy peligroso que concatenes strings que vienen del usuario en tu código SQL. Busca en internet: SQL Injection. Básicamente alguién podría o borrarte la base de datos o modificar los valores en la tabla pedidos de forma arbitraria.

También investiga como usar un connection pool.

Imagen de ezamudio

inyección de SQL

No te vayas tan lejos, hace mucho tiempo que puse un ejemplo muy claro aquí mismo.

Imagen de tav

gracias por el aporte... pero me faltaba comentar...

que tal Oscar... gracias nuevamente por la retroalimentacion... pondre atencion a la observacion... pero tengo que comentar algo con respecto al codigo que publique...; quedamos en que el usuario luego de dar registrar pedido el sistema lo saca pero no le muestra el mensage de registro exitoso..., solo lo manda al login.jsp..., resulta que cuando el usuario vuelve a entrar al sistema..., y si escoge a un cliente que ya tiene pedido ese dia, el sistema le notifica del caso, pero el usuario reporta que no recibe la notificacion o aviso..., lo que quiere decir que que el pedido no se registro...
Es por eso que creo que el usuario no registra doble...; tambien debo recalcar que no les pasa a todos los usuarios..., es a uno o max. dos de vez en cuando...; conexiones a db no es pues estan debidamente gestionadas... y trato de usarlas poco aprovechando el data in memory asi he evitado usar la estrategia del pool(a modo de prueba..)..
Quisiera saber si el manejo de transacciones en el codigo esta bien o falta algo...

Imagen de tav

gracias por el aporte...

Atento al sendero... d)

Imagen de beto.bateria

Sucesion de ordenes:

Saludos:

Tienes algo asi:

Connection conx=null;
Statement estx=null;

Segun yo el Statement funciona basandose en Connection, entonces al cerrar los recursos deberia ser algo asi:

conx.commit();
conx.setAutoCommit(true);
estx.close();
conx.close();

Como lo estas manejando existe la posibilidad de que cierres la conexion, pero haya un problema al cerrar el Statement, y como ya se cerro la Connection, ¿como va a hacer el rollback?, ¿porque ejecutas conx.setAutoCommit(true);?

Otra cosa, si estas creando una instancia de la clase que contiene este metodo desde el JSP no le veo caso que pongas synchronized al metodo y si estas manejando metodos static hay que tener mucho cuidado. Tambien podrias regresar un int para que manejaras los estados del valor boolean mas si hubo error o rollback, o sea, definir y manejar mejor tu error.

Personalmente creo que este error es mas de como estas implementando todo, sobre todo al cerrar la sesion y mandar el login.

Independientemente de eso, es una lata manejar conexiones via movil por la alta latencia que puede existir.

Imagen de ezamudio

try-with-resources

Por qué no se quitan de broncas y usan el try-with-resources de Java 7.

Imagen de tav

Gracias por el aporte...

Ok... modificare el orden...
Ejecuto el conx.setAutoCommit(true)..., creo entender que es para dejar a la tabla en su estado normal de bloqueo natural(caracteristica del mysql), porque de lo contrario la dejo sin bloqueo y podria la concurrencia bloquear o dejar inconsistente al sistema...
Si estoy instanciando una clase q contiene ese metodo y lo sincronizo por la concurrencia que tiene este metodo en la realidad, lo que me evita que la tabla detalle de pedidos me quede fragmentada y las busquedas se hagan mas consistentes...
Hice pruebas de ingreso al tiempo con varios usuarios sin los parametros que uso actualmente y a nivel de un solo usuario pues todo ok pero todo salia mal en concurrencia real(varios usuarios al tiempo)...
LLegue a los paramettros actuales gracias a comentarios como los de ezamudio entre otros aqui por javamexico. Gracias beto...

Imagen de tav

try-with-resources

Y en rollback en el catch... para efectos de devolver la transac por si ocurre algo... queda alli mismo??.., meto todo dentro del try?? o solo la conexion y estament a la db??? Gracias

Imagen de ezamudio

TransactionTemplate

O te puedes quitar un montón de broncas si usas la TransactionTemplate de Spring. Porque en ese código ni siquiera estás definiendo una transacción.

Imagen de beto.bateria

ahi esta bien, por lo que leo

ahi esta bien, por lo que leo necesitas estudiar como trabaja JDBC y Tomcat, y volver a replantear la solucion, acuerdate de que debes de mantener tu solucion lo mas sencilla que se pueda, hasta donde me acuerdo nunca utilice setAutoCommit, y las aplicaciones que he hecho han funcionado bien, y como dice ezamudio, ¿en donde esta la transaccion?

Imagen de tav

Gracias por los aportes

...Post/Redirect/Get... fue la solucion q aplique para el reenvio del post....A cerca de lo de la transaccion.. utilizo las capacidades jdbc para que me haga el manejo d transac...,

Gracias por los aportes...

"Esta seguro de que quiere

"Esta seguro de que quiere reenviar la información"? Usuario: Si
Ahora tienes registros "duplicados"