一、异常出现的场景

1)异常出现的SQL

@Select("SELECT\n" +
" id,discount_type ,min_charge, ${cardFee} AS actualDiscountPrice , discount_price AS discountPrice ,status ,name \n" +
"FROM\n" +
"\tuser_coupon \n" +
"WHERE\n" +
"\tstore_id = #{storeId}\n" +
"\tAND uid = #{uid}\n" +
"\tAND STATUS = 0 \n" +
"\tAND expired_date >= now( ) \n" +
"\tAND (card_coupon_type = 1 OR ( card_coupon_type = 2 AND JSON_CONTAINS ( card_coupon -> '$[*]','#{cardId}', '$' ) )\n" +
"\tAND (discount_type = 2 OR ( discount_type = 1 AND min_charge <= #{cardFee} ) ) )")
List<UserCouponRuleResult> findUserCouponCard(@Param("storeId") Integer storeId, @Param("uid") Integer uid, @Param("cardFee") BigDecimal cardFee, @Param("cardId") Integer cardId);

2)异常信息

org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.type.TypeException: Could not set parameters for mapping: ParameterMapping{property='cardFee', mode=IN, javaType=class java.lang.Object, jdbcType=null, numericScale=null, resultMapId='null', jdbcTypeName='null', expression='null'}. Cause: org.apache.ibatis.type.TypeException: Error setting non null for parameter #4 with JdbcType null . Try setting a different JdbcType for this parameter or a different configuration property. Cause: org.apache.ibatis.type.TypeException: Error setting non null for parameter #4 with JdbcType null . Try setting a different JdbcType for this parameter or a different configuration property. Cause: java.sql.SQLException: Parameter index out of range (4 > number of parameters, which is 3).

    at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:77)
at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:446)
at com.sun.proxy.$Proxy185.selectList(Unknown Source)
at org.mybatis.spring.SqlSessionTemplate.selectList(SqlSessionTemplate.java:230)
at org.apache.ibatis.binding.MapperMethod.executeForMany(MapperMethod.java:139)
at org.apache.ibatis.binding.MapperMethod.execute(MapperMethod.java:76)
at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:59)
at com.sun.proxy.$Proxy250.findUserCouponCard(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
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:343)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:197)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212)
at com.sun.proxy.$Proxy251.findUserCouponCard(Unknown Source)
at com.xinchan.xcauto.merchants.saas.CommonTest.run13(CommonTest.java:79)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.springframework.test.context.junit4.statements.RunBeforeTestExecutionCallbacks.evaluate(RunBeforeTestExecutionCallbacks.java:73)
at org.springframework.test.context.junit4.statements.RunAfterTestExecutionCallbacks.evaluate(RunAfterTestExecutionCallbacks.java:83)
at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:251)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:190)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
Caused by: org.apache.ibatis.type.TypeException: Could not set parameters for mapping: ParameterMapping{property='cardFee', mode=IN, javaType=class java.lang.Object, jdbcType=null, numericScale=null, resultMapId='null', jdbcTypeName='null', expression='null'}. Cause: org.apache.ibatis.type.TypeException: Error setting non null for parameter #4 with JdbcType null . Try setting a different JdbcType for this parameter or a different configuration property. Cause: org.apache.ibatis.type.TypeException: Error setting non null for parameter #4 with JdbcType null . Try setting a different JdbcType for this parameter or a different configuration property. Cause: java.sql.SQLException: Parameter index out of range (4 > number of parameters, which is 3).
at org.apache.ibatis.scripting.defaults.DefaultParameterHandler.setParameters(DefaultParameterHandler.java:89)
at org.apache.ibatis.executor.statement.PreparedStatementHandler.parameterize(PreparedStatementHandler.java:93)
at org.apache.ibatis.executor.statement.RoutingStatementHandler.parameterize(RoutingStatementHandler.java:64)
at org.apache.ibatis.executor.SimpleExecutor.prepareStatement(SimpleExecutor.java:86)
at org.apache.ibatis.executor.SimpleExecutor.doQuery(SimpleExecutor.java:62)
at org.apache.ibatis.executor.BaseExecutor.queryFromDatabase(BaseExecutor.java:326)
at org.apache.ibatis.executor.BaseExecutor.query(BaseExecutor.java:156)
at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:109)
at com.github.pagehelper.PageInterceptor.intercept(PageInterceptor.java:143)
at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:61)
at com.sun.proxy.$Proxy414.query(Unknown Source)
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:148)
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:141)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
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:433)
... 48 more
Caused by: org.apache.ibatis.type.TypeException: Error setting non null for parameter #4 with JdbcType null . Try setting a different JdbcType for this parameter or a different configuration property. Cause: org.apache.ibatis.type.TypeException: Error setting non null for parameter #4 with JdbcType null . Try setting a different JdbcType for this parameter or a different configuration property. Cause: java.sql.SQLException: Parameter index out of range (4 > number of parameters, which is 3).
at org.apache.ibatis.type.BaseTypeHandler.setParameter(BaseTypeHandler.java:55)
at org.apache.ibatis.scripting.defaults.DefaultParameterHandler.setParameters(DefaultParameterHandler.java:87)
... 65 more
Caused by: org.apache.ibatis.type.TypeException: Error setting non null for parameter #4 with JdbcType null . Try setting a different JdbcType for this parameter or a different configuration property. Cause: java.sql.SQLException: Parameter index out of range (4 > number of parameters, which is 3).
at org.apache.ibatis.type.BaseTypeHandler.setParameter(BaseTypeHandler.java:55)
at org.apache.ibatis.type.UnknownTypeHandler.setNonNullParameter(UnknownTypeHandler.java:45)
at org.apache.ibatis.type.BaseTypeHandler.setParameter(BaseTypeHandler.java:53)
... 66 more
Caused by: java.sql.SQLException: Parameter index out of range (4 > number of parameters, which is 3).
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:965)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:898)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:887)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:861)
at com.mysql.jdbc.PreparedStatement.checkBounds(PreparedStatement.java:3327)
at com.mysql.jdbc.PreparedStatement.setInternal(PreparedStatement.java:3312)
at com.mysql.jdbc.PreparedStatement.setInternal(PreparedStatement.java:3351)
at com.mysql.jdbc.PreparedStatement.setBigDecimal(PreparedStatement.java:2790)
at com.zaxxer.hikari.pool.HikariProxyPreparedStatement.setBigDecimal(HikariProxyPreparedStatement.java)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.apache.ibatis.logging.jdbc.PreparedStatementLogger.invoke(PreparedStatementLogger.java:67)
at com.sun.proxy.$Proxy415.setBigDecimal(Unknown Source)
at org.apache.ibatis.type.BigDecimalTypeHandler.setNonNullParameter(BigDecimalTypeHandler.java:32)
at org.apache.ibatis.type.BigDecimalTypeHandler.setNonNullParameter(BigDecimalTypeHandler.java:27)
at org.apache.ibatis.type.BaseTypeHandler.setParameter(BaseTypeHandler.java:53)
... 68 more

