mysql map类型_Mybatis中Oracle和Mysql的count字段问题

我们在进行项目开发时经常会碰到查询总数的问题,所以我们直接是用select count(1) from table来进行查询。那么在Mybatis通常情况下我们是这么写的

<select id="testCount" resultType="int">    select count(1) as "totalCount" from ams.t_ams_ac_pmt_dtlselect>

这样做是没问题的,无论是在Oracle还是Mysql,因为Mybatis中有类型处理器,当其检测到resultType时会将其值转化为Int类型的值。所以接收是没问题的。但是如果是如下的写法的话,将resultType变为Map,那么就会有问题。

<select id="testCount" resultType="Map">    select count(1) as "totalCount" from ams.t_ams_ac_pmt_dtlselect>

在Mybatis中如果resultType是Map的话,那么在接收结果参数的时候会实例化一个Map的Map,问题就出现在这,在之前的代码中是用Map来接收的,这在Oracle中是没有问题的,因为在Oracle中count函数获得的值在Java对应的类型是BigDecimal,但是在Mysql中就会出现问题。

在ResultSetMetaData.getClassNameForJavaType()的方法中可以看到Mysql字段对应的Java字段,我们可以得知在Mysql中查询的count得到的数据库类型是BigInt类型的对应的Java类型是Long

54c1e407e735823fd4d5b63083e27675.png

解决办法

  • 改代码,将接收的Map改为Map,然后进行类型转换

  • 改Sql

6d12058a6c57dfa171a876267da7f2c1.png

我们可以看到在Mysql中的Decimal和Numeric类型的都被转化为了BigDecimal,所以在Sql文件中进行类型转换就行

select CAST(count(1) as decimal(18,0)) as "totalCount" from table

不学无数的程序员

jianshu.com/p/2a675a4bd8d0

89367893d8ce076b3f4ad914aabea129.png

