JdbcTransaction.java

  1. /*
  2.  *    Copyright 2009-2024 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.apache.ibatis.transaction.jdbc;

  17. import java.sql.Connection;
  18. import java.sql.SQLException;

  19. import javax.sql.DataSource;

  20. import org.apache.ibatis.logging.Log;
  21. import org.apache.ibatis.logging.LogFactory;
  22. import org.apache.ibatis.session.TransactionIsolationLevel;
  23. import org.apache.ibatis.transaction.Transaction;
  24. import org.apache.ibatis.transaction.TransactionException;

  25. /**
  26.  * {@link Transaction} that makes use of the JDBC commit and rollback facilities directly. It relies on the connection
  27.  * retrieved from the dataSource to manage the scope of the transaction. Delays connection retrieval until
  28.  * getConnection() is called. Ignores commit or rollback requests when autocommit is on.
  29.  *
  30.  * @author Clinton Begin
  31.  *
  32.  * @see JdbcTransactionFactory
  33.  */
  34. public class JdbcTransaction implements Transaction {

  35.   private static final Log log = LogFactory.getLog(JdbcTransaction.class);

  36.   protected Connection connection;
  37.   protected DataSource dataSource;
  38.   protected TransactionIsolationLevel level;
  39.   protected boolean autoCommit;
  40.   protected boolean skipSetAutoCommitOnClose;

  41.   public JdbcTransaction(DataSource ds, TransactionIsolationLevel desiredLevel, boolean desiredAutoCommit) {
  42.     this(ds, desiredLevel, desiredAutoCommit, false);
  43.   }

  44.   public JdbcTransaction(DataSource ds, TransactionIsolationLevel desiredLevel, boolean desiredAutoCommit,
  45.       boolean skipSetAutoCommitOnClose) {
  46.     dataSource = ds;
  47.     level = desiredLevel;
  48.     autoCommit = desiredAutoCommit;
  49.     this.skipSetAutoCommitOnClose = skipSetAutoCommitOnClose;
  50.   }

  51.   public JdbcTransaction(Connection connection) {
  52.     this.connection = connection;
  53.   }

  54.   @Override
  55.   public Connection getConnection() throws SQLException {
  56.     if (connection == null) {
  57.       openConnection();
  58.     }
  59.     return connection;
  60.   }

  61.   @Override
  62.   public void commit() throws SQLException {
  63.     if (connection != null && !connection.getAutoCommit()) {
  64.       if (log.isDebugEnabled()) {
  65.         log.debug("Committing JDBC Connection [" + connection + "]");
  66.       }
  67.       connection.commit();
  68.     }
  69.   }

  70.   @Override
  71.   public void rollback() throws SQLException {
  72.     if (connection != null && !connection.getAutoCommit()) {
  73.       if (log.isDebugEnabled()) {
  74.         log.debug("Rolling back JDBC Connection [" + connection + "]");
  75.       }
  76.       connection.rollback();
  77.     }
  78.   }

  79.   @Override
  80.   public void close() throws SQLException {
  81.     if (connection != null) {
  82.       resetAutoCommit();
  83.       if (log.isDebugEnabled()) {
  84.         log.debug("Closing JDBC Connection [" + connection + "]");
  85.       }
  86.       connection.close();
  87.     }
  88.   }

  89.   protected void setDesiredAutoCommit(boolean desiredAutoCommit) {
  90.     try {
  91.       if (connection.getAutoCommit() != desiredAutoCommit) {
  92.         if (log.isDebugEnabled()) {
  93.           log.debug("Setting autocommit to " + desiredAutoCommit + " on JDBC Connection [" + connection + "]");
  94.         }
  95.         connection.setAutoCommit(desiredAutoCommit);
  96.       }
  97.     } catch (SQLException e) {
  98.       // Only a very poorly implemented driver would fail here,
  99.       // and there's not much we can do about that.
  100.       throw new TransactionException(
  101.           "Error configuring AutoCommit.  " + "Your driver may not support getAutoCommit() or setAutoCommit(). "
  102.               + "Requested setting: " + desiredAutoCommit + ".  Cause: " + e,
  103.           e);
  104.     }
  105.   }

  106.   protected void resetAutoCommit() {
  107.     try {
  108.       if (!skipSetAutoCommitOnClose && !connection.getAutoCommit()) {
  109.         // MyBatis does not call commit/rollback on a connection if just selects were performed.
  110.         // Some databases start transactions with select statements
  111.         // and they mandate a commit/rollback before closing the connection.
  112.         // A workaround is setting the autocommit to true before closing the connection.
  113.         // Sybase throws an exception here.
  114.         if (log.isDebugEnabled()) {
  115.           log.debug("Resetting autocommit to true on JDBC Connection [" + connection + "]");
  116.         }
  117.         connection.setAutoCommit(true);
  118.       }
  119.     } catch (SQLException e) {
  120.       if (log.isDebugEnabled()) {
  121.         log.debug("Error resetting autocommit to true " + "before closing the connection.  Cause: " + e);
  122.       }
  123.     }
  124.   }

  125.   protected void openConnection() throws SQLException {
  126.     if (log.isDebugEnabled()) {
  127.       log.debug("Opening JDBC Connection");
  128.     }
  129.     connection = dataSource.getConnection();
  130.     if (level != null) {
  131.       connection.setTransactionIsolation(level.getLevel());
  132.     }
  133.     setDesiredAutoCommit(autoCommit);
  134.   }

  135.   @Override
  136.   public Integer getTimeout() throws SQLException {
  137.     return null;
  138.   }

  139. }