iBatis for Java [READ ONLY]
  1. iBatis for Java [READ ONLY]
  2. IBATIS-770

remapResults is thread-unsafe (The value is set to wrong property)

    Details

    • Type: Bug Bug
    • Status: Open
    • Priority: Critical Critical
    • Resolution: Unresolved
    • Affects Version/s: 2.3.0, 2.3.1, 2.3.2, 2.3.3, 2.3.4
    • Fix Version/s: None
    • Component/s: Core
    • Labels:
      None

      Description

      When remapResults is true, The value is set to wrong property, sometimes.
      The attached sample program can reproduce it.
      remapResults is thread-unsafe.

      This problem occurs when
      remapResults="true" is really necessary to SQL(column is dynamic).

        Activity

        Hide
        Naozumi Taromaru added a comment -

        <<Result of my survey>>
        com.ibatis.sqlmap.engine.mapping.result.ResultMap#dataExchange
        is thread-unsafe.(The same field of IBATIS-519 is a cause.)

        By correcting IBATIS-519,
        com.ibatis.sqlmap.engine.mapping.result.ResultMap#setResultMappingList (dataExchange initialize)
        and
        com.ibatis.sqlmap.engine.mapping.result.ResultMap#setResultObjectValues (dataExchange.setData)
        became not executed at the same time.

        However,
        the above-mentioned two methods exist in independent synchronized blocks.

        For example, SqlExecutor#handleResults...
        [SqlExecutor(l.384)] Object[] columnValues = resultMap.resolveSubMap(statementScope, rs).getResults(statementScope, rs);
        [SqlExecutor(l.385)] callback.handleResultObject(statementScope, columnValues, rs);

        SqlExecutor#handleResults (l.384)
        synchronized (lock: AutoResultMap instance)
        ->AutoResultMap#getResults
        ->AutoResultMap#initialize
        ->AutoResultMap#initializeBeanResults
        ->ResultMap#setResultMappingList (dataExchange initialize)

        SqlExecutor#handleResults (l.385)
        ->RowHandlerCallback#handleResultObject
        ->AutoResultMap#setResultObjectValues
        synchronized (lock: AutoResultMap instance)
        ->ResultMap#setResultObjectValues (dataExchange.setData)

        Therefore, the following issue occur.

        Thread-1's SQL: SELECT columun1 as prop1 FROM foo;
        Thread-2's SQL: SELECT columun2 as prop2 FROM foo;
        (column is dynamic)

        [Thread-1] execute SqlExecutor#handleResults (l.384)
        ResultMap#dataExchange: 1st value should be set in prop1
        returned columnValues =

        {Value that should be set in prop1}

        [Thread-2] execute SqlExecutor#handleResults (l.384)
        ResultMap#dataExchange: 1st value should be set in prop2
        returned columnValues = {Value that should be set in prop2}

        [Thread-1] execute SqlExecutor#handleResults (l.385)
        {Value that should be set in prop1}

        set to prop2
        according to

        {ResultMap#dataExchange: 1st value should be set in prop2}

        .

        <<About the bug fix>>
        If line 384-385 of SqlExecutor#handleResults are in a synchronized block,
        I think that synchronized lock time bocomes too long.

        I think that ResultMap#dataExchange should be
        changed to ThreadLocal(like ResultMap#remappableResultMappings).

        Show
        Naozumi Taromaru added a comment - <<Result of my survey>> com.ibatis.sqlmap.engine.mapping.result.ResultMap#dataExchange is thread-unsafe.(The same field of IBATIS-519 is a cause.) By correcting IBATIS-519 , com.ibatis.sqlmap.engine.mapping.result.ResultMap#setResultMappingList (dataExchange initialize) and com.ibatis.sqlmap.engine.mapping.result.ResultMap#setResultObjectValues (dataExchange.setData) became not executed at the same time. However, the above-mentioned two methods exist in independent synchronized blocks. For example, SqlExecutor#handleResults... [SqlExecutor(l.384)] Object[] columnValues = resultMap.resolveSubMap(statementScope, rs).getResults(statementScope, rs); [SqlExecutor(l.385)] callback.handleResultObject(statementScope, columnValues, rs); SqlExecutor#handleResults (l.384) synchronized (lock: AutoResultMap instance) ->AutoResultMap#getResults ->AutoResultMap#initialize ->AutoResultMap#initializeBeanResults ->ResultMap#setResultMappingList (dataExchange initialize) SqlExecutor#handleResults (l.385) ->RowHandlerCallback#handleResultObject ->AutoResultMap#setResultObjectValues synchronized (lock: AutoResultMap instance) ->ResultMap#setResultObjectValues (dataExchange.setData) Therefore, the following issue occur. Thread-1's SQL: SELECT columun1 as prop1 FROM foo; Thread-2's SQL: SELECT columun2 as prop2 FROM foo; (column is dynamic) [Thread-1] execute SqlExecutor#handleResults (l.384) ResultMap#dataExchange: 1st value should be set in prop1 returned columnValues = {Value that should be set in prop1} [Thread-2] execute SqlExecutor#handleResults (l.384) ResultMap#dataExchange: 1st value should be set in prop2 returned columnValues = {Value that should be set in prop2} [Thread-1] execute SqlExecutor#handleResults (l.385) {Value that should be set in prop1} set to prop2 according to {ResultMap#dataExchange: 1st value should be set in prop2} . <<About the bug fix>> If line 384-385 of SqlExecutor#handleResults are in a synchronized block, I think that synchronized lock time bocomes too long. I think that ResultMap#dataExchange should be changed to ThreadLocal(like ResultMap#remappableResultMappings).
        Hide
        Naozumi Taromaru added a comment -

        iBATIS stand-alone test program

        Show
        Naozumi Taromaru added a comment - iBATIS stand-alone test program

          People

          • Assignee:
            Unassigned
            Reporter:
            Naozumi Taromaru
          • Votes:
            1 Vote for this issue
            Watchers:
            1 Start watching this issue

            Dates

            • Created:
              Updated:

              Development