两个值相同的Integer类型用!=比较出错的问题

本文探讨了Java中Integer缓存机制及不同数值下Integer对象的比较行为。当数值位于特定范围内时,Integer对象会被缓存,导致相同数值的对象实际上是同一个实例。而对于范围外的大数值,则会创建新的Integer实例。这可能导致不直观的比较结果。文章还提供了正确的Integer对象比较方法。

本文转载于:http://1006836709.iteye.com/blog/1714378

记下来用于积累!

有这么一行代码 

newInvoiceNumbertarget.getAgency().getSuperiorAgency().getId() != cuttentAgency.getId() 
不等号的两边,全部都是34,这个表达式的结果是false,如果两边的值都是765454的话,结果就是true,很奇怪,百思不得其解,问带我的同事大哥,他说如果是Integer类型的话,用!=来比较两个值,是不严谨的,比如刚才的情况,如果是34,返回结果就是false,而如果是特别大的数,如765454,就会出现true,这个情况不常注意,但是是一个漏洞,而要是想知道其中原理,就得好好看看jdk提供的Integer.class类,在里面,定义了,初始化Integer类的一个上限和下限,比如 
public static Integer valueOf(int i) { 
        if(i >= -128 && i <= IntegerCache.high) 
            return IntegerCache.cache[i + 128]; 
        else 
            return new Integer(i); 
    } 
