### Question:
SelectForUpdateExecutor extends BaseTransactionalExecutor<T, S> { @Override public T doExecute(Object... args) throws Throwable { Connection conn = statementProxy.getConnection(); DatabaseMetaData dbmd = conn.getMetaData(); T rs; Savepoint sp = null; LockRetryController lockRetryController = new LockRetryController(); boolean originalAutoCommit = conn.getAutoCommit(); ArrayList<List<Object>> paramAppenderList = new ArrayList<>(); String selectPKSQL = buildSelectSQL(paramAppenderList); try { if (originalAutoCommit) { conn.setAutoCommit(false); } else if (dbmd.supportsSavepoints()) { sp = conn.setSavepoint(); } else { throw new SQLException("not support savepoint. please check your db version"); } while (true) { try { rs = statementCallback.execute(statementProxy.getTargetStatement(), args); TableRecords selectPKRows = buildTableRecords(getTableMeta(), selectPKSQL, paramAppenderList); String lockKeys = buildLockKey(selectPKRows); if (StringUtils.isNullOrEmpty(lockKeys)) { break; } if (RootContext.inGlobalTransaction()) { statementProxy.getConnectionProxy().checkLock(lockKeys); } else if (RootContext.requireGlobalLock()) { statementProxy.getConnectionProxy().appendLockKey(lockKeys); } else { throw new RuntimeException("Unknown situation!"); } break; } catch (LockConflictException lce) { if (sp != null) { conn.rollback(sp); } else { conn.rollback(); } lockRetryController.sleep(lce); } } } finally { if (sp != null) { try { conn.releaseSavepoint(sp); } catch (SQLException e) { if (LOGGER.isWarnEnabled()) { LOGGER.warn("{} does not support release save point, but this is not a error.", getDbType()); } } } if (originalAutoCommit) { conn.setAutoCommit(true); } } return rs; } SelectForUpdateExecutor(StatementProxy<S> statementProxy, StatementCallback<T, S> statementCallback,
                                   SQLRecognizer sqlRecognizer); @Override T doExecute(Object... args);  }### Answer:
@Test public void testDoExecute() throws Throwable { Assertions.assertThrows(RuntimeException.class, () -> selectForUpdateExecutor.doExecute((Object) null)); RootContext.bind("xid"); Assertions.assertDoesNotThrow(() -> { selectForUpdateExecutor.doExecute((Object) null); }); RootContext.unbind(); RootContext.bindGlobalLockFlag(); Assertions.assertDoesNotThrow(() -> { selectForUpdateExecutor.doExecute((Object) null); }); RootContext.unbindGlobalLockFlag(); connectionProxy = new MockLockConflictConnectionProxy(connectionProxy.getDataSourceProxy(), connectionProxy.getTargetConnection()); statementProxy = new StatementProxy(connectionProxy, statementProxy.getTargetStatement()); statementProxy.getTargetStatement().getConnection().setAutoCommit(false); String sql = "select * from dual"; List<SQLStatement> asts = SQLUtils.parseStatements(sql, JdbcConstants.MYSQL); MySQLSelectForUpdateRecognizer recognizer = new MySQLSelectForUpdateRecognizer(sql, asts.get(0)); selectForUpdateExecutor = new SelectForUpdateExecutor(statementProxy, (statement, args) -> null, recognizer); RootContext.bind("xid"); Assertions.assertThrows(LockWaitTimeoutException.class, () -> selectForUpdateExecutor.doExecute((Object) null)); RootContext.unbind(); }