Преглед изворни кода

替换执行器,支持query,update返回null.

聂秋秋 пре 6 година
родитељ
комит
b05e3d4bdc

+ 4 - 5
mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/MybatisConfiguration.java

@@ -16,15 +16,15 @@
 package com.baomidou.mybatisplus.core;
 
 import com.baomidou.mybatisplus.core.config.GlobalConfig;
+import com.baomidou.mybatisplus.core.executor.MybatisBatchExecutor;
+import com.baomidou.mybatisplus.core.executor.MybatisReuseExecutor;
 import com.baomidou.mybatisplus.core.executor.MybatisSimpleExecutor;
 import com.baomidou.mybatisplus.core.toolkit.GlobalConfigUtils;
 import lombok.Getter;
 import lombok.Setter;
 import org.apache.ibatis.binding.MapperRegistry;
-import org.apache.ibatis.executor.BatchExecutor;
 import org.apache.ibatis.executor.CachingExecutor;
 import org.apache.ibatis.executor.Executor;
-import org.apache.ibatis.executor.ReuseExecutor;
 import org.apache.ibatis.logging.Log;
 import org.apache.ibatis.logging.LogFactory;
 import org.apache.ibatis.mapping.Environment;
@@ -156,11 +156,10 @@ public class MybatisConfiguration extends Configuration {
         executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
         Executor executor;
         if (ExecutorType.BATCH == executorType) {
-            executor = new BatchExecutor(this, transaction);
+            executor = new MybatisBatchExecutor(this, transaction);
         } else if (ExecutorType.REUSE == executorType) {
-            executor = new ReuseExecutor(this, transaction);
+            executor = new MybatisReuseExecutor(this, transaction);
         } else {
-            //todo 这里我替换了执行器
             executor = new MybatisSimpleExecutor(this, transaction);
         }
         if (cacheEnabled) {

+ 175 - 0
mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/executor/MybatisBatchExecutor.java

@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 2011-2019, hubin (jobob@qq.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * <p>
+ * https://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.baomidou.mybatisplus.core.executor;
+
+import org.apache.ibatis.cursor.Cursor;
+import org.apache.ibatis.executor.BaseExecutor;
+import org.apache.ibatis.executor.BatchExecutorException;
+import org.apache.ibatis.executor.BatchResult;
+import org.apache.ibatis.executor.keygen.Jdbc3KeyGenerator;
+import org.apache.ibatis.executor.keygen.KeyGenerator;
+import org.apache.ibatis.executor.keygen.NoKeyGenerator;
+import org.apache.ibatis.executor.statement.StatementHandler;
+import org.apache.ibatis.mapping.BoundSql;
+import org.apache.ibatis.mapping.MappedStatement;
+import org.apache.ibatis.session.Configuration;
+import org.apache.ibatis.session.ResultHandler;
+import org.apache.ibatis.session.RowBounds;
+import org.apache.ibatis.transaction.Transaction;
+
+import java.sql.BatchUpdateException;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * 重写执行器
+ * {@link org.apache.ibatis.executor.BatchExecutor}
+ *
+ * @author nieqiurong 2019/4/14.
+ */
+public class MybatisBatchExecutor extends BaseExecutor {
+    public static final int BATCH_UPDATE_RETURN_VALUE = Integer.MIN_VALUE + 1002;
+    
+    private final List<Statement> statementList = new ArrayList<>();
+    private final List<BatchResult> batchResultList = new ArrayList<>();
+    private String currentSql;
+    private MappedStatement currentStatement;
+    
+    public MybatisBatchExecutor(Configuration configuration, Transaction transaction) {
+        super(configuration, transaction);
+    }
+    
+    @Override
+    public int doUpdate(MappedStatement ms, Object parameterObject) throws SQLException {
+        final Configuration configuration = ms.getConfiguration();
+        final StatementHandler handler = configuration.newStatementHandler(this, ms, parameterObject, RowBounds.DEFAULT, null, null);
+        final BoundSql boundSql = handler.getBoundSql();
+        final String sql = boundSql.getSql();
+        final Statement stmt;
+        if (sql.equals(currentSql) && ms.equals(currentStatement)) {
+            int last = statementList.size() - 1;
+            stmt = statementList.get(last);
+            applyTransactionTimeout(stmt);
+            handler.parameterize(stmt);//fix Issues 322
+            BatchResult batchResult = batchResultList.get(last);
+            batchResult.addParameterObject(parameterObject);
+        } else {
+            Connection connection = getConnection(ms.getStatementLog());
+            stmt = handler.prepare(connection, transaction.getTimeout());
+            if (stmt == null) {
+                return 0;
+            }
+            handler.parameterize(stmt);    //fix Issues 322
+            currentSql = sql;
+            currentStatement = ms;
+            statementList.add(stmt);
+            batchResultList.add(new BatchResult(ms, sql, parameterObject));
+        }
+        handler.batch(stmt);
+        return BATCH_UPDATE_RETURN_VALUE;
+    }
+    
+    @Override
+    public <E> List<E> doQuery(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql)
+        throws SQLException {
+        Statement stmt = null;
+        try {
+            flushStatements();
+            Configuration configuration = ms.getConfiguration();
+            StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameterObject, rowBounds, resultHandler, boundSql);
+            Connection connection = getConnection(ms.getStatementLog());
+            stmt = handler.prepare(connection, transaction.getTimeout());
+            if (stmt == null) {
+                return Collections.emptyList();
+            }
+            handler.parameterize(stmt);
+            return handler.query(stmt, resultHandler);
+        } finally {
+            closeStatement(stmt);
+        }
+    }
+    
+    @Override
+    protected <E> Cursor<E> doQueryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds, BoundSql boundSql) throws SQLException {
+        flushStatements();
+        Configuration configuration = ms.getConfiguration();
+        StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, null, boundSql);
+        Connection connection = getConnection(ms.getStatementLog());
+        //游标不支持返回null
+        Statement stmt = handler.prepare(connection, transaction.getTimeout());
+        stmt.closeOnCompletion();
+        handler.parameterize(stmt);
+        return handler.queryCursor(stmt);
+    }
+    
+    @Override
+    public List<BatchResult> doFlushStatements(boolean isRollback) throws SQLException {
+        try {
+            List<BatchResult> results = new ArrayList<>();
+            if (isRollback) {
+                return Collections.emptyList();
+            }
+            for (int i = 0, n = statementList.size(); i < n; i++) {
+                Statement stmt = statementList.get(i);
+                applyTransactionTimeout(stmt);
+                BatchResult batchResult = batchResultList.get(i);
+                try {
+                    batchResult.setUpdateCounts(stmt.executeBatch());
+                    MappedStatement ms = batchResult.getMappedStatement();
+                    List<Object> parameterObjects = batchResult.getParameterObjects();
+                    KeyGenerator keyGenerator = ms.getKeyGenerator();
+                    if (Jdbc3KeyGenerator.class.equals(keyGenerator.getClass())) {
+                        Jdbc3KeyGenerator jdbc3KeyGenerator = (Jdbc3KeyGenerator) keyGenerator;
+                        jdbc3KeyGenerator.processBatch(ms, stmt, parameterObjects);
+                    } else if (!NoKeyGenerator.class.equals(keyGenerator.getClass())) { //issue #141
+                        for (Object parameter : parameterObjects) {
+                            keyGenerator.processAfter(this, ms, stmt, parameter);
+                        }
+                    }
+                    // Close statement to close cursor #1109
+                    closeStatement(stmt);
+                } catch (BatchUpdateException e) {
+                    StringBuilder message = new StringBuilder();
+                    message.append(batchResult.getMappedStatement().getId())
+                        .append(" (batch index #")
+                        .append(i + 1)
+                        .append(")")
+                        .append(" failed.");
+                    if (i > 0) {
+                        message.append(" ")
+                            .append(i)
+                            .append(" prior sub executor(s) completed successfully, but will be rolled back.");
+                    }
+                    throw new BatchExecutorException(message.toString(), e, results, batchResult);
+                }
+                results.add(batchResult);
+            }
+            return results;
+        } finally {
+            for (Statement stmt : statementList) {
+                closeStatement(stmt);
+            }
+            currentSql = null;
+            statementList.clear();
+            batchResultList.clear();
+        }
+    }
+}