这一段代码,以这个为例,这是一个设置Integer缓存的代码,如果在初始化的时候,值出在这个区间,那么就直接初始化,如果大于这个区间的话,就会对他加一个缓存,不一定就是这一段,在初始化一个Integer的时候,比如说我的上限和下限分别是128和-127,那么我的34处于这个区间,他就会当成一个int的值,也就是一个变量,放到内存中,而如果是765454这样大的值,才真正初始化成为Integer对象,然后将值封装进去,而在比较的时候,765454的两个Integer是两个不同的对象,有不同的存储空间,那肯定用!=号是比较不出来值的,而如果是34,那么他实际上比较的是变量,而765454比较的是对象,所以就会出现上面的问题 
这个我想也肯定是为了优化考虑,还有就是对象的应用,如果一个系统中大量的用到Integer类型,那么就要设置一下jvm或者jdk中队Integer类型的上限和下限的值,这样的话,比如说,将上限放到1000,原来的情况中,如果大于128的话就会初始化为对象,然后存储,现在大于128小于1000的还是弄成变量,大于1000的才生成对象,当然对象和变量在内存中的存储大小是有着天壤之别的,而且系统大量用到Integer,并且我们能设置的话,就会为系统省去很多的内存,优化,java强大之处,我才只挖到一角 
回过来,原理弄完了,问题知道了,就要解决了 
解决方法还是很多的,因为我们用!=有可能比较的是变量,也有可能比较的是对象,所以,我们在比较Integer类型的时候,尽量不适用!=,当然int中肯定不用担心这个,我们可以对两个Integer对象进行eqauls比较,因为两个Integer都是对象,而equals又恰好只比较值,不比较对象,所以返回结果肯定是自己想要的,另外一种就是 
public boolean equals(Object obj) { 
if (obj instanceof Integer) { 
    return value == ((Integer)obj).intValue(); 

return false; 
    } 
jdk中Integer的equals 

这个里面的底层也是用intValue来比较的,所以我们在进行比较的时候,也可以用Integer i=234;i.intValue()这样来取值,然后!=比较不会有问题,OK



<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.qs.birp.jgAudit.JgAuditHeadDao"> <select id="getReqByReqNo" resultType="jg_audit_head" parameterType="String"> select * from jg_audit_head where request_no = #{request_no} limit 1; </select> <select id="showJgAuditHead" resultType="jg_audit_head"> SELECT * FROM jg_audit_head <where> and is_show = "1" <if test='request_no !=null and request_no !=""'>and request_no =#{request_no} </if> <if test='purchase_no !=null and purchase_no !=""'>and purchase_no =#{purchase_no} </if> <if test='project_number !=null and project_number !=""'>and project_number =#{project_number} </if> <if test='project_name !=null and project_name !=""'> and project_name like "%"#{project_name}"%"</if> <if test='company_code !=null and company_code !=""'>and company_code =#{company_code} </if> <if test='sssdwdm !=null and sssdwdm !=""'>and sssdwdm =#{sssdwdm}</if> <if test='ssxdwdm !=null and ssxdwdm !=""'>and ssxdwdm =#{ssxdwdm}</if> <if test='status !=null and status !=""'>and status =#{status}</if> <if test='company_code_values!=null and company_code_values.size()>0'> and company_code in <foreach collection="company_code_values" item="item" open="(" separator="," close=")"> #{item} </foreach> </if> </where> limit #{currIndex}, #{pageSize} ; </select> <select id="showJgAuditHeadCount" resultType="Integer"> SELECT count(*) FROM jg_audit_head <where> and is_show = "1" <if test='request_no !=null and request_no !=""'>and request_no =#{request_no} </if> <if test='purchase_no !=null and purchase_no !=""'>and purchase_no =#{purchase_no} </if> <if test='project_number !=null and project_number !=""'>and project_number =#{project_number} </if> <if test='project_name !=null and project_name !=""'> and project_name like "%"#{project_name}"%"</if> <if test='company_code !=null and company_code !=""'>and company_code =#{company_code} </if> <if test='sssdwdm !=null and sssdwdm !=""'>and sssdwdm =#{sssdwdm}</if> <if test='ssxdwdm !=null and ssxdwdm !=""'>and ssxdwdm =#{ssxdwdm}</if> <if test='status !=null and status !=""'>and status =#{status}</if> <if test='company_code_values!=null and company_code_values.size()>0'> and company_code in <foreach collection="company_code_values" item="item" open="(" separator="," close=")"> #{item} </foreach> </if> </where> </select> </mapper> 请你帮我分析 什么原因导致服务起不来
03-08
<think>好的,我现在要帮用户分析为什么这个MyBatis的Mapper文件会导致服务起不来。首先,我需要仔细看看用户提供的XML代码,找出可能的问题点。 首先,检查XML的声明和DOCTYPE是否正确。用户提供的代码中,XML版本和编码是正确的,DOCTYPE的public ID和DTD链接也没有明显错误,这部分应该没问题。 接下来看mapper的namespace属性,指向的是com.qs.birp.jgAudit.JgAuditHeadDao,这应该对应Java接口的完整类名。如果这个路径不正确,可能会导致MyBatis找不到对应的映射,从而引发错误,但通常这种情况下服务可能启动时报找不到mapper的错误,而不是完全起不来。不过还是需要确认是否存在拼写错误或者包路径不正确的情况。 然后检查各个select语句。比如第一个select的id是getReqByReqNo,参数类型是String,这里参数名是request_no,但MyBatis中如果只有一个参数,名称应该与方法参数一致。如果接口方法中的参数名不是request_no,可能会导致参数绑定失败,但通常这会引发运行时错误,而不是服务启动失败。 接下来看showJgAuditHead这个查询,它包含动态条件。这里要注意是否使用了正确的参数名,比如company_code_values在传入时是否是一个集合。如果传入的参数名不一致,或者类型不匹配,比如应该用List而传入了其他类型,可能会导致解析错误,但这也可能是在运行时才会报错。 另外,在动态SQL中,比如foreach循环,collection属性应该是传入参数的集合名称。如果这里写错了,比如应该是companyCodes而不是company_code_values,那么解析时会出错,导致启动时加载失败。例如,如果接口方法中没有名为company_code_values的参数,这里就会报错,导致MyBatis初始化失败,进而整个服务启动失败。 还有,检查SQL语句中的占位符是否正确。例如,like语句中使用的是"%"#{project_name}"%",这里是否正确?MyBatis中正确的写法应该是concat('%',#{project_name},'%'),但用户这里用的是双引号包围,可能在某些数据库中会导致语法错误,但更多是运行时的问题,而不是启动问题。 再看看resultType是否正确。用户写的是jg_audit_head,这应该是MyBatis的别名配置或者全限定类名。如果配置文件中没有为jg_audit_head配置对应的类,或者类名不正确,会导致映射失败,可能引发启动时的错误,尤其是在启用严格映射检查的情况下。 另外,检查是否有语法错误,比如标签未正确闭合,或者特殊符号未转义。比如在XML中,像"<"这样的符号需要转义,但用户的代码中似乎没有这种情况,不过动态SQL中的比较符号如"<"应该用<代替。例如,在status的判断中,如果status参数包含特殊字符,或者XML解析器认为这里有标签,就会导致解析错误,进而服务启动失败。 还有可能的问题是SQL语句中的分号,比如limit后面有分号。在MyBatis中,通常不需要在SQL语句末尾加分号,有些数据库可能不允许,这可能导致SQL语法错误,但通常是在执行时报错,而不是启动时。 另外,检查是否重复的id,比如两个select有相同的id,这会导致MyBatis初始化失败,但用户提供的代码中id都是唯一的,所以这点应该没问题。 此外,MyBatis配置文件中是否正确地扫描到了这个Mapper文件?如果路径配置错误,或者该文件没有被正确加载,会导致Mapper未被注册,进而服务启动失败。但用户的问题可能更直接与XML内容有关,所以需要先排除文件本身的问题。 总结可能的原因: 1. 动态SQL中的collection属性不正确,比如company_code_values与实际参数名不匹配,导致MyBatis初始化时解析失败,引发启动错误。 2. XML中的特殊字符未正确转义,比如在<if test='status !=null and status !=""'>中,如果status的包含特殊符号,可能导致XML解析错误。 3. resultType或parameterType的类名配置错误,导致MyBatis找不到对应的类,从而初始化失败。 4. Mapper的namespace与对应的Java接口不匹配,导致无法绑定,但通常这是启动时的错误,可能导致服务无法启动。 5. SQL语句中的语法问题,如分号或like语句写法,可能在某些数据库驱动中导致问题,但更可能在运行时出错。 其中,最可能导致服务启动失败的原因是XML解析错误,比如动态SQL中的某个部分写错了,导致MyBatis在初始化时无法解析该Mapper文件。例如,foreach中的collection属性如果引用了不存在的参数,会抛出异常,导致应用启动失败。例如,如果company_code_values在接口方法中没有对应的参数,或者参数类型不是集合,就会在启动时抛出异常,导致服务无法启动。</think>这个MyBatis映射文件可能导致服务启动失败的主要原因如下: **1. XML特殊字符未转义** - 在`<if test='status !=null and status !=""'>`中,`!=`符号可能被XML解析器识别为非法字符 - 正确写法应为:`<if test="status != null and status != ''">`(使用实体编码或CDATA块) **2. 集合参数处理问题** - `<foreach collection="company_code_values">`要求接口方法必须包含名为`company_code_values`的集合参数 - 若方法参数名不匹配或参数类型不是`List/Collection`,会导致初始化失败 **3. ResultType映射问题** - `resultType="jg_audit_head"`需要满足以下任一条件: - 在mybatis-config.xml中定义了类型别名 - 使用全限定类名(如`com.example.JgAuditHead`) - 若未正确定义,启动时会抛出类型找不到异常 **4. SQL语法规范问题** - 分号结尾的`limit #{currIndex}, #{pageSize};`在某些数据库驱动中会报错 - 建议移除末尾分号 **5. 参数占位符问题** - `like "%"#{project_name}"%"`应改为: ```xml <bind name="pattern" value="'%' + project_name + '%'"/> like #{pattern} ``` 或使用SQL函数: ```xml like CONCAT('%', #{project_name}, '%') ``` **6. 参数类型匹配** - 所有`#{参数名}`需要严格匹配接口方法的参数: - 若使用`@Param`注解,名称必须完全一致 - 若使用Map传参,key必须存在 **排查建议:** 1. 检查应用启动日志中的`org.apache.ibatis`相关错误 2. 确认`mybatis-config.xml`中: ```xml <typeAliases> <typeAlias type="完整实体类路径" alias="jg_audit_head"/> </typeAliases> ``` 3. 验证Mapper接口方法参数与XML中的`#{}`参数名一致性 4. 使用XML验证工具检查特殊字符(推荐将动态SQL写在`<![CDATA[ ]]>`中) **典型错误日志特征:** ```log ### Cause: org.apache.ibatis.builder.BuilderException: Error parsing Mapper XML... |-- Caused by: org.xml.sax.SAXParseException: 元素内容必须由格式正确的字符数据或标记组成 |-- Caused by: org.apache.ibatis.reflection.ReflectionException: 没有找到对应的结果字段... ``` 建议按以下顺序排查:XML语法 → 参数映射 → 类型别名 → SQL语法。可通过逐步注释SQL片段来定位具体问题节点。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值