• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mybatis / spring / 1857

21 May 2026 09:57PM UTC coverage: 90.353% (+0.02%) from 90.335%
1857

Pull #1144

github

web-flow
Merge c52fd48ed into c4b5c8257
Pull Request #1144: Improve transaction state detection logic

324 of 386 branches covered (83.94%)

3 of 4 new or added lines in 1 file covered. (75.0%)

946 of 1047 relevant lines covered (90.35%)

0.9 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

93.33
/src/main/java/org/mybatis/spring/transaction/SpringManagedTransaction.java
1
/*
2
 * Copyright 2010-2026 the original author or authors.
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *    https://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
package org.mybatis.spring.transaction;
17

18
import static org.springframework.util.Assert.notNull;
19

20
import java.sql.Connection;
21
import java.sql.SQLException;
22

23
import javax.sql.DataSource;
24

25
import org.apache.ibatis.transaction.Transaction;
26
import org.mybatis.logging.Logger;
27
import org.mybatis.logging.LoggerFactory;
28
import org.springframework.jdbc.datasource.ConnectionHolder;
29
import org.springframework.jdbc.datasource.DataSourceUtils;
30
import org.springframework.transaction.support.TransactionSynchronizationManager;
31

32
/**
33
 * {@code SpringManagedTransaction} handles the lifecycle of a JDBC connection. It retrieves a connection from Spring's
34
 * transaction manager and returns it back to it when it is no longer needed.
35
 * <p>
36
 * If Spring's transaction handling is active it will no-op all commit/rollback/close calls assuming that the Spring
37
 * transaction manager will do the job.
38
 * <p>
39
 * If it is not it will behave like {@code JdbcTransaction}.
40
 *
41
 * @author Hunter Presnall
42
 * @author Eduardo Macarron
43
 */
44
public class SpringManagedTransaction implements Transaction {
45

46
  private static final Logger LOGGER = LoggerFactory.getLogger(SpringManagedTransaction.class);
1✔
47

48
  private final DataSource dataSource;
49

50
  private Connection connection;
51

52
  private boolean isConnectionTransactional;
53

54
  private boolean autoCommit;
55

56
  /**
57
   * Instantiates a new spring managed transaction.
58
   *
59
   * @param dataSource
60
   *          the data source
61
   */
62
  public SpringManagedTransaction(DataSource dataSource) {
1✔
63
    notNull(dataSource, "No DataSource specified");
1✔
64
    this.dataSource = dataSource;
1✔
65
  }
1✔
66

67
  @Override
68
  public Connection getConnection() throws SQLException {
69
    if (this.connection == null) {
1✔
70
      openConnection();
1✔
71
    }
72
    return this.connection;
1✔
73
  }
74

75
  /**
76
   * Gets a connection from Spring transaction manager and discovers if this {@code Transaction} should manage
77
   * connection or let it to Spring.
78
   * <p>
79
   * It also reads autocommit setting because when using Spring Transaction MyBatis thinks that autocommit is always
80
   * false and will always call commit/rollback so we need to no-op that calls.
81
   */
82
  private void openConnection() throws SQLException {
83
    this.connection = DataSourceUtils.getConnection(this.dataSource);
1✔
84
    this.autoCommit = this.connection.getAutoCommit();
1✔
85

86
    boolean isInActiveTransaction = TransactionSynchronizationManager.isActualTransactionActive();
1✔
87
    this.isConnectionTransactional = isInActiveTransaction &&
1✔
88
      DataSourceUtils.isConnectionTransactional(this.connection, this.dataSource);
1!
89

90
    LOGGER.debug(() -> "JDBC Connection [" + this.connection + "] will"
1✔
NEW
91
      + (this.isConnectionTransactional ? " " : " not ") + "be managed by Spring");
×
92
  }
1✔
93

94
  @Override
95
  public void commit() throws SQLException {
96
    if (this.connection != null && !this.isConnectionTransactional && !this.autoCommit) {
1!
97
      LOGGER.debug(() -> "Committing JDBC Connection [" + this.connection + "]");
1✔
98
      this.connection.commit();
1✔
99
    }
100
  }
1✔
101

102
  @Override
103
  public void rollback() throws SQLException {
104
    if (this.connection != null && !this.isConnectionTransactional && !this.autoCommit) {
1!
105
      LOGGER.debug(() -> "Rolling back JDBC Connection [" + this.connection + "]");
1✔
106
      this.connection.rollback();
1✔
107
    }
108
  }
1✔
109

110
  @Override
111
  public void close() throws SQLException {
112
    DataSourceUtils.releaseConnection(this.connection, this.dataSource);
1✔
113
  }
1✔
114

115
  @Override
116
  public Integer getTimeout() throws SQLException {
117
    var holder = (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);
1✔
118
    if (holder != null && holder.hasTimeout()) {
1!
119
      return holder.getTimeToLiveInSeconds();
×
120
    }
121
    return null;
1✔
122
  }
123

124
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc