MyCat1
END &&
DELIMITER ;
备注:这里的存储过程比较简单,就是根据一个表的 ID,返回一个表的另外一个字段,本例中 a_goods_id 为出参。
2、mybatis 映射文件
================
<![CDATA[
/!mycat:sql=select 1 from es_goods_community where seller_id=26/{call test_proc(
#{id,mode=IN,jdbcType=INTEGER},
@goodsId
)};select @goodsId;
]]>
</select>
这里的关键:statementType="CALLABLE"不需要加上,而是把存储过程当成一条普通的 SQL 语句,发送给 mycat 执行,mycat 根据注解路由到具体的后端节点,然后执行之,并返回结果,还需要在后面使用 sel
elect 语句返回 OUT 参数。在 call 语句中,出参用 @加变量名定义,名字与 select 语句中的名字保持一样即可。
为什么要这样写呢?原因如下:
mycat 已经声明,存储过程的调用通过注解来支持(主要原因,调用存储过程的语句无法定位路由信息),如果 statementType="CALLABLE",mysql 客户端(本例指 mysql 驱动包)会把语句当存储过程来看到,势必需要知道存储过程的元数据(出参列表)。故在 mybatis 文件中,call 语句之前需要待上注解,但这和 mycat 驱动包处理存储过程的代码产生了矛盾,如下代码:
public CallableStatement(MySQLConnection conn, String sql, String catalog,
boolean isFunctionCall) throws SQLException {
super(conn, sql, catalog);
this.callingStoredFunction = isFunctionCall;
if (!this.callingStoredFunction) {
if (!StringUtils.startsWithIgnoreCaseAndWs(sql, "CALL")) { // @1
// not really a stored procedure call
fakeParameterTypes(false); //@2
} else {
determineParameterTypes(); //@3
}
generateParameterMap();
} else {
determineParameterTypes();
generateParameterMap();
this.parameterCount += 1;
}
this.retrieveGeneratedKeys = true; // not provided for in the JDBC spec
}
代码来源与 mysql-connector-java-5.1.30.jar 中 CallableStatement,现在做个简单的解读:
代码 @1,判断 SQL 语句是否以 CALL 语句开头,如果不是,则调用代码 @2fakeParameterTypes 方法, 我可以很负责任人的
告诉你,该方法只是固定返回一个参数列表,完全与调用的存储过程的出参列表不匹配
代码 @3,调用后端连接,得到存储过程的源信息:发送的语句为:? ? ? ? ? ? ? ? ?
SELECT?name,?type,?comment?FROM?mysql.proc?WHERE?name?like?'存储过程名'?and?db?<=>?'数据库
名'?ORDER?BY?name,?type;
但 mycat 的处理如下:io.mycat.server.ServerConnection?的 public?void?execute(String?sql,?int?type)?方法:
跟进 MysqlProcHandler.handle 方法得知,mycat 只是返回空数据给前端连接,并没有去后端执行该语句。所以,mybatis 配置文件的 statementType 不能陪在为 CALLABLE 的原因。
3、DAO 与控制层的代码就在这里省略。
===================
评论