Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Prepared statement returns false but row is inserted? [duplicate]

So this is my table:

mysql> DESCRIBE app_user;
+----------+-------------+------+-----+---------+----------------+
| Field    | Type        | Null | Key | Default | Extra          |
+----------+-------------+------+-----+---------+----------------+
| id       | int(11)     | NO   | PRI | NULL    | auto_increment |
| username | varchar(40) | NO   | PRI | NULL    |                |
| password | varchar(40) | NO   |     | NULL    |                |
| email    | varchar(40) | NO   | PRI | NULL    |                |
+----------+-------------+------+-----+---------+----------------+
4 rows in set

mysql> 

What I am expecting is that, I should not be able to add 2 rows with same username because username is Primary Key..

And this is my Java Code:

@Test
public void shouldNotInsertWithSameUserName() throws IOException, SQLException {
    AppUserAccessObject appUserAccessObject = new AppUserAccessObject(new DatabaseConnectionImpl());
    Assert.assertFalse(appUserAccessObject.insertUser("koray", "email", "password"));
}

So this test passes, which means insertUser returns false.. However when I check the database, I see a new row insterted. What am I doing wrong? And the insertuser:

public boolean insertUser(String username,String email,String password) throws SQLException {
    PreparedStatement preparedStatement = connection.prepareStatement("INSERT INTO "+ tableName + "(username,email,password) VALUES(?,?,?)");
    preparedStatement.setString(1,username);
    preparedStatement.setString(2,email);
    preparedStatement.setString(3,password);
    boolean execute = preparedStatement.execute();
    return execute;
}
like image 1000
Koray Tugay Avatar asked Apr 15 '14 15:04

Koray Tugay


1 Answers

Your primary key is based on 3 fields:

  • id (which has auto increment value)
  • username
  • email

So, the primary key restricts a new row with these 3 fields having the same value. But since id is marked on auto increment and you're always sending null to it, it will generate a new value, thus never having these three fields with the same value.

A better design for your table would be having id as primary key only, and an Unique Key for your username and email fields. In fact, it would be even better having two unique keys: one for username and another for email.

This will do it:

CREATE TABLE app_user (
    id INT PRIMARY KEY AUTO_INCREMENT,
    username varchar(40),
    password varchar(40),
    email varchar(40),
    UNIQUE KEY (username),
    UNIQUE KEY (email)
);

Apart from the design problem in your database:

  • Use PreparedStatement#executeUpdate to execute DML statemens like INSERT, UPDATE and DELETE.
  • Use PreparedStatement#executeQuery when retrieving data from database through a SELECT.
  • Use PreparedStatement#execute when performing any kind of SQL statement like CREATE TABLE or ALTER TABLE.

Prepared statement returns false but row is inserted?

From PreparedStatement#execute javadoc:

Returns: true if the first result is a ResultSet object; false if the first result is an update count or there is no result.

In this case, you got a false result since you executed an update operation (INSERT is understood as an update operation).

like image 191
Luiggi Mendoza Avatar answered Nov 01 '22 00:11

Luiggi Mendoza