View Javadoc

1   package org.apache.torque.util;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.sql.Connection;
23  import java.sql.SQLException;
24  
25  import org.apache.commons.logging.Log;
26  import org.apache.commons.logging.LogFactory;
27  
28  import org.apache.torque.Torque;
29  import org.apache.torque.TorqueException;
30  
31  /***
32   * Refactored begin/commit/rollback transaction methods away from
33   * the <code>BasePeer</code>.
34   *
35   * <p>
36   * This can be used to handle cases where transaction support is optional.
37   * The second parameter of beginOptionalTransaction will determine with a
38   * transaction is used or not.
39   * If a transaction is not used, the commit and rollback methods
40   * do not have any effect. Instead it simply makes the logic easier to follow
41   * by cutting down on the if statements based solely on whether a transaction
42   * is needed or not.
43   *
44   * @author <a href="mailto:stephenh@chase3000.com">Stephen Haberman</a>
45   * @version $Id: Transaction.java 476550 2006-11-18 16:08:37Z tfischer $
46   */
47  public final class Transaction
48  {
49  
50      /*** The log. */
51      private static Log log = LogFactory.getLog(Transaction.class);
52  
53      /***
54       * Private constructor to prevent instantiation.
55       *
56       * Class contains only static method ans should therefore not be
57       * instantiated.
58       */
59      private Transaction()
60      {
61      }
62  
63      /***
64       * Begin a transaction for the default database.
65       * This method will fallback gracefully to
66       * return a normal connection, if the database being accessed does
67       * not support transactions.
68       *
69       * @return The Connection for the transaction.
70       * @throws TorqueException Any exceptions caught during processing will be
71       *         rethrown wrapped into a TorqueException.
72       */
73      public static Connection begin() throws TorqueException
74      {
75          return Transaction.begin(Torque.getDefaultDB());
76      }
77  
78      /***
79       * Begin a transaction.  This method will fallback gracefully to
80       * return a normal connection, if the database being accessed does
81       * not support transactions.
82       *
83       * @param dbName Name of database.
84       * @return The Connection for the transaction.
85       * @throws TorqueException Any exceptions caught during processing will be
86       *         rethrown wrapped into a TorqueException.
87       */
88      public static Connection begin(String dbName) throws TorqueException
89      {
90          return Transaction.beginOptional(dbName, true);
91      }
92  
93      /***
94       * Begin a transaction.  This method will fallback gracefully to
95       * return a normal connection, if the database being accessed does
96       * not support transactions.
97       *
98       * @param dbName Name of database.
99       * @param useTransaction If false, a transaction won't be used.
100      * @return The Connection for the transaction.
101      * @throws TorqueException Any exceptions caught during processing will be
102      *         rethrown wrapped into a TorqueException.
103      */
104     public static Connection beginOptional(String dbName,
105                                            boolean useTransaction)
106         throws TorqueException
107     {
108         Connection con = Torque.getConnection(dbName);
109         try
110         {
111             if (con.getMetaData().supportsTransactions() && useTransaction)
112             {
113                 con.setAutoCommit(false);
114             }
115         }
116         catch (SQLException e)
117         {
118             throw new TorqueException(e);
119         }
120         return con;
121     }
122 
123     /***
124      * Commit a transaction.  This method takes care of releasing the
125      * connection after the commit.  In databases that do not support
126      * transactions, it only returns the connection.
127      *
128      * @param con The Connection for the transaction.
129      * @throws TorqueException Any exceptions caught during processing will be
130      *         rethrown wrapped into a TorqueException.
131      */
132     public static void commit(Connection con) throws TorqueException
133     {
134         if (con == null)
135         {
136             throw new NullPointerException("Connection object was null. "
137                     + "This could be due to a misconfiguration of the "
138                     + "DataSourceFactory. Check the logs and Torque.properties "
139                     + "to better determine the cause.");
140         }
141 
142         try
143         {
144             if (con.getMetaData().supportsTransactions()
145                 && con.getAutoCommit() == false)
146             {
147                 con.commit();
148                 con.setAutoCommit(true);
149             }
150         }
151         catch (SQLException e)
152         {
153             throw new TorqueException(e);
154         }
155         finally
156         {
157             Torque.closeConnection(con);
158         }
159     }
160 
161     /***
162      * Roll back a transaction in databases that support transactions.
163      * It also releases the connection. In databases that do not support
164      * transactions, this method will log the attempt and release the
165      * connection.
166      *
167      * @param con The Connection for the transaction.
168      * @throws TorqueException Any exceptions caught during processing will be
169      *         rethrown wrapped into a TorqueException.
170      */
171     public static void rollback(Connection con) throws TorqueException
172     {
173         if (con == null)
174         {
175             throw new TorqueException("Connection object was null. "
176                     + "This could be due to a misconfiguration of the "
177                     + "DataSourceFactory. Check the logs and Torque.properties "
178                     + "to better determine the cause.");
179         }
180         else
181         {
182             try
183             {
184                 if (con.getMetaData().supportsTransactions()
185                     && con.getAutoCommit() == false)
186                 {
187                     con.rollback();
188                     con.setAutoCommit(true);
189                 }
190             }
191             catch (SQLException e)
192             {
193                 log.error("An attempt was made to rollback a transaction "
194                         + "but the database did not allow the operation to be "
195                         + "rolled back.", e);
196                 throw new TorqueException(e);
197             }
198             finally
199             {
200                 Torque.closeConnection(con);
201             }
202         }
203     }
204 
205     /***
206      * Roll back a transaction without throwing errors if they occur.
207      * A null Connection argument is logged at the debug level and other
208      * errors are logged at warn level.
209      *
210      * @param con The Connection for the transaction.
211      * @see Transaction#rollback(Connection)
212      */
213     public static void safeRollback(Connection con)
214     {
215         if (con == null)
216         {
217             log.debug("called safeRollback with null argument");
218         }
219         else
220         {
221             try
222             {
223                 Transaction.rollback(con);
224             }
225             catch (TorqueException e)
226             {
227                 log.warn("An error occured during rollback.", e);
228             }
229         }
230     }
231 }