记一个mysql使用时in()内字符串长度截断的问题

众所周知,mysql对in内的数量和长度是没有限制的(当然我也是百度才确认的^_^),那么为什么会有in内的内容被截断的问题呢?先看下报错日志如下

 .......|mybatis|select * from user_acct where user_id in ('e1035711b70a4b46aaf3f622617ccd00','e105604d110c46338f164b54db9a9d40','e1080ae78c034bb08e8ff084463f3275','e10ee307d07b40a18e8c1218d104938b','e10fbf6943ff4f219aaef02a173fa8f8','e114724745514f7d8ed15a1a72002d77','e11efc56ef144cff9509f62846a2eeb1','e123a55c6b3f44a7be2523ed5e253953','e1294c3b54774d10883486b9eafdcba3','e12f318594524d3e88ece35224086fef','e139463f5e30403fba138fccca028ad1','e14a783a73094fe0b0ea30a0fe3703eb','e1585e28f7bc4af7b589b3c9a8a80f1b','e15ffddccd6e409086b8d9a267411f7f','e168c71ac82c48c3ad9125a5614eba59','e16a0d2234344257ae7b9048380fe3de','e16ba2f5472b46d5ac5ce92ddded3bde','e16d519f16584a9f9ce3364ef1b51ed0','e171e4698ee54e22b183ad69fe5a21f4','e17555068fd84f579b09b866598cdd64','e1777e9028be4cda829651732b036f1b','e17b4fd3fdc5497280d44871a8518ee0','e18a261edb3147ebaa8217a1b5f96f0d','e191b891fced43ce90f8c1152e25e3e3','e1930b1f53ea43058a71db7859a2a678','e19cca9de073448e9409d11cccea0ed9','e1c01de6b8d74a2b82278b345bd5db31','e1c6b23168d643259f873b98dd7255e1','e1cd50f75e1d472386e03abf09325bde','e1dc283b) and origin=? GROUP BY user_id, acct_type|'ls'|0|java.lang.reflect.InvocationTargetException
at sun.reflect.GeneratedMethodAccessor54.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.apache.ibatis.plugin.Invocation.proceed(Invocation.java:49)
at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:60)
at com.sun.proxy.$Proxy184.query(Unknown Source)
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:108)
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:102)
at sun.reflect.GeneratedMethodAccessor57.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:354)
at com.sun.proxy.$Proxy35.selectList(Unknown Source)
at org.mybatis.spring.SqlSessionTemplate.selectList(SqlSessionTemplate.java:194)
at org.apache.ibatis.binding.MapperMethod.executeForMany(MapperMethod.java:119)
at org.apache.ibatis.binding.MapperMethod.execute(MapperMethod.java:63)
at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:52)
at com.sun.proxy.$Proxy44.getByUserIds(Unknown Source)
at sun.reflect.GeneratedMethodAccessor166.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:317)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:183)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)
at com.alibaba.druid.support.spring.stat.DruidStatInterceptor.invoke(DruidStatInterceptor.java:72)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204)
at com.sun.proxy.$Proxy45.getByUserIds(Unknown Source)
... 60 more
Caused by: java.sql.SQLException: Parameter index out of range (1 > number of parameters, which is 0).
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:998)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:937)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:926)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:872)
at com.mysql.jdbc.PreparedStatement.checkBounds(PreparedStatement.java:3367)
at com.mysql.jdbc.PreparedStatement.setInternal(PreparedStatement.java:3352)
at com.mysql.jdbc.PreparedStatement.setString(PreparedStatement.java:4078)
at com.alibaba.druid.filter.FilterChainImpl.preparedStatement_setString(FilterChainImpl.java:2823)
at com.alibaba.druid.filter.FilterAdapter.preparedStatement_setString(FilterAdapter.java:1340)
at com.alibaba.druid.filter.FilterChainImpl.preparedStatement_setString(FilterChainImpl.java:2820)
at com.alibaba.druid.proxy.jdbc.PreparedStatementProxyImpl.setString(PreparedStatementProxyImpl.java:547)
at com.alibaba.druid.pool.DruidPooledPreparedStatement.setString(DruidPooledPreparedStatement.java:365)
at org.apache.ibatis.type.StringTypeHandler.setNonNullParameter(StringTypeHandler.java:31)
at org.apache.ibatis.type.StringTypeHandler.setNonNullParameter(StringTypeHandler.java:26)
at org.apache.ibatis.type.BaseTypeHandler.setParameter(BaseTypeHandler.java:50)
at org.apache.ibatis.type.UnknownTypeHandler.setNonNullParameter(UnknownTypeHandler.java:45)
at org.apache.ibatis.type.BaseTypeHandler.setParameter(BaseTypeHandler.java:50)
at org.apache.ibatis.scripting.defaults.DefaultParameterHandler.setParameters(DefaultParameterHandler.java:81)
at org.apache.ibatis.executor.statement.PreparedStatementHandler.parameterize(PreparedStatementHandler.java:80)
at org.apache.ibatis.executor.statement.RoutingStatementHandler.parameterize(RoutingStatementHandler.java:61)
at org.apache.ibatis.executor.SimpleExecutor.prepareStatement(SimpleExecutor.java:74)
at org.apache.ibatis.executor.SimpleExecutor.doQuery(SimpleExecutor.java:59)
at org.apache.ibatis.executor.BaseExecutor.queryFromDatabase(BaseExecutor.java:267)
at org.apache.ibatis.executor.BaseExecutor.query(BaseExecutor.java:137)
at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:96)
at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:77)
... 60 more

报错是说sql中没有参数,但是我们传了一个参数,所以参数索引越界

Caused by: java.sql.SQLException: Parameter index out of range (1 > number of parameters, which is 0).

拿到日志中的sql:

SELECT
    *
FROM
    user_acct
WHERE
    user_id IN (
    'e1035711b70a4b46aaf3f622617c0000',
    'e105604d110c46338f160004db9a9d40',
    ...这里省略26个user_id
    'e1cd50f75e1d472386e0000f09325bde',
    'e1dc283b) 
    and origin=? GROUP BY user_id, acct_type;

可以看出sql中是有一个参数位的,但是因为最后一个user_id的右引号没了,所以sql语句把后面全部认为是最后一个左引号的字符串了。
我们再拿到代码里面的sql

@Select("select * from user_acct "
            + "where user_id in (${userIds}) and origin=#{origin} GROUP BY user_id, acct_type")
@ResultMap("com.user.dao.UserAcctMapper.UserAcctResult")
List<UserAcct> getByUserIds(@Param("userIds") String userIds, @Param("origin") String origin);

从这里看,第一反应是mybatis在拼接sql时,占位符${}内容由于过长被截断了。
从这里开始查找问题,面向百度编程:mybatis并不会截断 ${}内的内容。Defeated!
那么是mysql的问题么?再次面向百度:mybatis对整体sql长度有限制,默认1M,但对in()内的长度和个数是没有限制的。再次Defeated!
最后,会不会是传过来的这个String userIds就是被截断的呢?
回溯到拼接这个userIds的地方,是用group_concat拼接的,如下:

SELECT GROUP_CONCAT("'",user_id,"'") FROM  user_info limit 1000;

到这里基本就能猜出问题所在了,但我们还是确认一下,百度了一下GROUP_CONCAT的长度限制,果然,默认1024字节,一个userId32字节,加两个引号,加一个逗号:(32+2+1)*29+9=1024,刚好。
这里就需要修改某个参数了:group_concat_max_len。根据我们要1000个userId拼接的要求35*1000=3.5w,我们改成5w,问题解决!

你可能感兴趣的:(mysql,解决问题)