二、异常信息分析

1)从第一个异常信息来看,无法设置cardFee属性,但是具体原因需要看下个异常信息

Could not set parameters for mapping: ParameterMapping{property='cardFee', mode=IN, javaType=class java.lang.Object, jdbcType=null, numericScale=null, resultMapId='null', jdbcTypeName='null', expression='null'}. Cause: org.apache.ibatis.type.TypeException: Error setting non null for parameter #4 with JdbcType null . 

2)从第二个异常信息来看,需要设置的参数值个数超过了范围,这就奇怪了,我们的SQL中明明有4个#{},也有对应的4个参数,那为什么会超过呢?

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

3)我们仔细看写的SQL,会发现这个:'#{}',#{}被单引号引用了,那会不会是这个原因呢?结果就是这个原因,去掉就可以了

 JSON_CONTAINS ( card_coupon -> '$[*]','#{cardId}', '$' ) )

三、解决方案及源码分析

使用#{}时,使用单引号会导致#{}失效

解决方案:

  如异常分析第三点,去掉单引号就可以了

源码分析:

1)我们直接定位到Mybatis设置参数的代码类和方法
  DefaultParameterHandler类的setParameters方法

@Override
public void setParameters(PreparedStatement ps) {
ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());
List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
if (parameterMappings != null) {
for (int i = 0; i < parameterMappings.size(); i++) {
ParameterMapping parameterMapping = parameterMappings.get(i);
if (parameterMapping.getMode() != ParameterMode.OUT) {
Object value;
String propertyName = parameterMapping.getProperty();
if (boundSql.hasAdditionalParameter(propertyName)) { // issue #448 ask first for additional params
value = boundSql.getAdditionalParameter(propertyName);
} else if (parameterObject == null) {
value = null;
} else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
value = parameterObject;
} else {
MetaObject metaObject = configuration.newMetaObject(parameterObject);
value = metaObject.getValue(propertyName);
}
TypeHandler typeHandler = parameterMapping.getTypeHandler();
JdbcType jdbcType = parameterMapping.getJdbcType();
if (value == null && jdbcType == null) {
jdbcType = configuration.getJdbcTypeForNull();
}
try {
typeHandler.setParameter(ps, i + 1, value, jdbcType); //从这里进入
} catch (TypeException e) {
throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);
} catch (SQLException e) {
throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);
}
}
}
}
}