<think>我们已知用户要求提供MyBatis调用存储过程的示例。根据提供的引用内容,我们可以总结出以下关键点:1.MyBatis调用存储过程需要在映射文件(mapper.xml)中使用`<select>`或其他标签,并设置`statementType="CALLABLE"`。2.存储过程调用使用`{call存储过程名(参数)}`的格式。3.参数需要指定mode(IN,OUT,INOUT),jdbcType,以及对于OUT参数可能需要指定javaTyperesultMap(如果是结果集)。4.在Java代码中,可以通过Map传递参数,或者使用注解方式传递参数。下面我们将结合引用中的示例,给出一个清晰的MyBatis调用存储过程的示例。示例目标:调用一个存储过程,该存储过程根据输入的用户名询用户信息,并返回一个结果集。步骤1:定义存储过程(以MySQL为例,假设已经存在)```sqlDELIMITER//CREATEPROCEDUREPROC_GET_USER_BY_NAME(INuserNameVARCHAR(255))BEGINSELECT*FROMuserWHEREuser_name=userName;END//DELIMITER;```步骤2:定义Mapper接口方法```javapublicinterfaceUserMapper{//调用存储过程,返回用户列表List<User>getUserByProcedure(StringuserName);}```步骤3:在MapperXML文件中配置存储过程调用```xml<selectid="getUserByProcedure"statementType="CALLABLE"resultMap="UserResultMap">{callPROC_GET_USER_BY_NAME(#{userName,mode=IN,jdbcType=VARCHAR})}</select><resultMapid="UserResultMap"type="User"><idproperty="id"column="id"/><resultproperty="userName"column="user_name"/><resultproperty="email"column="email"/><!--其他字段映射--></resultMap>```注意:这里假设存储过程返回的是结果集,所以我们使用`resultMap`来映射结果。如果存储过程有输出参数(OUT参数),则需要按照引用的方式处理输出参数。例如,如果存储过程有OUT参数(如引用35所示),我们可以这样处理:假设存储过程如下(Oracle):```sqlCREATEORREPLACEPROCEDUREENQ_USER(userNameINVARCHAR2,resultOUTSYS_REFCURSOR)ASBEGINOPENresultFORSELECT*FROMUSERWHEREUSER_NAME=userName;ENDENQ_USER;```则在Mapper接口中,我们可以使用Map来传递参数:```javapublicinterfaceUserMapper{voidgetUser(Map<String,Object>map);}```在XML中:```xml<selectid="getUser"statementType="CALLABLE"parameterType="Map">{callinc.PKG_USER.ENQ_USER(#{userName,mode=IN,jdbcType=VARCHAR},#{result,mode=OUT,jdbcType=CURSOR,javaType=java.sql.ResultSet,resultMap=UserMap})}</select><resultMapid="UserMap"type="com.example.UserDTO"><!--字段映射--></resultMap>```在调用时,需要传入一个Map,其中包含userNameresult(用于接收结果集):```javaMap<String,Object>map=newHashMap<>();map.put("userName","test");userMapper.getUser(map);//然后从map中获取结果集List<UserDTO>users=(List<UserDTO>)map.get("result");```步骤4:在Service层调用Mapper方法。注意:不同的数据库在OUT参数的处理上可能有差异,尤其是游标类型(如Oracle的SYS_REFCURSOR)需要特殊处理。总结MyBatis调用存储过程的基本步骤:1.确保存储过程/存储函数已经在数据库中创建。2.在Mapper接口中定义对应的方法,参数根据存储过程的参数设定,可以使用Map来传递多个参数(特别是包含OUT参数时)。3.在MapperXML中,使用`<select>`(或`<insert>`、`<update>`、`<delete>`,根据存储过程的操作类型)标签,设置`statementType="CALLABLE"`。4.使用`{call存储过程名(参数列表)}`的语法,参数列表中每个参数使用`#{}`指定参数模式、jdbcType等。5.对于OUT参数,需要指定`mode=OUT`,并设置正确的`jdbcType``javaType`,如果是结果集游标,通常`jdbcType=CURSOR`,`javaType=ResultSet`,并且还需要指定`resultMap`。6.在Java代码中调用Mapper方法,并处理返回的结果或输出参数。最后,提供相关问题以帮助用户深入学习。相关问题:1.MyBatis中如何调用带有多个OUT参数的存储过程?2.在MyBatis中调用存储过程时,如何处理存储过程中的事务?3.调用存储过程与直接写SQL询在性能上有何差异?4.如何在使用MyBatis调用存储过程时进行错误处理(例如捕获数据库异常)?5.MyBatis调用存储函数与调用存储过程有何不同?</think> ### MyBatis 调用存储过程完整示例 #### 1. Mapper 接口定义 ```java public interface UserMapper { // 方式1:使用Map传递参数(推荐处理OUT参数) void callProcedureWithMap(Map<String, Object> params); // 方式2:使用注解传递参数 @Options(statementType = StatementType.CALLABLE) @Select("{CALL PROC_GET_USER(#{name, mode=IN, jdbcType=VARCHAR}, #{count, mode=OUT, jdbcType=INTEGER})}") void callProcedureWithAnnotation( @Param("name") String name, @Param("count") Integer count ); } ``` #### 2. Mapper XML 配置 ```xml <!-- 存储过程调用示例 --> <select id="callProcedureWithMap" statementType="CALLABLE" parameterType="map"> {CALL PROC_GET_USER( #{userName, mode=IN, jdbcType=VARCHAR}, #{resultCount, mode=OUT, jdbcType=INTEGER}, #{userList, mode=OUT, jdbcType=CURSOR, javaType=ResultSet, resultMap=UserResultMap} )} </select> <resultMap id="UserResultMap" type="User"> <id property="id" column="user_id"/> <result property="name" column="user_name"/> <result property="email" column="user_email"/> </resultMap> ``` #### 3. 存储过程示例 (MySQL) ```sql CREATE PROCEDURE PROC_GET_USER( IN userName VARCHAR(50), OUT resultCount INT, OUT userList CURSOR ) BEGIN -- 返回匹配用户数 SELECT COUNT(*) INTO resultCount FROM users WHERE name LIKE CONCAT(userName, '%'); -- 返回用户列表 OPEN userList FOR SELECT user_id, user_name, user_email FROM users WHERE name LIKE CONCAT(userName, '%'); END; ``` #### 4. Service 层调用 ```java @Service public class UserService { @Autowired private UserMapper userMapper; public UserResult callProcedure(String name) { // 使用Map接收OUT参数 Map<String, Object> params = new HashMap<>(); params.put("userName", name); params.put("resultCount", 0); // 初始化OUT参数 params.put("userList", null); // 预留结果集位置 // 执行存储过程 userMapper.callProcedureWithMap(params); // 获取OUT参数值 int count = (int) params.get("resultCount"); List<User> users = (List<User>) params.get("userList"); return new UserResult(count, users); } } ``` #### 5. 关键参数说明 | 参数属性 | 作用 | 示例 | |---------|------|------| | `statementType="CALLABLE"` | 声明调用存储过程 | `<select statementType="CALLABLE">` | | `mode` | 参数方向 | `mode=IN`, `mode=OUT`, `mode=INOUT` | | `jdbcType` | 数据库类型 | `jdbcType=VARCHAR`, `jdbcType=INTEGER` | | `javaType` | Java类型 | `javaType=ResultSet` | | `resultMap` | 结果集映射 | `resultMap="UserResultMap"` | | `typeHandler` | 自定义类型转换 | `typeHandler=com.example.MyTypeHandler` | ### 常见使用场景 1. **分页询**:通过存储过程返回总记录数+分页数据 2. **批量处理**:一次调用执行多条SQL操作 3. **事务操作**:包含业务逻辑的数据库原子操作 4. **数据统计**:返回计算结果而非原始数据集 [^1]: MyBatis支持使用存储过程的配置 [^3]: 存储过程的调用最终在mapper.xml中 [^5]: 调用存储过程需要设置参数“mode”
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值