jpa 使用 StoredProcedureQuery的execute方法永远返回false

事件的起因

事源是这样的,由于jpa没有更新单一字段的方法,只能够手写sql语句来进行更新,既然如此为何不写在数据库中的存储过程里面呢?

于是就写了一个存储过程。

CREATE DEFINER=`root`@`localhost` PROCEDURE `p1_delete_article`(IN `a_id` int)
BEGIN
	UPDATE tb_article 
	SET is_delete=1 
	WHERE article_id = a_id;
END

接下来使用jpa来调用存储过程。

//data object
@NamedStoredProcedureQueries({
        @NamedStoredProcedureQuery(name = "deleteArticle",procedureName = "p1_delete_article",
        parameters = {@StoredProcedureParameter(name = "articleId",mode = ParameterMode.IN,type = Integer.class)})
})
@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "tb_article")
@EntityListeners(AuditingEntityListener.class)
public class Article {
	...
}
//service层
	@PersistenceContext
    private EntityManager em;

    @Override
    public Boolean deleteArticle(Integer id){
        StoredProcedureQuery query = em.createNamedStoredProcedureQuery("deleteArticle")
                                       .setParameter("articleId",id);
        return query.execute();
    }

然后前端调用这个接口无论如何都返回False!
后台能够执行存储过程,并可以更改到数据库中的数据

分析错误

查找源码,发现调用的是ProcedureCallImpl里面的execute方法:

	@Override
	public boolean execute() {
		try {
			final Output rtn = outputs().getCurrent();
			return rtn != null && ResultSetOutput.class.isInstance( rtn );
		}
		catch (NoMoreReturnsException e) {
			return false;
		}
		catch (HibernateException he) {
			throw getExceptionConverter().convert( he );
		}
		catch (RuntimeException e) {
			getProducer().markForRollbackOnly();
			throw e;
		}
	}

查找ProcedureCallImpl实现的接口StoreProcedureQuery来看看解释:

    /**
     * Return true if the first result corresponds to a result set,
     * and false if it is an update count or if there are no results
     * other than through INOUT and OUT parameters, if any.
     * @return  true if first result corresponds to result set
     * @throws QueryTimeoutException if the query execution exceeds
     *         the query timeout value set and only the statement is
     *         rolled back
     * @throws PersistenceException if the query execution exceeds 
     *         the query timeout value set and the transaction 
     *         is rolled back 
     */
    boolean execute();

只有返回的第一个结果是resultSet的话,就return true。如果返回的是update count(应该是update影响的行数)或者没有其他结果除了通过INOUT和OUT参数得到的话,就return false。

因为我调用的存储过程是update,所以一直return false 了。

测试正确方法使用execute方法

测试一下return true的情况:
ResultSet是数据中查询结果返回的一种对象,可以说结果集是一个存储查询结果的对象,但是结果集并不仅仅具有存储的功能,他同时还具有操纵数据的功能,可能完成对数据的更新等。
因此编写一个新的存储过程:

CREATE DEFINER=`root`@`localhost` PROCEDURE `p_test`()
BEGIN
	#Routine body goes here...
	SELECT * FROM tb_article;
END

jpa调用这个存储过程:

//实体类
@NamedStoredProcedureQuery(name = "findAll",procedureName = "p_test",
        resultClasses = {Article.class}
//调用这个存储过程
    @Override
    public Boolean deleteArticle(Integer id){
        StoredProcedureQuery query = em.createNamedStoredProcedureQuery("findAll");
        return query.execute();
    }

这时候在前端可以获得结果为true:
新调用execute的结果


版权声明:本文为weixin_41006725原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。