2)BaseTypeHandler类的setParameter方法

@Override
public void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException {
if (parameter == null) {
if (jdbcType == null) {
throw new TypeException("JDBC requires that the JdbcType must be specified for all nullable parameters.");
}
try {
ps.setNull(i, jdbcType.TYPE_CODE);
} catch (SQLException e) {
throw new TypeException("Error setting null for parameter #" + i + " with JdbcType " + jdbcType + " . " +
"Try setting a different JdbcType for this parameter or a different jdbcTypeForNull configuration property. " +
"Cause: " + e, e);
}
} else {
try {
setNonNullParameter(ps, i, parameter, jdbcType); //从这里进
} catch (Exception e) {
throw new TypeException("Error setting non null for parameter #" + i + " with JdbcType " + jdbcType + " . " +
"Try setting a different JdbcType for this parameter or a different configuration property. " +
"Cause: " + e, e);
}
}
}

3)BigDecimalTypeHandler类的setNonNullParameter方法

@Override
public void setNonNullParameter(PreparedStatement ps, int i, BigDecimal parameter, JdbcType jdbcType)
throws SQLException {
ps.setBigDecimal(i, parameter); //从从里继续
}

4)PreparedStatement类的setBigDecimal方法

public void setBigDecimal(int parameterIndex, BigDecimal x) throws SQLException {
if (x == null) {
setNull(parameterIndex, java.sql.Types.DECIMAL);
} else {
setInternal(parameterIndex, StringUtils.fixDecimalExponent(StringUtils.consistentToString(x))); //从这里进 this.parameterTypes[parameterIndex - 1 + getParameterIndexOffset()] = Types.DECIMAL;
}
}
protected final void setInternal(int paramIndex, String val) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) { byte[] parameterAsBytes = null; if (this.charConverter != null) {
parameterAsBytes = this.charConverter.toBytes(val);
} else {
parameterAsBytes = StringUtils.getBytes(val, this.charConverter, this.charEncoding, this.connection.getServerCharset(),
this.connection.parserKnowsUnicode(), getExceptionInterceptor());
} setInternal(paramIndex, parameterAsBytes); //从这里进
}
}
protected final void setInternal(int paramIndex, byte[] val) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) { int parameterIndexOffset = getParameterIndexOffset(); checkBounds(paramIndex, parameterIndexOffset); //看这里 this.isStream[paramIndex - 1 + parameterIndexOffset] = false;
this.isNull[paramIndex - 1 + parameterIndexOffset] = false;
this.parameterStreams[paramIndex - 1 + parameterIndexOffset] = null;
this.parameterValues[paramIndex - 1 + parameterIndexOffset] = val;
}
}
protected void checkBounds(int paramIndex, int parameterIndexOffset) throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
if ((paramIndex < 1)) {
throw SQLError.createSQLException(Messages.getString("PreparedStatement.49") + paramIndex + Messages.getString("PreparedStatement.50"),
SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor());
} else if (paramIndex > this.parameterCount) {  //这个If不满足即 4 > 3,抛出异常
throw SQLError
.createSQLException(
Messages.getString("PreparedStatement.51") + paramIndex + Messages.getString("PreparedStatement.52")
+ (this.parameterValues.length) + Messages.getString("PreparedStatement.53"),
SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor());
} else if (parameterIndexOffset == -1 && paramIndex == 1) {
throw SQLError.createSQLException("Can't set IN parameter for return value of stored function call.", SQLError.SQL_STATE_ILLEGAL_ARGUMENT,
getExceptionInterceptor());
}
}
}

5)paramIndex代表我的待赋值的参数的索引从1开始,那么上面的this.parameterCount应该为4才对为啥是3呢?那么我们就需要看看this.parameterCount值怎么来的

5.1、PreparedStatement类initializeFromParseInfo方法

