Mybatis调用数据库存储过程时,怎么根据数据库存储过程最新的参数,来动态调整call里面的参数。
现在是数据库存储过程里面入参和出参会随时修改,也会调整入参和出参顺序。现在数据库那里要求,后台Mybatis在调用存储过程,需要根据最新的参数和顺序动态调整。但前提是不能修改代码,不能重新发布。必须在调用数据库存储过程前,通过一个通用方法来获取存储过程最新的参数和顺序。然后将最新的参数和顺序传到mapper.xml文件中
这是之前的写法,通过字段名和数据库存储过程一一对应
call bsp_CommRole;8(
#{action,mode=IN,jdbcType=VARCHAR},
#{lan_id,mode=IN,jdbcType=INTEGER},
#{branch_id,mode=IN,jdbcType=VARCHAR},
#{column_title,mode=OUT,jdbcType=VARCHAR},
#{column_length,mode=OUT,jdbcType=VARCHAR},
#{column_align,mode=OUT,jdbcType=VARCHAR}
)
现在通过 [sys].[sp_procedure_params_100_managed] @procedure_name=N'存储过程名' 可以获取最新的参数字段及输入输出类型,但是需要将最新的参数动态传到call bsp_CommRole;8里面
现在在调用存储过程,里面参数名和mode不能直接写死,需要在接口调用的地方,先通过上面的sp_procedure_params_100_managed获取最新的参数,然后不管通过什么方法把最新的参数传到call里面。这样以后数据库修改存储过程后,后端不用跟着修改调用参数也能正常调用。
这个问题困扰了好几天,如能解决,感激不尽
小魔女参考了bing和GPT部分内容调写:
Mybatis调用数据库存储过程时,参数动态提交的方法有很多,下面介绍一种实现方式。
首先,在Mybatis中,可以使用标签,来实现动态提交参数。可以通过在mapper.xml文件中定义一个list集合,然后再使用标签来遍历list集合,将list集合里面的参数动态传入到call里面。
具体的实现步骤如下:
例如:
<select id="callProcedure" parameterType="map" statementType="CALLABLE">
{call bsp_CommRole(
<foreach collection="paramList" item="item" index="index" open="" separator="," close="">
#{item.paramName, mode = #{item.paramMode}, jdbcType = #{item.jdbcType}}
</foreach>)}
</select>
以上就是Mybatis调用数据库存储过程时,根据数据库存储过程最新的参数动态提交的一种实现方式。
回答不易,记得采纳呀。
该回答引用ChatGPT
如有疑问可以回复我
根据您的需求,需要在调用存储过程之前获取最新的参数字段及输入输出类型,并将其动态传递到MyBatis的mapper.xml文件中,以便调用存储过程。
这可以通过以下步骤实现:
1、创建一个Java类,该类使用JDBC连接到数据库并调用存储过程 [sys].[sp_procedure_params_100_managed],获取最新的参数字段及其输入输出类型。
2、在该Java类中,将获取到的参数信息动态构建为一个包含参数名、输入/输出类型和参数值的Map对象。可以使用HashMap或者其他类型的Map来存储参数信息。
3、将上述Map对象传递给MyBatis的mapper.xml文件。可以使用MyBatis提供的动态SQL语句构建工具,在mapper.xml文件中动态构建调用存储过程的SQL语句。例如,可以使用标签遍历Map对象中的参数,并动态构建存储过程的调用语句。
4、在Java代码中调用MyBatis mapper接口,将上述动态构建的SQL语句作为参数传递给MyBatis mapper方法,即可执行存储过程并获取结果。
下面是一个示例Java类,该类演示了如何使用JDBC连接到数据库并调用存储过程 [sys].[sp_procedure_params_100_managed],获取最新的参数字段及其输入输出类型,并将其动态构建为一个Map对象。
import java.sql.*;
import java.util.*;
public class ProcedureParamMapper {
private static final String URL = "jdbc:sqlserver://localhost:1433;databaseName=MyDatabase";
private static final String USERNAME = "myuser";
private static final String PASSWORD = "mypassword";
public Map<String, Object> getProcedureParams(String procedureName) throws SQLException {
Connection connection = DriverManager.getConnection(URL, USERNAME, PASSWORD);
Map<String, Object> paramInfo = new HashMap<>();
try {
CallableStatement statement = connection.prepareCall("{call [sys].[sp_procedure_params_100_managed](?)}");
statement.setString(1, procedureName);
ResultSet resultSet = statement.executeQuery();
while (resultSet.next()) {
String paramName = resultSet.getString("parameter_name");
int paramMode = resultSet.getInt("parameter_mode");
int dataType = resultSet.getInt("data_type");
String typeName = resultSet.getString("type_name");
paramInfo.put(paramName, getJdbcType(paramMode, dataType, typeName));
}
} finally {
connection.close();
}
return paramInfo;
}
private int getJdbcType(int paramMode, int dataType, String typeName) {
switch (paramMode) {
case 1: return Types.IN;
case 2: return Types.OUT;
case 3: return Types.INOUT;
default: return Types.NULL;
}
}
}
在MyBatis的mapper.xml文件中,可以使用标签遍历上述获取到的参数信息,并动态构建调用存储过程的SQL语句。例如:
<select id="callProcedure" statementType="CALLABLE">
{ call ${procedureName}(
<foreach collection="params" item="param" separator=",">
#{param.value, mode=IN, jdbcType=param.type}
</foreach>
) }
</select>
在上述示例中,使用标签遍历了params参数Map对象中的所有参数,并动态构建了存储过程的调用语句。其中,${procedureName}为调用存储过程的名称,#{param.value}为当前参数的值,mode和jdbcType属性分别指定了参数的输入/输出类型和JDBC类型。您可以根据实际需求调整这些参数。
最后,在Java代码中调用MyBatis mapper接口的callProcedure方法,将上述动态构建的SQL语句作为参数传递给该方法,即可执行存储过程并获取结果。例如:
SqlSession sqlSession = sqlSessionFactory.openSession();
try {
ProcedureParamMapper mapper = sqlSession.getMapper(ProcedureParamMapper.class);
Map<String, Object> params = mapper.getProcedureParams("bsp_CommRole");
Map<String, Object> inputParams = new HashMap<>();
inputParams.put("action", "someAction");
inputParams.put("lan_id", 1);
inputParams.put("branch_id", "someBranchId");
Map<String, Object> outputParams = new HashMap<>();
outputParams.put("column_title", null);
outputParams.put("column_length", null);
outputParams.put("column_align", null);
Map<String, Object> result = new HashMap<>();
result.putAll(inputParams);
result.putAll(outputParams);
sqlSession.selectOne("callProcedure", new HashMap<String, Object>() {{
put("procedureName", "bsp_CommRole");
put("params", result);
}});
System.out.println("output parameters: " + outputParams);
} finally {
sqlSession.close();
}
在上述示例中,首先调用ProcedureParamMapper的getProcedureParams方法获取存储过程的最新参数信息,并将输入参数和输出参数分别存储在inputParams和outputParams Map对象中。然后,将inputParams和outputParams合并为一个result Map对象,并将procedureName和result对象作为参数传递给callProcedure方法。最后,从outputParams Map对象中获取存储过程的输出参数结果。
参考GPT和自己的思路,根据您的描述,您需要动态调整Mybatis调用存储过程的参数,以适应存储过程参数的修改。下面提供一种基于Mybatis自定义TypeHandler的解决方案。
首先,您需要编写一个自定义的TypeHandler,用于将存储过程的参数和类型转换为Mybatis的参数类型和模式。以下是一个示例TypeHandler:
public class StoredProcedureTypeHandler extends BaseTypeHandler<List<StoredProcedureParam>> {
@Override
public void setNonNullParameter(PreparedStatement ps, int i, List<StoredProcedureParam> parameter, JdbcType jdbcType) throws SQLException {
StringBuilder sb = new StringBuilder();
sb.append("{call ").append(parameter.get(0).getName()).append("(");
for (int j = 1; j < parameter.size(); j++) {
sb.append("?,");
}
sb.deleteCharAt(sb.length() - 1).append(")}");
ps.setString(i, sb.toString());
}
@Override
public List<StoredProcedureParam> getNullableResult(ResultSet rs, String columnName) throws SQLException {
return parseStoredProcedureParams(rs.getString(columnName));
}
@Override
public List<StoredProcedureParam> getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
return parseStoredProcedureParams(rs.getString(columnIndex));
}
@Override
public List<StoredProcedureParam> getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
return parseStoredProcedureParams(cs.getString(columnIndex));
}
private List<StoredProcedureParam> parseStoredProcedureParams(String paramStr) {
// 解析存储过程参数
// ...
}
}
该TypeHandler将存储过程的名称和参数列表转换为Mybatis调用存储过程所需的字符串格式,并将其设置为PreparedStatement的参数。此外,它还将ResultSet返回的存储过程参数字符串转换为Java对象。您需要根据实际情况实现parseStoredProcedureParams方法。
接下来,您需要在Mybatis的配置文件中注册该TypeHandler:
<typeHandlers>
<typeHandler handler="com.example.StoredProcedureTypeHandler" javaType="java.util.List" jdbcType="VARCHAR"/>
</typeHandlers>
在Mapper XML文件中,您需要声明一个返回类型为List的select语句,用于查询存储过程的参数列表:
<select id="getStoredProcedureParams" resultType="java.util.List">
SELECT param_name, param_type, param_mode
FROM [sys].[sp_procedure_params_100_managed]
WHERE procedure_name = #{procedureName}
ORDER BY param_order;
</select>
最后,在Java代码中,您可以使用SqlSession的selectOne方法查询存储过程的参数列表,然后将其作为参数传递给Mybatis的调用存储过程方法。以下是一个示例:
SqlSession sqlSession = sqlSessionFactory.openSession();
try {
List<StoredProcedureParam> params = sqlSession.selectOne("com.example.MyMapper.getStoredProcedureParams", "存储过程名");
Map<String, Object> paramValues = new HashMap<>();
for (StoredProcedureParam param : params) {
if (param.getMode() == StoredProcedureParam.Mode.IN) {
paramValues.put(param.getName(), /* 从请求参数中获取对应的值 */);
} else {
paramValues.put(param.getName(), null);
// 输出参数需要预先设为 null,否则会抛出异常
}
}
sqlSession.selectOne("com.example.MyMapper.callStoredProcedure", new StoredProcedureCall("存储过程名", paramValues));
// 处理输出参数
for (StoredProcedureParam param : params) {
if (param.getMode() == StoredProcedureParam.Mode.OUT) {
System.out.println(param.getName() + ": " + paramValues.get(param.getName()));
}
}
} finally {
sqlSession.close();
}
其中,"com.example.MyMapper.getStoredProcedureParams" 和 "com.example.MyMapper.callStoredProcedure" 是两个 MyBatis 的 Mapper 方法,需要在对应的 Mapper XML 文件中定义它们的 SQL 查询和调用。其中,getStoredProcedureParams 方法返回指定存储过程的参数信息,callStoredProcedure 方法调用指定的存储过程。
在 getStoredProcedureParams 方法中,可以使用数据库的元数据功能获取指定存储过程的参数信息。例如,对于 Oracle 数据库,可以使用如下 SQL 查询:
SELECT
argument_name AS name,
data_type AS type,
IN_OUT AS mode
FROM
all_arguments
WHERE
object_name = #{procedureName}
ORDER BY
position;
这个查询会返回存储过程的参数信息,包括参数名、参数类型和参数模式(输入还是输出)等。可以使用 MyBatis 的 resultMap 和 resultType 等功能将这些信息映射为 Java 对象。
在 callStoredProcedure 方法中,可以使用 MyBatis 的 selectOne 或者 update 等方法来执行存储过程的调用。例如,对于 Oracle 数据库,可以使用如下语句调用存储过程:
BEGIN
存储过程名(:param1, :param2, ..., :paramN);
END;
其中,:param1, :param2, ..., :paramN 是存储过程的参数,需要和 getStoredProcedureParams 方法中查询到的参数名一一对应。这里使用了 BEGIN 和 END 来封装存储过程的调用,这是因为在 Oracle 中,存储过程调用必须在 BEGIN 和 END 中进行封装。
在调用存储过程后,可以从 paramValues 中获取输出参数的值,并进行相应的处理。需要注意的是,输出参数需要预先设为 null,否则会抛出异常。
看看这样能不能达到你的要求,仅供参考:
通用方法获取存储过程最新的参数和顺序:
public Map<String, String> getProcedureParams(String procedureName) {
Map<String, String> params = new HashMap<>();
// 调用存储过程获取最新参数信息,并将结果保存到params中
return params;
}
mapper.xml中的select语句:
<select id="getProcedureParams" resultType="java.util.HashMap">
SELECT PARAMETER_NAME AS paramName, DATA_TYPE AS jdbcType
FROM [sys].[sp_procedure_params_100_managed]
WHERE PROCEDURE_NAME = #{procedureName}
</select>
mapper.xml中的动态SQL:
<sql id="procedureParams">
<foreach collection="params" item="value" separator=",">
#{value, mode=IN, jdbcType=${paramMap[value]}}
</foreach>
</sql>
mapper接口中的方法:
public void callProcedure() {
// 调用select语句获取存储过程最新的参数和顺序
Map<String, String> paramMap = sqlSession.selectOne("getProcedureParams", "存储过程名");
// 使用动态SQL生成call语句的参数部分
String paramsSql = sqlSession.getConfiguration().getMappedStatement("procedureParams").getSqlSource().getBoundSql(null).getSql();
// 拼接call语句并执行
String callSql = "CALL 存储过程名(" + paramsSql + ")";
sqlSession.selectOne(callSql);
}
1楼上的可以的。
定义多个存储过程呢,然后根据条件判断该去调用某一个存储过程
分三步走
第一步:获取到最新的参数字段和顺序,用新定义的实体类接收
第二步:在java代码中将新的参数字段和前端的传的值一一对应
第三步:将第二步的字段以及值和bsp_CommRole;8存储过程中的参数一一对应上。