在休眠

时间:2016-10-16 06:11:29

标签: java mysql hibernate stored-procedures

我有一个问题,关于在mysql和hibernate中使用存储过程的最佳方法是什么。我使用hibernate 4.0.0.Final 作为我的ORM工具运行mysql版本 5.7.14 。现在在mysql数据库中,我有一个存储过程定义如下:

DROP PROCEDURE IF EXISTS LK_spInsertBaseUser;
DELIMITER $$
CREATE PROCEDURE `LK_spInsertBaseUser`(f_name  VARCHAR(255),
                                       l_name  VARCHAR(255),
                                       n_name  VARCHAR(255),
                                       pwd     VARCHAR(255),
  OUT                                  user_id INT)
  BEGIN
    ## Declaring exit handler
    DECLARE EXIT HANDLER FOR SQLEXCEPTION
    BEGIN
      GET DIAGNOSTICS CONDITION 1
      @state = RETURNED_SQLSTATE,
      @errno = MYSQL_ERRNO,
      @message = MESSAGE_TEXT;
      SET @full_error = CONCAT('ERROR ', @errno, ' (', @state, '): ', @message);
      SELECT @full_error;
      ROLLBACK;
    END;

    START TRANSACTION;
    IF NOT EXISTS(SELECT first_name
                  FROM base_user
                  WHERE first_name = f_name AND last_name = l_name AND nick_name = n_name)
    THEN
      INSERT INTO base_user (first_name, last_name, nick_name, password)
      VALUES (f_name, l_name, n_name, pwd);
      SET user_id = LAST_INSERT_ID();
      SELECT @user_id AS userId;
    ELSE
      SET @exiting_user = CONCAT('Base user already exists');
      SELECT @exiting_user;
      ROLLBACK;
    END IF;
  END $$
DELIMITER ;

正如我们从上面的过程中看到的那样,如果插入有效,新记录的id将存储在OUT参数 user_id 中,我们也会进行选择。但是,如果出现错误,我会打印出错误。现在,这是问题的核心。尝试通过hibernate执行存储过程时遇到了一些小问题。我终于提出了一个解决方案,但我不相信这是正确的解决方案。让我来看看我经历过的各种尝试。

尝试1 : 我决定对我的BaseUser实体使用 @NamedNativeQueries 注释(注意:base_user sql表映射到BaseUser pojo实体)。以下是代码段:

@SqlResultSetMapping(name="insertUserResult", columns = { @ColumnResult(name = "userId")})
@NamedNativeQueries({
        @NamedNativeQuery(
                name = "spInsertBaseUser",
                query = "CALL LK_spInsertBaseUser(:firstName, :lastName, :nickName, :password, @user_id)",
                resultSetMapping = "insertUserResult"
        )
})

现在,在Dao类中,我创建了一个通过会话对象调用命名查询的方法,如下所示:

Query query = getSession().getNamedQuery("spInsertBaseUser")
        .setParameter("firstName", user.getFirstName())
        .setParameter("lastName", user.getLastName())
        .setParameter("nickName", user.getNickName())
        .setParameter("password", user.getEncodedPassword());
Object data = query.list();
System.out.println(data);

现在这部分工作了。它将数据插入数据库,但数据对象为空。似乎没有设置甚至检索out参数。然后我决定使用不同的方法并使用CallableStatement对象。以下是代码:

尝试2:

getSession().doWork((Connection connection) -> {
    CallableStatement statement = connection.prepareCall("{call LK_spInsertBaseUser(?, ? , ?, ?, ?)}");
    statement.setString(1, user.getFirstName());
    statement.setString(2, user.getLastName());
    statement.setString(3, user.getNickName());
    statement.setString(4, user.getEncodedPassword());
    statement.registerOutParameter(5, Types.INTEGER);
    statement.executeUpdate();
    System.out.println(statement.getInt(5));
});

这是有效的,而且相当快,但我已经读过,prepareCall的实例化是昂贵的,所以我想真正的问题是,这个解决方案是可接受的标准还是我应该继续在任务中找出NamedNativeQuery方法 更好的效果

0 个答案:

没有答案