private void initializeFromParseInfo() throws SQLException {
synchronized (checkClosed().getConnectionMutex()) {
this.staticSqlStrings = this.parseInfo.staticSql;//看这里 (2)
this.isLoadDataQuery = this.parseInfo.foundLoadData;
this.firstCharOfStmt = this.parseInfo.firstStmtChar; this.parameterCount = this.staticSqlStrings.length - 1; //看这里 (1) this.parameterValues = new byte[this.parameterCount][];
this.parameterStreams = new InputStream[this.parameterCount];
this.isStream = new boolean[this.parameterCount];
this.streamLengths = new int[this.parameterCount];
this.isNull = new boolean[this.parameterCount];
this.parameterTypes = new int[this.parameterCount]; clearParameters(); for (int j = 0; j < this.parameterCount; j++) {
this.isStream[j] = false;
}
}
}

5.2、在看this.parseInfo值怎么来的,是从PreparedStatement的构造函数

public PreparedStatement(MySQLConnection conn, String sql, String catalog) throws SQLException {
super(conn, catalog); if (sql == null) {
throw SQLError.createSQLException(Messages.getString("PreparedStatement.0"), SQLError.SQL_STATE_ILLEGAL_ARGUMENT, getExceptionInterceptor());
} detectFractionalSecondsSupport();
this.originalSql = sql; this.doPingInstead = this.originalSql.startsWith(PING_MARKER); this.dbmd = this.connection.getMetaData(); this.useTrueBoolean = this.connection.versionMeetsMinimum(3, 21, 23); this.parseInfo = new ParseInfo(sql, this.connection, this.dbmd, this.charEncoding, this.charConverter); //看这里 initializeFromParseInfo(); this.compensateForOnDuplicateKeyUpdate = this.connection.getCompensateOnDuplicateKeyUpdateCounts(); if (conn.getRequiresEscapingEncoder()) {
this.charsetEncoder = Charset.forName(conn.getEncoding()).newEncoder();
}
}

ParseInfo是PreparedStatement的一个内部类

