Is createNativeQuery()
safe against SQL injection if used as in:
@ManagedBean
@ViewScoped
public class UserController {
@PersistenceContext
private EntityManager em;
public User register(User u) {
Query query = em.createNativeQuery("SELECT r1_register(?,?,?,?,?,?,?)");
short i = 0;
query.setParameter(++i, u.getUsername());
query.setParameter(++i, u.getPassword());
query.setParameter(++i, u.getName());
query.setParameter(++i, u.getSurname());
query.setParameter(++i, u.getEmail());
query.setParameter(++i, u.getBirthdate());
query.setParameter(++i, u.getPhoneNumber());
int id = (int) query.getSingleResult();
if (id != 0) u.setIduser(id);
return u;
}
}
r1_register
is a stored function that performs an INSERT and returns the id of the newly inserted user. Would this be equivalent:
public User register(User u) {
em.persist(u);
// get the last inserted id (user id must be @Generated)
em.flush(); // user id set here
return u;
}
u
is in both cases filled by the user. Finally is a transaction initiated by default ?
EDIT: The routine:
CREATE DEFINER=`root`@`localhost` FUNCTION `r1_register`(username VARCHAR(45),
_password VARCHAR(45),
_name VARCHAR(45),
surname VARCHAR(45),
_email VARCHAR(45),
_birthdate DATE,
phone_number VARCHAR(10) ) RETURNS int(11)
BEGIN
-- Adds a new user.
-- START TRANSACTION; -- Begin a transaction -- NOT ALLOWED
-- http://stackoverflow.com/questions/16969875/
IF r1_check_unique_username(username)=0 THEN
RETURN 0;
END IF;
INSERT IGNORE INTO `hw1_db`.`users` (`username`, `password`, `name`, `surname`, `email`, `birthdate`, `phone_number`)
VALUES (username, _password, _name, surname, _email, _birthdate, phone_number);
-- see: http://stackoverflow.com/a/5939840/281545
-- The drawback to this approach is that you cannot go back and use
-- ids wasted because of failed attempts to INSERT IGNORE in the event
-- of a duplicate key. Shouldn't be a problem for us as we check.
-- /Transaction
-- IF ROW_COUNT() > 0 THEN
-- ROW_COUNT() returns the number of rows updated/inserted/deleted
-- COMMIT; -- Finalize the transaction
-- ELSE
-- ROLLBACK; -- Revert all changes made before the transaction began
-- END IF;
RETURN LAST_INSERT_ID();
END
This depends on what
r1_register
is actually doing. If it just saving the user and nothing else, than yes, they are equivalent because that's whatEntityManager#persist
is doing. But if the DB function is performing some security checking or writing to other tables, than you need to implement it in JPA too. Btw code for insertingUser
and obtaining the ID should beBut you don't have to call
EntityManager#flush
if you need that id after theregister
method is called, flush is performed by the end of every transaction.