+ 121 - 0
mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/executor/MybatisReuseExecutor.java

@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2011-2019, hubin (jobob@qq.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * <p>
+ * https://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.baomidou.mybatisplus.core.executor;
+
+import org.apache.ibatis.cursor.Cursor;
+import org.apache.ibatis.executor.BaseExecutor;
+import org.apache.ibatis.executor.BatchResult;
+import org.apache.ibatis.executor.statement.StatementHandler;
+import org.apache.ibatis.logging.Log;
+import org.apache.ibatis.mapping.BoundSql;
+import org.apache.ibatis.mapping.MappedStatement;
+import org.apache.ibatis.session.Configuration;
+import org.apache.ibatis.session.ResultHandler;
+import org.apache.ibatis.session.RowBounds;
+import org.apache.ibatis.transaction.Transaction;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 重写执行器
+ * {@link org.apache.ibatis.executor.ReuseExecutor}
+ *
+ * @author nieqiurong 2019/4/14.
+ */
+public class MybatisReuseExecutor extends BaseExecutor {
+    
+    private final Map<String, Statement> statementMap = new HashMap<>();
+    
+    public MybatisReuseExecutor(Configuration configuration, Transaction transaction) {
+        super(configuration, transaction);
+    }
+    
+    @Override
+    public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
+        Configuration configuration = ms.getConfiguration();
+        StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null);
+        Statement stmt = prepareStatement(handler, ms.getStatementLog(), false);
+        return stmt == null ? 0 : handler.update(stmt);
+    }
+    
+    @Override
+    public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
+        Configuration configuration = ms.getConfiguration();
+        StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
+        Statement stmt = prepareStatement(handler, ms.getStatementLog(), false);
+        return stmt == null ? Collections.emptyList() : handler.query(stmt, resultHandler);
+    }
+    
+    @Override
+    protected <E> Cursor<E> doQueryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds, BoundSql boundSql) throws SQLException {
+        Configuration configuration = ms.getConfiguration();
+        StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, null, boundSql);
+        Statement stmt = prepareStatement(handler, ms.getStatementLog(), true);
+        return handler.queryCursor(stmt);
+    }
+    
+    @Override
+    public List<BatchResult> doFlushStatements(boolean isRollback) {
+        for (Statement stmt : statementMap.values()) {
+            closeStatement(stmt);
+        }
+        statementMap.clear();
+        return Collections.emptyList();
+    }
+    
+    private Statement prepareStatement(StatementHandler handler, Log statementLog, boolean isCursor) throws SQLException {
+        Statement stmt;
+        BoundSql boundSql = handler.getBoundSql();
+        String sql = boundSql.getSql();
+        if (hasStatementFor(sql)) {
+            stmt = getStatement(sql);
+            applyTransactionTimeout(stmt);
+        } else {
+            Connection connection = getConnection(statementLog);
+            stmt = handler.prepare(connection, transaction.getTimeout());
+            //游标不支持返回null.
+            if (stmt == null && !isCursor) {
+                return null;
+            }
+            putStatement(sql, stmt);
+        }
+        handler.parameterize(stmt);
+        return stmt;
+    }
+    
+    private boolean hasStatementFor(String sql) {
+        try {
+            return statementMap.keySet().contains(sql) && !statementMap.get(sql).getConnection().isClosed();
+        } catch (SQLException e) {
+            return false;
+        }
+    }
+    
+    private Statement getStatement(String s) {
+        return statementMap.get(s);
+    }
+    
+    private void putStatement(String sql, Statement stmt) {
+        statementMap.put(sql, stmt);
+    }
+}

