一個jdbc與儲存過程呼叫之間的資料對映問題
阿新 • • 發佈:2018-11-19
背景
一個功能,管理員直接新增使用者賬號,儲存過程如下【postgresql資料庫】:
-- 儲存過程 管理員直接新增會員賬號 CREATE OR REPLACE FUNCTION "sp_account_member_reg_by_admin"( para_name character varying(45), para_email character varying(255), para_mobile character(11), para_avatar character varying(400), para_longitude numeric(10,6), para_latitude numeric(10,6), para_region_id integer, para_address character varying(100), para_member_status smallint, out record_json varchar ) RETURNS varchar AS $BODY$ declare tmpId integer; declare tmpId_str varchar; declare opResult sys_type_operation_outline; declare logic_allow boolean; declare c_v_name character varying(45); declare c_v_email character varying(255); declare c_v_mobile character(11); declare c_v_avatar character varying(400); declare c_v_regist_time timestamp(6) without time zone; declare c_v_longitude numeric(10,6); declare c_v_latitude numeric(10,6); declare c_v_region_id integer; declare c_v_address character varying(100); declare c_v_member_status smallint; declare c_v_data_completed boolean; declare no_mobile boolean; declare no_email boolean; begin opResult.state:=false; opResult."stateCode":=0; opResult.message:=''; -- 正式的引數賦值 c_v_name:=para_name; c_v_email:=para_email; c_v_mobile:=para_mobile; c_v_avatar:=para_avatar; c_v_regist_time:= now(); c_v_longitude:=para_longitude; c_v_latitude:=para_latitude; c_v_region_id:=para_region_id; c_v_address:=para_address; c_v_member_status:=para_member_status; c_v_data_completed:=false; if para_avatar is not null and char_length(para_avatar)>0 then c_v_data_completed:=true; end if; no_mobile:=false; no_email:=false; if c_v_mobile is null or char_length(c_v_mobile) <1 then no_mobile:=true; else perform id from member where "mobile"=c_v_mobile limit 1; if found then opResult.message:=config('errors','mobile_exist','message'); opResult."stateCode":=config('errors','mobile_exist','code'); opResult."state":=false; select row_to_json(t) into record_json from ( select opResult.state,opResult."stateCode",opResult.message,'' as data ) t; return; end if; end if; if c_v_email is null or char_length (c_v_email) < 1 then no_email:=true; else perform id from member where "email"=c_v_email limit 1; if found then opResult.message:=config('errors','email_exist','message'); opResult."stateCode":=config('errors','email_exist','code'); opResult."state":=false; select row_to_json(t) into record_json from ( select opResult.state,opResult."stateCode",opResult.message ) t; return; end if; end if ; if no_mobile=true and no_email=true then opResult.message:='手機號碼或者郵箱地址不能同時為空!'; opResult."stateCode":=-1; opResult."state":=false; select row_to_json(t) into record_json from ( select opResult.state,opResult."stateCode",opResult.message ) t; return; end if; INSERT INTO "member"( -- 主鍵不插入記錄。 "name" , "email" , "mobile" , "avatar" , "regist_time" , "longitude" , "latitude" , "region_id" , "address" , "member_status" , "data_completed" ) VALUES ( c_v_name , c_v_email , c_v_mobile , c_v_avatar , c_v_regist_time , c_v_longitude , c_v_latitude , c_v_region_id , c_v_address , c_v_member_status , c_v_data_completed ); if FOUND then opResult.message:='您已經成功建立了一個會員賬號'; opResult."stateCode":=0; opResult."state":=true; else opResult.message:='會員賬號建立失敗!'; opResult."stateCode":=-1; opResult."state":=false; end if; if opResult.state=true then select row_to_json(t) into record_json from ( select opResult.state,opResult."stateCode",opResult.message,currval(pg_get_serial_sequence('member', 'id')) as data ) t; else select row_to_json(t) into record_json from ( select opResult.state,opResult."stateCode",opResult.message ) t; end if; return; end; $BODY$ LANGUAGE plpgsql volatile;
請留意引數:
然後,jdbc下面的呼叫為:
/*** * 管理員直接添會員賬號 ***/ public OpResult RegByAdmin(MemberRegByAdmin model) { int totalParaCount=9+1 ;//--儲存過程引數總個數。 String procName="sp_account_member_reg_by_admin"; final HashMap<String,Integer> map_out_paras=new HashMap<>(); int theParamIndex=0; OpResult opResult=new OpResult(); StringBuilder paraStr=new StringBuilder(); String callable_para_str=""; for(int i=0;i<totalParaCount;i++){ paraStr.append('?'); paraStr.append(','); } if(totalParaCount>0){ paraStr.append(','); callable_para_str=(paraStr.toString().replaceFirst(",,","")); } final String sql="{ call \""+procName+"\"("+callable_para_str+")}"; CallableStatementCreator stCreator=new CallableStatementCreator() { @Override public CallableStatement createCallableStatement(Connection con) throws SQLException { CallableStatement st=con.prepareCall(sql); int paraIndex=0; paraIndex++; st.setString(paraIndex,model.name); paraIndex++; st.setString(paraIndex,model.email); paraIndex++; st.setString(paraIndex,model.mobile); paraIndex++; st.setString(paraIndex,model.avatar); paraIndex++; st.setDouble(paraIndex,model.longitude); paraIndex++; st.setDouble(paraIndex,model.latitude); paraIndex++; st.setInt(paraIndex,model.region_id); paraIndex++; st.setString(paraIndex,model.address); paraIndex++; st.setShort(paraIndex,model.member_status); paraIndex++;st.registerOutParameter(paraIndex, Types.VARCHAR);map_out_paras.put("op_result",paraIndex); return st; } }; CallableStatementCallback<OpResult> stCallback=new CallableStatementCallback<OpResult>(){ @Override public OpResult doInCallableStatement(CallableStatement cs) throws SQLException, DataAccessException { OpResult op_result=new OpResult(); cs.execute(); ResultSet rs=(ResultSet)cs.getResultSet(); String json_op_result=cs.getString(map_out_paras.get("op_result")); op_result= JSONObject.parseObject(json_op_result,OpResult.class); if(rs!=null){ rs.close(); } cs.getConnection().setAutoCommit(true); return op_result; } }; opResult=jdbcTemplate.execute(stCreator,stCallback); return opResult; }
用到的模型為:
public class MemberRegByAdmin { public MemberRegByAdmin(){ this.setNULL(); } public String name=""; public void setName(String name){ this.name=name; } public String getName(){ return this.name; } public String email=""; public void setEmail(String email){ this.email=email; } public String getEmail(){ return this.email; } public String mobile=""; public void setMobile(String mobile){ this.mobile=mobile; } public String getMobile(){ return this.mobile; } public String avatar=""; public void setAvatar(String avatar){ this.avatar=avatar; } public String getAvatar(){ return this.avatar; } public Double longitude=0.0; public void setLongitude(Double longitude){ this.longitude=longitude; } public Double getLongitude(){ return this.longitude; } public Double latitude=0.0; public void setLatitude(Double latitude){ this.latitude=latitude; } public Double getLatitude(){ return this.latitude; } public Integer region_id=0; public void setRegion_id(Integer region_id){ this.region_id=region_id; } public Integer getRegion_id(){ return this.region_id; } public String address=""; public void setAddress(String address){ this.address=address; } public String getAddress(){ return this.address; } public Short member_status=0; public void setMember_status(Short member_status){ this.member_status=member_status; } public Short getMember_status(){ return this.member_status; } public void setNULL(){ this.name=null; this.email=null; this.mobile=null; this.avatar=null; this.longitude=null; this.latitude=null; this.region_id=null; this.address=null; this.member_status=null; } public void resetDefaultVal(){ this.name=""; this.email=""; this.mobile=""; this.avatar=""; this.longitude=0.0; this.latitude=0.0; this.region_id=0; this.address=""; this.member_status=0; } }
測試程式碼為:
@Test
public void testMemberRegByAdmin(){
MemberRegByAdmin model=new MemberRegByAdmin();
model.resetDefaultVal();
model.setName("dfdfdf");
model.setMobile("");
model.setEmail("");
OpResult opResult=memberBiz.RegByAdmin(model);
System.out.println(JSONObject.toJSONString(opResult));
}
測試結果為:
Caused by: org.postgresql.util.PSQLException: ERROR: function
sp_account_member_reg_by_admin(character varying, character varying, character varying, character varying, double precision, double precision, integer, character varying, smallint) does not exist
建議:No function matches the given name and argument types. You might need to add explicit type casts.
位置:15
注意到:
兩個座標的資料型別
與:
方法定義裡面的引數不一樣,所以,java中的double與numeric是不一樣的,
只有一種解決方案,就是直接指定引數型別:
然後你會發現:
done.