因为要对接项目的mysql数据库,部分语句要使用到mysql的存储过程,保证调用的一致性。
在网上查找了好多种方式,都很复杂,而且我试验了好多种,都没有成功。最后使用了
EntityManager的createNamedStoredProcedureQuery调用,成功执行mysql的存储过程。
现将方式记录,以便后面查阅。
1.mysql的存储过程很复杂,主要是用户注册,需要向两个表中插入数据
CREATE DEFINER=`demodb`@`%` PROCEDURE `user_register`(
in_password VARCHAR(50),
in_device_os VARCHAR(20),
in_device_os_version VARCHAR(30),
in_device_support_tele INT,
in_device_manufactory VARCHAR(40),
in_device_model VARCHAR(30),
in_app_mobile_version VARCHAR(20),
in_gmail VARCHAR(30),
in_verified TINYINT,
in_cc VARCHAR(20),
in_account VARCHAR(128),
in_mn VARCHAR(20),
OUT ret_passwd VARCHAR(50),
OUT ret_userid VARCHAR(30),
OUT ret_flag INT)
BEGIN
DECLARE var_get_userid VARCHAR(30);
DECLARE start_pos INT;
DECLARE var_mn VARCHAR(30);
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
SET ret_flag=-1;
ROLLBACK;
END;
START TRANSACTION;
SET @dt = NOW();
SET @dtunix=UNIX_TIMESTAMP(@dt);
SET @sid = REPLACE(UUID(),'-','');
SET start_pos=CEIL(RAND()*1000);
SELECT id INTO var_get_userid
FROM useridtable
LIMIT start_pos,1;
DELETE FROM useridtable
WHERE id=var_get_userid;
IF in_mn='' THEN
SET var_mn=CONCAT('+',in_cc,var_get_userid);
ELSE
SET var_mn = in_mn;
END IF;
IF ROW_COUNT()=1 THEN
INSERT INTO friends(
NAME,
username,
secret,
context,
accountcode)
VALUES( var_get_userid,
NULL,
in_password,
'ppcall-intercom',
var_get_userid);
INSERT INTO UserTable(NAME,
reg_date,
truemail,
truemobile,
true_mobile_country_code,
device_os,
device_os_version,
device_support_tele,
device_manufactory,
device_model,
app_mobile_version,
register_time,
verified,
capability,
account )
VALUES( var_get_userid,
@dt,
in_gmail,
var_mn,
in_cc,
in_device_os,
in_device_os_version ,
in_device_support_tele ,
in_device_manufactory ,
in_device_model,
in_app_mobile_version ,
@dt,
in_verified,
in_account);
SET ret_passwd=in_password;
SET ret_userid=var_get_userid;
SET ret_flag=1;
ELSE
SET ret_flag=-2;
END IF;
COMMIT;
END
2.代码调用首先要声明一个Entity,注明存储过程的名称和对应的输入参数和输出参数
代码如下:
package com.example.demo.entity;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import javax.persistence.*;
import java.io.Serializable;
@Entity
@NamedStoredProcedureQuery(
name = "user_register", //存储过程名称,可以自己命名,但一般和mysql的存储过程保持一致
procedureName = "user_register", //mysql中定义的存储过程名称,这个必须和mysql数据库中的保持一致
//声明存储过程的输入和输出参数,ParameterMode.IN 对应输入参数,ParameterMode.OUT 对应输出参数
// name必须和mysql存储过程语句的输入参数保持一样,名字不能错误,type为参数的对应的类型
parameters = {
@StoredProcedureParameter(mode = ParameterMode.IN, name = "in_password", type = String.class),
@StoredProcedureParameter(mode = ParameterMode.IN, name = "in_device_os", type = String.class),
@StoredProcedureParameter(mode = ParameterMode.IN, name = "in_device_os_version", type = String.class),
@StoredProcedureParameter(mode = ParameterMode.IN, name = "in_device_support_tele", type = Integer.class),
@StoredProcedureParameter(mode = ParameterMode.IN, name = "in_device_manufactory", type = String.class),
@StoredProcedureParameter(mode = ParameterMode.IN, name = "in_device_model", type = String.class),
@StoredProcedureParameter(mode = ParameterMode.IN, name = "in_app_mobile_version", type = String.class),
@StoredProcedureParameter(mode = ParameterMode.IN, name = "in_gmail", type = String.class),
@StoredProcedureParameter(mode = ParameterMode.IN, name = "in_verified", type = Integer.class),
@StoredProcedureParameter(mode = ParameterMode.IN, name = "in_cc", type = String.class),
@StoredProcedureParameter(mode = ParameterMode.IN, name = "in_account", type = String.class),
@StoredProcedureParameter(mode = ParameterMode.IN, name = "in_mn", type = String.class),
@StoredProcedureParameter(mode = ParameterMode.OUT, name = "ret_passwd", type = String.class),
@StoredProcedureParameter(mode = ParameterMode.OUT, name = "ret_userid", type = String.class),
@StoredProcedureParameter(mode = ParameterMode.OUT, name = "ret_flag", type = Integer.class)
}
)
public class Regist {
//必要要有这个id声明,否则执行会出错,无法是否这个id有用。
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
}
注意:网上有些示例,有说要@Table的注解,用这种方式调用,其实不用的@Table注解。
而且这Entity自己随便命名,只要声明的@NamedStoredProcedureQuery存储过程这mysql保持一致就行。另外创建的class Regist必须要有一个id,并且注解是@Id和@GeneratedValue(strategy = GenerationType.IDENTITY),否则执行会出错。
3.创建好Entity后,就可以调用语句了。
package com.example.demo;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.StoredProcedureQuery;
@RestController
public class demoController {
@RequestMapping("/regist")
public boolean regist(HttpServletRequest request, HttpServletResponse res) {
Map params = Util.getRequestParams(request);
String account = params.get("account");
String password = params.get("password");
//执行存储过程
StoredProcedureQuery query = entityManager.createNamedStoredProcedureQuery("user_register");
//设置存储过程输入参数值
query.setParameter("in_password",pwd);
query.setParameter("in_device_os","");
query.setParameter("in_device_os_version","");
query.setParameter("in_device_support_tele",0);
query.setParameter("in_device_manufactory","");
query.setParameter("in_device_model","");
query.setParameter("in_app_mobile_version","");
query.setParameter("in_gmail","");
query.setParameter("in_verified",4);
query.setParameter("in_cc","");
query.setParameter("in_account",account);
query.setParameter("in_mn","");
query.execute();
//获取输出参数值
String passwd =(String) query.getOutputParameterValue("ret_passwd");
String userid =(String) query.getOutputParameterValue("ret_userid");
int flag=(int) query.getOutputParameterValue("ret_flag");
return true;
}
}
只要上面的步骤就可以执行mysql的存储过程,并获取多个返回值。