+ 51 - 9
mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/executor/MybatisSimpleExecutor.java

@@ -16,8 +16,11 @@
 
 package com.baomidou.mybatisplus.core.executor;
 
-import org.apache.ibatis.executor.SimpleExecutor;
+import org.apache.ibatis.cursor.Cursor;
+import org.apache.ibatis.executor.BaseExecutor;
+import org.apache.ibatis.executor.BatchResult;
 import org.apache.ibatis.executor.statement.StatementHandler;
+import org.apache.ibatis.logging.Log;
 import org.apache.ibatis.mapping.BoundSql;
 import org.apache.ibatis.mapping.MappedStatement;
 import org.apache.ibatis.session.Configuration;
@@ -33,31 +36,70 @@ import java.util.List;
 
 /**
  * 重写执行器
+ * {@link org.apache.ibatis.executor.SimpleExecutor}
  *
  * @author nieqiurong 2019/4/14.
  */
-public class MybatisSimpleExecutor extends SimpleExecutor {
+public class MybatisSimpleExecutor extends BaseExecutor {
     
     public MybatisSimpleExecutor(Configuration configuration, Transaction transaction) {
         super(configuration, transaction);
     }
     
+    @Override
+    public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
+        Statement stmt = null;
+        try {
+            Configuration configuration = ms.getConfiguration();
+            StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null);
+            stmt = prepareStatement(handler, ms.getStatementLog(), false);
+            return stmt == null ? 0 : handler.update(stmt);
+        } finally {
+            closeStatement(stmt);
+        }
+    }
+    
     @Override
     public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
         Statement stmt = null;
         try {
             Configuration configuration = ms.getConfiguration();
             StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
-            Connection connection = getConnection(ms.getStatementLog());
-            stmt = handler.prepare(connection, transaction.getTimeout());
-            if (stmt == null) {
-                return Collections.emptyList();
-            }
-            handler.parameterize(stmt);
-            return handler.query(stmt, resultHandler);
+            stmt = prepareStatement(handler, ms.getStatementLog(), false);
+            return stmt == null ? Collections.emptyList() : handler.query(stmt, resultHandler);
         } finally {
             closeStatement(stmt);
         }
     }
     
+    @Override
+    protected <E> Cursor<E> doQueryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds, BoundSql boundSql) throws SQLException {
+        Configuration configuration = ms.getConfiguration();
+        StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, null, boundSql);
+        Statement stmt = prepareStatement(handler, ms.getStatementLog(), true);
+        if (stmt != null) {
+            stmt.closeOnCompletion();
+            return handler.queryCursor(stmt);
+        } else {
+            return null;
+        }
+    }
+    
+    @Override
+    public List<BatchResult> doFlushStatements(boolean isRollback) {
+        return Collections.emptyList();
+    }
+    
+    private Statement prepareStatement(StatementHandler handler, Log statementLog, boolean isCursor) throws SQLException {
+        Statement stmt;
+        Connection connection = getConnection(statementLog);
+        stmt = handler.prepare(connection, transaction.getTimeout());
+        //游标不支持返回null.
+        if (stmt == null && !isCursor) {
+            return null;
+        } else {
+            handler.parameterize(stmt);
+            return stmt;
+        }
+    }
 }