ParseInfo(String sql, MySQLConnection conn, java.sql.DatabaseMetaData dbmd, String encoding, SingleByteCharsetConverter converter) throws SQLException {
this(sql, conn, dbmd, encoding, converter, true); //进去
}
 public ParseInfo(String sql, MySQLConnection conn, java.sql.DatabaseMetaData dbmd, String encoding, SingleByteCharsetConverter converter,
boolean buildRewriteInfo) throws SQLException {
try {
if (sql == null) {
throw SQLError.createSQLException(Messages.getString("PreparedStatement.61"), SQLError.SQL_STATE_ILLEGAL_ARGUMENT,
conn.getExceptionInterceptor());
} this.charEncoding = encoding;
this.lastUsed = System.currentTimeMillis(); String quotedIdentifierString = dbmd.getIdentifierQuoteString(); char quotedIdentifierChar = 0; if ((quotedIdentifierString != null) && !quotedIdentifierString.equals(" ") && (quotedIdentifierString.length() > 0)) {
quotedIdentifierChar = quotedIdentifierString.charAt(0);
} this.statementLength = sql.length(); ArrayList<int[]> endpointList = new ArrayList<int[]>();
boolean inQuotes = false;
char quoteChar = 0;
boolean inQuotedId = false;
int lastParmEnd = 0;
int i; boolean noBackslashEscapes = conn.isNoBackslashEscapesSet(); // we're not trying to be real pedantic here, but we'd like to skip comments at the beginning of statements, as frameworks such as Hibernate
// use them to aid in debugging this.statementStartPos = findStartOfStatement(sql); for (i = this.statementStartPos; i < this.statementLength; ++i) {
char c = sql.charAt(i); if ((this.firstStmtChar == 0) && Character.isLetter(c)) {
// Determine what kind of statement we're doing (_S_elect, _I_nsert, etc.)
this.firstStmtChar = Character.toUpperCase(c); // no need to search for "ON DUPLICATE KEY UPDATE" if not an INSERT statement
if (this.firstStmtChar == 'I') {
this.locationOfOnDuplicateKeyUpdate = getOnDuplicateKeyLocation(sql, conn.getDontCheckOnDuplicateKeyUpdateInSQL(),
conn.getRewriteBatchedStatements(), conn.isNoBackslashEscapesSet());
this.isOnDuplicateKeyUpdate = this.locationOfOnDuplicateKeyUpdate != -1;
}
} if (!noBackslashEscapes && c == '\\' && i < (this.statementLength - 1)) {
i++;
continue; // next character is escaped
} // are we in a quoted identifier? (only valid when the id is not inside a 'string')
if (!inQuotes && (quotedIdentifierChar != 0) && (c == quotedIdentifierChar)) {
inQuotedId = !inQuotedId;
} else if (!inQuotedId) {
// only respect quotes when not in a quoted identifier if (inQuotes) {
if (((c == '\'') || (c == '"')) && c == quoteChar) { //(5)当sql中存在单引号和双引号时,会进入改方法
if (i < (this.statementLength - 1) && sql.charAt(i + 1) == quoteChar) {
i++;
continue; // inline quote escape
} inQuotes = !inQuotes; //(4)这里会改变inQuotes的值
quoteChar = 0;
} else if (((c == '\'') || (c == '"')) && c == quoteChar) {
inQuotes = !inQuotes;
quoteChar = 0;
}
} else {
if (c == '#' || (c == '-' && (i + 1) < this.statementLength && sql.charAt(i + 1) == '-')) {
// run out to end of statement, or newline, whichever comes first
int endOfStmt = this.statementLength - 1; for (; i < endOfStmt; i++) {
c = sql.charAt(i); if (c == '\r' || c == '\n') {
break;
}
} continue;
} else if (c == '/' && (i + 1) < this.statementLength) {
// Comment?
char cNext = sql.charAt(i + 1); if (cNext == '*') {
i += 2; for (int j = i; j < this.statementLength; j++) {
i++;
cNext = sql.charAt(j); if (cNext == '*' && (j + 1) < this.statementLength) {
if (sql.charAt(j + 1) == '/') {
i++; if (i < this.statementLength) {
c = sql.charAt(i);
} break; // comment done
}
}
}
}
} else if ((c == '\'') || (c == '"')) {
inQuotes = true;
quoteChar = c;
}
}
} if ((c == '?') && !inQuotes && !inQuotedId) {  //(3) 不仅是要?,而且还要满足 inQuotes == false
endpointList.add(new int[] { lastParmEnd, i }); //(2)
lastParmEnd = i + 1; if (this.isOnDuplicateKeyUpdate && i > this.locationOfOnDuplicateKeyUpdate) {
this.parametersInDuplicateKeyClause = true;
}
}
} if (this.firstStmtChar == 'L') {
if (StringUtils.startsWithIgnoreCaseAndWs(sql, "LOAD DATA")) {
this.foundLoadData = true;
} else {
this.foundLoadData = false;
}
} else {
this.foundLoadData = false;
} endpointList.add(new int[] { lastParmEnd, this.statementLength });
this.staticSql = new byte[endpointList.size()][]; //(1) for (i = 0; i < this.staticSql.length; i++) {
int[] ep = endpointList.get(i);
int end = ep[1];
int begin = ep[0];
int len = end - begin; if (this.foundLoadData) {
this.staticSql[i] = StringUtils.getBytes(sql, begin, len);
} else if (encoding == null) {
byte[] buf = new byte[len]; for (int j = 0; j < len; j++) {
buf[j] = (byte) sql.charAt(begin + j);
} this.staticSql[i] = buf;
} else {
if (converter != null) {
this.staticSql[i] = StringUtils.getBytes(sql, converter, encoding, conn.getServerCharset(), begin, len, conn.parserKnowsUnicode(),
conn.getExceptionInterceptor());
} else {
this.staticSql[i] = StringUtils.getBytes(sql, encoding, conn.getServerCharset(), begin, len, conn.parserKnowsUnicode(), conn,
conn.getExceptionInterceptor());
}
}
}
} catch (StringIndexOutOfBoundsException oobEx) {
SQLException sqlEx = new SQLException("Parse error for " + sql);
sqlEx.initCause(oobEx); throw sqlEx;
} if (buildRewriteInfo) {
this.canRewriteAsMultiValueInsert = PreparedStatement.canRewrite(sql, this.isOnDuplicateKeyUpdate, this.locationOfOnDuplicateKeyUpdate,
this.statementStartPos) && !this.parametersInDuplicateKeyClause; if (this.canRewriteAsMultiValueInsert && conn.getRewriteBatchedStatements()) {
buildRewriteBatchedParams(sql, conn, dbmd, encoding, converter);
}
}
}

6)通过上面的源码分析,我们可以知道,使用#{}时,使用单引号会导致#{}失效

