2

Llevo todo el día de ayer intentando insertar los datos que recibo por el scanner a la base de datos y me da error, no encuentro la solución por ningún lado.

Me sale este mensaje de error:

Exception in thread "main" com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '?,?,?,?)' at line 1 at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) at java.lang.reflect.Constructor.newInstance(Constructor.java:423) at com.mysql.jdbc.Util.handleNewInstance(Util.java:411) at com.mysql.jdbc.Util.getInstance(Util.java:386) at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1053) at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4120) at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4052) at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2503) at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2664) at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2788) at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2738) at com.mysql.jdbc.StatementImpl.execute(StatementImpl.java:899) at com.mysql.jdbc.StatementImpl.execute(StatementImpl.java:737) at inventario.SwitchInt.RegistrarProducto(SwitchInt.java:59) at inventario.Inventario.main(Inventario.java:31)

He cambiado la sintaxis mas de 20 veces literalmente, pero no lo consigo. En clase estamos acostumbrado hacerlo con postgre y es diferente, he buscado la sintaxis de mysql y me ponían que era la que tengo puesta, pero no me va, os dejo abajo el código.

Clase Conexion

public class Conexion {

Connection conexion = null;
Statement comando = null;
ResultSet registro;

public Connection MySQLConnect() {

    try {
        Class.forName("com.mysql.jdbc.Driver");
        String servidor = "jdbc:mysql://localhost:3306/inventario";
        String usuario = "root";
        String pass = "";
        conexion = DriverManager.getConnection(servidor, usuario, pass);

    } catch (ClassNotFoundException ex) {
        JOptionPane.showMessageDialog(null, ex, "Error en la conexión a la base de datos: " + ex.getMessage(), JOptionPane.ERROR_MESSAGE);
        conexion = null;
    } catch (SQLException ex) {
        JOptionPane.showMessageDialog(null, ex, "Error en la conexión a la base de datos: " + ex.getMessage(), JOptionPane.ERROR_MESSAGE);
        conexion = null;
    } catch (Exception ex) {
        JOptionPane.showMessageDialog(null, ex, "Error en la conexión a la base de datos: " + ex.getMessage(), JOptionPane.ERROR_MESSAGE);
        conexion = null;
    } finally {
        JOptionPane.showMessageDialog(null, "Conexion establecida correctamente.");
        return conexion;
    }
}

PreparedStatement prepareStatement(String insert_into_usuarioNombreApellidosEdadCor) {
    throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
}

Aquí tengo el error, en esta clase.

public class SwitchInt {

**Conexion db = new Conexion();
Connection cn = db.MySQLConnect();**


static String nombre;
static double precio;
static int opcion, stock, codigo;
Producto p;
Vector<Producto> productos = new Vector<Producto>();

public void Intro() {
    System.out.print("\nElija un número:\n 1. Registrar producto\n 2. Vender producto\n 3. Buscar producto\n 4. Calcular precio medio\n 5. Salir \n\n ");
}

public void RegistrarProducto() throws SQLException {
    System.out.print("\n Ingrese un código del producto: \n");
    codigo = entrada.nextInt();
    System.out.print("Nombre: ");
    nombre = entrada.next();
    System.out.print("Precio: ");
    precio = entrada.nextDouble();
    System.out.print("Stock: ");
    stock = entrada.nextInt();
    p = busqueda(codigo, productos);

    if (p == null) {
        productos.addElement(new Producto(codigo, nombre, precio, stock));

        **String sql = "INSERT INTO productos (ID, Nombre, Precio, Stock) VALUES(?,?,?,?)";

        PreparedStatement pst;
        pst = cn.prepareStatement(sql);
        pst.setInt(1, codigo);
        pst.setString(2, nombre);
        pst.setDouble(3, precio);
        pst.setInt(4, stock);
        pst.execute(sql);**

        System.out.print("Producto agregado\n");
    } else {
        System.out.print("ya existe este producto");
    }
}

Agradezco una pequeña ayuda, gracias.

Pablo Simon DiEstefano
  • 3,151
  • 1
  • 16
  • 40
Manuee
  • 41
  • 10
  • Has probado la consulta SQL directamente contra la base de datos? Te devuelve el mismo error? – rencinas Mar 21 '18 at 12:11
  • Si, directamente en la base de datos si me coge la consulta, pero claro, nunca he probado el VALUES(?,?,?,?), no se si tengo algún error de código o algo – Manuee Mar 21 '18 at 12:18
  • Has probado a: `INSERT INTO productos (ID, Nombre, Precio, Stock) VALUES(" + String.valueOf(codigo) + "," + nombre + ", " + String.valueOf(precio) + "," + String.valueOf(stock) + ")"` – rencinas Mar 21 '18 at 12:20
  • @rencinas Me da este error: Exception in thread "main" java.sql.SQLException: Parameter index out of range (1 > number of parameters, which is 0). Busqué en google y me ponía que cambiara de controlador jdbc, que podría ser eso, lo he cambiado y sigue igual. – Manuee Mar 21 '18 at 12:34
  • 1
    @rencinas no recomiendes eso. El uso de `?` es para evitar la Inyección de código, lo cual ocurre precisamente si se pasa la consulta como indicas. Es una mala práctica y muy peligroso ejecutar consultas concatenando valores externos. – A. Cedano Mar 21 '18 at 12:37
  • Manuee, **deja el código tal y como está, con los `?`**, ya que tu error está aquí: `pst.execute(sql);`, debes cambiarlo por esto : **`pst.executeUpdate();`** – A. Cedano Mar 21 '18 at 12:41
  • @A.Cedano Muchas gracias ! – Manuee Mar 21 '18 at 12:47

1 Answers1

5

Cuando se usan consultas preparadas, que es lo correcto en este caso1, el método que ejecuta la sentencia es executeUpdate, no execute.

executeUpdate

Ejecuta la instrucción SQL en este objeto PreparedStatement, que debe ser una declaración de SQL Data Manipulation Language (DML), como INSERT, UPDATE o DELETE; o una declaración SQL que no devuelve nada, como una instrucción DDL.

Además, la instrucción SQL ya fue pasada aquí: pst = cn.prepareStatement(sql);, luego sólo queda ejecutar, no hay que pasar de nuevo la variable sql en executeUpdate.

Si escribes tu código así, debería funcionar:

    String sql = "INSERT INTO productos (ID, Nombre, Precio, Stock) VALUES(?,?,?,?)";

    PreparedStatement pst;
    pst = cn.prepareStatement(sql);
    pst.setInt(1, codigo);
    pst.setString(2, nombre);
    pst.setDouble(3, precio);
    pst.setInt(4, stock);
    pst.executeUpdate();

Notas:

1 Cuando en una consulta intervienen datos externos hay que aplicar siempre el principio de consultas preparadas, de lo contrario nuestro código sería vulnerable a un grave riesgo de seguridad conocido como Inyección SQL, a través del cual un usuario mal intencionado podría tomar el control no solamente de nuestra base de datos, sino de todo el sistema operativo.

A. Cedano
  • 86,578
  • 19
  • 122
  • 221
  • ¡Muchas gracias! me funciono a la perfección sin ningún error, de verdad muchas gracias ! – Manuee Mar 21 '18 at 12:47
  • 1
    @Manuee, me alegro de que la respuesta te haya ayudado a resolver el problema. Por favor, cuando sea posible l◔_◔: **[¿Qué debo hacer cuando alguien contesta mi pregunta?](https://es.stackoverflow.com/help/someone-answers)** en el Centro de Ayuda. – A. Cedano Mar 21 '18 at 12:51