Why System.out.println() Can Kill Your MyBatis Performance and How to Fix It

This article explains why MyBatis's default StdOutImpl logging, which relies on System.out.println, blocks threads and creates severe concurrency bottlenecks, and demonstrates how to replace it with asynchronous logging implementations like Slf4jImpl, configure log levels, and even create custom Log classes for optimal performance.

Java Architect Essentials
Java Architect Essentials
Java Architect Essentials
Why System.out.println() Can Kill Your MyBatis Performance and How to Fix It

When using MyBatis or its derivatives, we often enable the default log output to troubleshoot issues via SQL logs. However, MyBatis logs lack timestamps, levels, and are left‑aligned because they use a class called StdOutImpl that prints directly to System.out.println().

Printing with System.out.println() blocks the current thread, causing SQL queries to wait for the log output to finish before returning results. This is why most articles recommend using a Log implementation instead of System.out.println(), as Log is asynchronous.

Worse Situation

Slow interface responses and high CPU usage can make the system almost unusable. Using jstack may reveal many web threads waiting to acquire the lock on java.io.PrintStream. The println() method synchronizes on the global System.out PrintStream, causing all threads to queue their SQL logs, leading to severe concurrency performance problems, especially with bulk inserts or data exports.

How to Optimize

Built‑in Log Implementations

MyBatis provides other logging implementations. Replacing StdOutImpl with Slf4jImpl solves the performance issue and allows unified formatting and output locations.

<configuration>
  <settings>
    <setting name="logImpl" value="SLF4J"/>
  </settings>
</configuration>

For MyBatis‑Plus:

mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.slf4j.Slf4jImpl

For MyBatis Flex:

@Configuration
public class MyBatisFlexConfig implements ConfigurationCustomizer {
    @Override
    public void customize(FlexConfiguration config) {
        // Use Slf4j for logging
        config.setLogImpl(Slf4jImpl.class);
    }
}

Note that the MyBatis Log interface does not define an info level; it only provides debug, trace, warn, and error methods. To enable detailed logging, configure the logger level (e.g., TRACE) in your logging framework.

Custom Log Implementation

You can implement your own Log that outputs at the info level:

public class MyBatisLogImpl implements Log {
    private final Logger log;
    public MyBatisLogImpl(String clazz) {
        log = LoggerFactory.getLogger(clazz);
        System.out.println(clazz);
    }
    @Override public boolean isDebugEnabled() { return true; }
    @Override public boolean isTraceEnabled() { return true; }
    @Override public void error(String s, Throwable e) { log.error(s, e); }
    @Override public void error(String s) { log.error(s); }
    @Override public void debug(String s) { log.info(s); }
    @Override public void trace(String s) { log.info(s); }
    @Override public void warn(String s) { log.warn(s); }
}

MyBatis also logs some debug messages that are often unnecessary, such as session creation logs. These can be filtered out in the logging configuration, for example:

<!-- Exclude all logs from SqlSessionUtils -->
<logger name="org.mybatis.spring.SqlSessionUtils" level="OFF"/>

Conclusion

System.out.println()

is a far worse logging method than expected; it should be avoided not only in MyBatis (where StdOutImpl uses it) but in any system. Relying on unformatted System.out output can cause thread blocking and severe concurrency performance degradation.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaconcurrencyloggingMyBatisslf4jsystem.out.println
Java Architect Essentials
Written by

Java Architect Essentials

Committed to sharing quality articles and tutorials to help Java programmers progress from junior to mid-level to senior architect. We curate high-quality learning resources, interview questions, videos, and projects from across the internet to help you systematically improve your Java architecture skills. Follow and reply '1024' to get Java programming resources. Learn together, grow together.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.