EntityManager创建本机查询与持久性和注入

时间:2014-02-08 00:45:59

标签: jpa ejb sql-injection entitymanager

createNativeQuery()如果在以下情况下使用,则可以安全地阻止SQL注入:

@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是一个存储函数,它执行INSERT并返回新插入用户的id。这是否相同:

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在两种情况下均由用户填写。最后是默认启动的交易吗?

编辑:例程:

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

1 个答案:

答案 0 :(得分:1)

这取决于r1_register实际上在做什么。如果它只是保存用户而不是其他任何东西,那么它们是等价的,因为那是EntityManager#persist正在做的事情。但是,如果DB函数正在执行某些安全检查或写入其他表,那么您需要在JPA中实现它。用于插入User和获取ID的顺便说一句代码应为

public User register(User u) {
    em.getTransaction().begin();
    em.persist(u);
    em.getTransaction().commit();
    int id = u.getId();
    return u;
}

但是,如果在调用EntityManager#flush方法后需要该id,则不必调用register,在每个事务结束时执行flush。