001/* 002 * Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com). 003 * <p> 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * <p> 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * <p> 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package com.mybatisflex.core.mybatis; 017 018import com.mybatisflex.core.transaction.TransactionContext; 019import org.apache.ibatis.cursor.Cursor; 020import org.apache.ibatis.executor.Executor; 021import org.apache.ibatis.executor.parameter.ParameterHandler; 022import org.apache.ibatis.executor.resultset.ResultSetWrapper; 023import org.apache.ibatis.mapping.BoundSql; 024import org.apache.ibatis.mapping.MappedStatement; 025import org.apache.ibatis.mapping.ResultMap; 026import org.apache.ibatis.mapping.ResultMapping; 027import org.apache.ibatis.session.ResultHandler; 028import org.apache.ibatis.session.RowBounds; 029import org.apache.ibatis.type.TypeHandler; 030 031import java.sql.SQLException; 032import java.sql.Statement; 033import java.util.Iterator; 034import java.util.List; 035import java.util.Locale; 036 037/** 038 * @author michael 039 * 用于增强对 Cursor 查询处理,以及 List<String> 的自动映射问题 040 */ 041public class FlexResultSetHandler extends FlexDefaultResultSetHandler { 042 043 public FlexResultSetHandler(Executor executor, MappedStatement mappedStatement, ParameterHandler parameterHandler 044 , ResultHandler<?> resultHandler, BoundSql boundSql, RowBounds rowBounds) { 045 super(executor, mappedStatement, parameterHandler, resultHandler, boundSql, rowBounds); 046 } 047 048 049 /** 050 * 从写 handleCursorResultSets, 用于适配在事务下自动关闭 Cursor 051 */ 052 @Override 053 public <E> Cursor<E> handleCursorResultSets(Statement stmt) throws SQLException { 054 Cursor<E> defaultCursor = super.handleCursorResultSets(stmt); 055 056 //in transaction 057 if (TransactionContext.getXID() != null) { 058 return new FlexCursor<>(defaultCursor); 059 } 060 061 return defaultCursor; 062 } 063 064 065 /** 066 * 修复当实体类中存在 List<String> 或者 List<Integer> 等自动映射出错的问题 067 * 本质问题应该出现 mybatis 判断有误 068 * <p> 069 * https://gitee.com/mybatis-flex/mybatis-flex/issues/I7XBQS 070 * https://gitee.com/mybatis-flex/mybatis-flex/issues/I7X7G7 071 * 072 * @param rsw 073 * @param resultMap 074 * @param columnPrefix 075 * @throws SQLException 076 */ 077 @Override 078 protected Object createPrimitiveResultObject(ResultSetWrapper rsw, ResultMap resultMap, String columnPrefix) 079 throws SQLException { 080 final Class<?> resultType = resultMap.getType(); 081 if (!resultMap.getResultMappings().isEmpty()) { 082 final List<ResultMapping> resultMappingList = resultMap.getResultMappings(); 083 final ResultMapping mapping = resultMappingList.get(0); 084 String columnName = prependPrefix(mapping.getColumn(), columnPrefix); 085 TypeHandler<?> typeHandler = mapping.getTypeHandler(); 086 087 List<String> mappedColumnNames = rsw.getMappedColumnNames(resultMap, columnPrefix); 088 if (columnName != null && mappedColumnNames.contains(columnName.toUpperCase(Locale.ENGLISH))) { 089 return typeHandler.getResult(rsw.getResultSet(), columnName); 090 } 091 return null; 092 } else { 093 String columnName = rsw.getColumnNames().get(0); 094 TypeHandler<?> typeHandler = rsw.getTypeHandler(resultType, columnName); 095 return typeHandler.getResult(rsw.getResultSet(), columnName); 096 } 097 } 098 099 100 static class FlexCursor<T> implements Cursor<T> { 101 102 private final Cursor<T> originalCursor; 103 104 public FlexCursor(Cursor<T> cursor) { 105 this.originalCursor = cursor; 106 TransactionContext.holdCursor(cursor); 107 } 108 109 @Override 110 public void close() { 111 // do nothing,由 TransactionContext 去关闭 112 } 113 114 @Override 115 public boolean isOpen() { 116 return originalCursor.isOpen(); 117 } 118 119 @Override 120 public boolean isConsumed() { 121 return originalCursor.isConsumed(); 122 } 123 124 @Override 125 public int getCurrentIndex() { 126 return originalCursor.getCurrentIndex(); 127 } 128 129 @Override 130 public Iterator<T> iterator() { 131 return originalCursor.iterator(); 132 } 133 134 } 135 136}