【异常及源码分析】org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.type.TypeException: Could not set parameters for mapping: ParameterMapping的更多相关文章

  1. 解决:org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.builder.BuilderException: Error evaluating expression 'requestMap.maintenancename != null and requestMap.maintenance

    异常如下:org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.builder.Builde ...

  2. org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.reflection.ReflectionException: There is no getter for property named 'socialCode' in 'class java.lang.String'

    异常: org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.reflection.Refl ...

  3. org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.binding.BindingException: Parameter 'username' not found. Available parameters are [1, 0, param1, param2]

    Spring+mybatis错误:org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.bi ...

  4. 怪事年年有,今天特别多!org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.binding.BindingException: Parameter 'empno' not found. Available parameters are [emp, deptno, param1, param

    错误: org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.binding.Binding ...

  5. HTTP Status 500 - org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.exceptions.PersistenceException:

    HTTP Status 500 - org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.e ...

  6. org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.binding.BindingException: Parameter 'userId' not found. Available parameters are [arg1, arg0, param1, param2]

    2018-06-27 16:43:45.552  INFO 16932 --- [nio-8081-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : ...

  7. SpringMvc错误:HTTP Status 500 - Request processing failed; nested exception is org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.reflection.ReflectionException: There is n

    HTTP Status 500 - Request processing failed; nested exception is org.mybatis.spring.MyBatisSystemExc ...

  8. Mybatis报错 org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.binding.BindingException: Parameter 'parentCode' not found. Available parameters are [0, 1, param1, param2]

    orcal数据库使用mybatis接收参数,如果传的是多个参数,需要使用#{0},#{1},...等代替具体参数名,0 代表第一个参数,1 代表第二个参数,以此类推. 错误语句: <select ...

  9. org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.reflection.ReflectionException: There is no getter for property named '__frch_lableId_0' in 'class com.cd.entity.Page'

    #号改为$即可

随机推荐

  1. topcoder srm 465 div1

    problem1 link 以两个点$p,q$为中心的两个正方形的边长和最大为$2dist(p,q)$,即$p,q$距离的两倍. 也就是两个$p,q$的连线垂直穿过两个正方形的一对边且平分两个正方形. ...

  2. LightOJ 1151 Snakes and Ladders(概率DP + 高斯消元)

    题意:1~100的格子,有n个传送阵,一个把进入i的人瞬间传送到tp[i](可能传送到前面,也可能是后面),已知传送阵终点不会有另一个传送阵,1和100都不会有传送阵.每次走都需要掷一次骰子(1~6且 ...

  3. 【Runtime Error】打开Matlib7.0运行程序报错的解决办法

    1.在C盘建立一个文件夹temp,存放临时文件: 2.右键我的电脑-属性-高级系统设置-环境变量-系统变量,将TEMP.TMP的值改成C:\temp: 3.还是在第2步那里,新建变量,变量名称为BLA ...

  4. Match function in R

    Examples:     print(match(5, c(1,2,9,5,3,6,7,4,5)))[1] 4     5 %in% c(1,2,9,5,3,6,7,4,5)[1] TRUE    ...

  5. python 之 模块

    在python模块,是一个python文件,以.py结尾,包含了python对象定义 和python语句 通过import语句 ,语法 import module1[,module2,module3, ...

  6. JavaI/O(输入/输出)

    File类 通过File类可以在程序中操作文件和目录,File能新建.删除.重命名文件和目录,但是不能访问文件内容本身. 理解I/O流 流(stream)是从起源(source)到接收(sink)的有 ...

  7. 数据集是 seq 文件的处理办法

    数据集是 seq 文件的处理办法 2017-03-17 最近下了一个数据集,是 seq 格式的,第一次处理这种数据.使用了官方提供的 matlab 工具包:https://pdollar.github ...

  8. (zhuan) LSTM Neural Network for Time Series Prediction

    LSTM Neural Network for Time Series Prediction Wed 21st Dec 2016 Neural Networks these days are the ...

  9. Linux 时间矫正命令

    Linux 时间矫正 sudo ntpdate -u ntp.api.bz 第一使用可能提示ntpdate没安装,用以下命令安装即可 sudo apt install ntpdate

  10. C#winform的textbox怎么设置滚动条

    用 C#开发软件的时候文本框textbox是没有滚动条的,而且是单行文本.下面教大家如何设置多行,并且设置横向滚动条和垂直滚动条. 打开VS工具,创建一个winform窗体项目.系统会自动创建一个主窗 ...