Skip to content

Race Condition in TypeHandlerRegistry #1819

Closed
@LyubinskiyPavel

Description

@LyubinskiyPavel

MyBatis version

3.5.1

Database vendor and version

PostgreSQL 11.+

Test case or example project

@Test
  void shouldAutoRegisterEnumTypeInMultiThreadEnvironment() {
    for (int iteration = 0; iteration < 1000; iteration++) {
      TypeHandlerRegistry typeHandlerRegistry = new TypeHandlerRegistry();
      CountDownLatch startLatch = new CountDownLatch(1);

      List<Future<Object>> taskResults = IntStream.range(0, THREAD_COUNT)
        .mapToObj(taskIndex -> executorService.submit(() -> {
          startLatch.await();
          assertTrue(typeHandlerRegistry.hasTypeHandler(TestEnum.class, JdbcType.VARCHAR),
            "TypeHandler not registered");
          return null;
        })).collect(Collectors.toList());

      startLatch.countDown();
      taskResults.forEach(Futures::getUnchecked);
    }
  }

Steps to reproduce

Expected result

typeHandlerRegistry.hasTypeHandler(TestEnum.class, JdbcType.VARCHAR) always true

Actual result

sometimes i got result false. If it happened i get strange exceptions with read/write enum values:

Caused by: org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.type.TypeException: Could not set parameters for mapping: ParameterMapping{property='role', 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 #6 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 #6 with JdbcType null . Try setting a different JdbcType for this parameter or a different configuration property. Cause: ...SqlException: database: [xxx]; connection: [/127.0.0.1:xxx -> localhost/127.0.0.1:xxx]; state: [07006]; reason: [Can't infer the SQL type to use for an instance of xxx.Role. Use setObject() with an explicit Types value to specify the type to use.]
at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:77)
at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:446)
at com.sun.proxy.$Proxy72.insert(Unknown Source)
at org.mybatis.spring.SqlSessionTemplate.insert(SqlSessionTemplate.java:278)
at org.apache.ibatis.binding.MapperMethod.execute(MapperMethod.java:62)
at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:58)
at com.sun.proxy.$Proxy115.addUserToAccount(Unknown Source)
... 27 more
Caused by: org.apache.ibatis.type.TypeException: Could not set parameters for mapping: ParameterMapping{property='role', 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 #6 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 #6 with JdbcType null . Try setting a different JdbcType for this parameter or a different configuration property. Cause: ...SqlException: database: [xxx]; connection: [/127.0.0.1:xxx -> localhost/127.0.0.1:xxx]; state: [07006]; reason: [Can't infer the SQL type to use for an instance of xxx.Role. Use setObject() with an explicit Types value to specify the type to use.]
at org.apache.ibatis.scripting.defaults.DefaultParameterHandler.setParameters(DefaultParameterHandler.java:89)
at org.apache.ibatis.executor.statement.PreparedStatementHandler.parameterize(PreparedStatementHandler.java:94)
at org.apache.ibatis.executor.statement.RoutingStatementHandler.parameterize(RoutingStatementHandler.java:64)
at org.apache.ibatis.executor.SimpleExecutor.prepareStatement(SimpleExecutor.java:87)
at org.apache.ibatis.executor.SimpleExecutor.doUpdate(SimpleExecutor.java:49)
at org.apache.ibatis.executor.BaseExecutor.update(BaseExecutor.java:117)
at org.apache.ibatis.executor.CachingExecutor.update(CachingExecutor.java:76)
at org.apache.ibatis.session.defaults.DefaultSqlSession.update(DefaultSqlSession.java:197)
at org.apache.ibatis.session.defaults.DefaultSqlSession.insert(DefaultSqlSession.java:184)
at jdk.internal.reflect.GeneratedMethodAccessor240.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:433)
... 34 more
Caused by: org.apache.ibatis.type.TypeException: Error setting non null for parameter #6 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 #6 with JdbcType null . Try setting a different JdbcType for this parameter or a different configuration property. Cause: ...SqlException: database: [xxx]; connection: [/127.0.0.1:xxx -> localhost/127.0.0.1:xxx]; state: [07006]; reason: [Can't infer the SQL type to use for an instance of xxx.Role. Use setObject() with an explicit Types value to specify the type to use.]
at org.apache.ibatis.type.BaseTypeHandler.setParameter(BaseTypeHandler.java:71)
at org.apache.ibatis.scripting.defaults.DefaultParameterHandler.setParameters(DefaultParameterHandler.java:87)
... 46 more
Caused by: org.apache.ibatis.type.TypeException: Error setting non null for parameter #6 with JdbcType null . Try setting a different JdbcType for this parameter or a different configuration property. Cause: ...SqlException: database: [xxx]; connection: [/127.0.0.1:xxx -> localhost/127.0.0.1:xxx]; state: [07006]; reason: [Can't infer the SQL type to use for an instance of xxx.Role. Use setObject() with an explicit Types value to specify the type to use.]
at org.apache.ibatis.type.BaseTypeHandler.setParameter(BaseTypeHandler.java:71)
at org.apache.ibatis.type.UnknownTypeHandler.setNonNullParameter(UnknownTypeHandler.java:45)
at org.apache.ibatis.type.BaseTypeHandler.setParameter(BaseTypeHandler.java:69)
... 47 more

or

Caused by: java.lang.IndexOutOfBoundsException: Index 1 out of bounds for length 1
	at java.base/jdk.internal.util.Preconditions.outOfBounds(Preconditions.java:64)
	at java.base/jdk.internal.util.Preconditions.outOfBoundsCheckIndex(Preconditions.java:70)
	at java.base/jdk.internal.util.Preconditions.checkIndex(Preconditions.java:248)
	at java.base/java.util.Objects.checkIndex(Objects.java:372)
	at java.base/java.util.ArrayList.get(ArrayList.java:458)
	at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.createUsingConstructor(DefaultResultSetHandler.java:669)
	at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.createByConstructorSignature(DefaultResultSetHandler.java:654)
	at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.createResultObject(DefaultResultSetHandler.java:618)
	at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.createResultObject(DefaultResultSetHandler.java:591)
	at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.getRowValue(DefaultResultSetHandler.java:397)
	at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleRowValuesForSimpleResultMap(DefaultResultSetHandler.java:354)
	at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleRowValues(DefaultResultSetHandler.java:328)
	at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleResultSet(DefaultResultSetHandler.java:301)
	at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleResultSets(DefaultResultSetHandler.java:194)
	at org.apache.ibatis.executor.statement.PreparedStatementHandler.query(PreparedStatementHandler.java:65)
	at org.apache.ibatis.executor.statement.RoutingStatementHandler.query(RoutingStatementHandler.java:79)
	at org.apache.ibatis.executor.SimpleExecutor.doQuery(SimpleExecutor.java:63)
	at org.apache.ibatis.executor.BaseExecutor.queryFromDatabase(BaseExecutor.java:324)
	at org.apache.ibatis.executor.BaseExecutor.query(BaseExecutor.java:156)
	at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:109)
	at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:83)
	at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:147)
	... 36 more

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions