e.g. Calendar Search Help
You must enter a value before pressing Search
spring

Class: org.springframework.jdbc.datasource.DataSourceTransactionManager   ©

 OK to copy?
001 /*
002  * Copyright 2002-2004 the original author or authors.
003  *
004  * Licensed under the Apache License, Version 2.0 (the "License");
005  * you may not use this file except in compliance with the License.
006  * You may obtain a copy of the License at
007  *
008  *      http://www.apache.org/licenses/LICENSE-2.0
009  *
010  * Unless required by applicable law or agreed to in writing, software
011  * distributed under the License is distributed on an "AS IS" BASIS,
012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013  * See the License for the specific language governing permissions and
014  * limitations under the License.
015  */
016 
017 package org.springframework.jdbc.datasource;
018 
019 import java.sql.Connection;
020 import java.sql.SQLException;
021 
022 import javax.sql.DataSource;
023 
024 import org.springframework.beans.factory.InitializingBean;
025 import org.springframework.transaction.CannotCreateTransactionException;
026 import org.springframework.transaction.TransactionDefinition;
027 import org.springframework.transaction.TransactionSystemException;
028 import org.springframework.transaction.support.AbstractPlatformTransactionManager;
029 import org.springframework.transaction.support.DefaultTransactionStatus;
030 import org.springframework.transaction.support.TransactionSynchronizationManager;
031 
032 /**
033  * PlatformTransactionManager implementation for a single JDBC DataSource.
034  * Binds a JDBC connection from the specified DataSource to the thread,
035  * potentially allowing for one thread connection per data source.
036  *
037  * <p>Application code is required to retrieve the JDBC Connection via
038  * <code>DataSourceUtils.getConnection(DataSource)</code> instead of J2EE's standard
039  * <code>DataSource.getConnection()</code>. This is recommended anyway, as it throws
040  * unchecked org.springframework.dao exceptions instead of checked SQLException.
041  * All framework classes like JdbcTemplate use this strategy implicitly.
042  * If not used with this transaction manager, the lookup strategy behaves exactly
043  * like the common one - it can thus be used in any case.
044  *
045  * <p>Alternatively, you can also allow application code to work with the standard
046  * J2EE lookup pattern <code>DataSource.getConnection()</code>, for example for
047  * legacy code that is not aware of Spring at all. In that case, define a
048  * TransactionAwareDataSourceProxy for your target DataSource, and pass that proxy
049  * DataSource to your DAOs, which will automatically participate in Spring-managed
050  * transactions through it. Note that DataSourceTransactionManager still needs to
051  * be wired with the target DataSource, driving transactions for it.
052  *
053  * <p>Supports custom isolation levels, and timeouts that get applied as
054  * appropriate JDBC statement query timeouts. To support the latter,
055  * application code must either use JdbcTemplate or call
056  * <code>DataSourceUtils.applyTransactionTimeout</code> for each created statement.
057  *
058  * <p>On JDBC 3.0, this transaction manager supports nested transactions via JDBC
059  * 3.0 Savepoints. The "nestedTransactionAllowed" flag defaults to true, as nested
060  * transactions work without restrictions on JDBC drivers that support Savepoints
061  * (like Oracle).
062  *
063  * <p>This implementation can be used instead of JtaTransactionManager in the single
064  * resource case, as it does not require the container to support JTA: typically,
065  * in combination with a locally defined JDBC DataSource like a Jakarta Commons DBCP
066  * connection pool. Switching between this local strategy and a JTA environment is
067  * just a matter of configuration, if you stick to the required connection lookup
068  * pattern. Note that JTA does not support custom isolation levels!
069  *
070  * @author Juergen Hoeller
071  * @since 02.05.2003
072  * @see #setNestedTransactionAllowed
073  * @see java.sql.Savepoint
074  * @see DataSourceUtils#getConnection
075  * @see DataSourceUtils#applyTransactionTimeout
076  * @see DataSourceUtils#closeConnectionIfNecessary
077  * @see TransactionAwareDataSourceProxy
078  * @see org.springframework.jdbc.core.JdbcTemplate
079  */
080 public class DataSourceTransactionManager extends AbstractPlatformTransactionManager implements InitializingBean {
081 
082     private DataSource dataSource;
083 
084 
085     /**
086      * Create a new DataSourceTransactionManager instance.
087      * A DataSource has to be set to be able to use it.
088      * @see #setDataSource
089      */
090     public DataSourceTransactionManager() {
091         setNestedTransactionAllowed(true);
092     }
093 
094     /**
095      * Create a new DataSourceTransactionManager instance.
096      * @param dataSource JDBC DataSource to manage transactions for
097      */
098     public DataSourceTransactionManager(DataSource dataSource) {
099         this();
100         this.dataSource = dataSource;
101         afterPropertiesSet();
102     }
103 
104     /**
105      * Set the JDBC DataSource that this instance should manage transactions for.
106      * <p>This will typically be a locally defined DataSource, for example a
107      * Jakarta Commons DBCP connection pool. Alternatively, you can also drive
108      * transactions for a non-XA J2EE DataSource fetched from JNDI. For an XA
109      * DataSource, use JtaTransactionManager.
110      * @see org.springframework.transaction.jta.JtaTransactionManager
111      */
112     public void setDataSource(DataSource dataSource) {
113         this.dataSource = dataSource;
114     }
115 
116     /**
117      * Return the JDBC DataSource that this instance manages transactions for.
118      */
119     public DataSource getDataSource() {
120         return dataSource;
121     }
122 
123     public void afterPropertiesSet() {
124         if (this.dataSource == null) {
125             throw new IllegalArgumentException("dataSource is required");
126         }
127     }
128 
129 
130     protected Object doGetTransaction() {
131         DataSourceTransactionObject txObject = new DataSourceTransactionObject();
132         txObject.setSavepointAllowed(isNestedTransactionAllowed());
133         ConnectionHolder conHolder =
134             (ConnectionHolder) TransactionSynchronizationManager.getResource(this.dataSource);
135         txObject.setConnectionHolder(conHolder);
136         return txObject;
137     }
138 
139     protected boolean isExistingTransaction(Object transaction) {
140         DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
141         // Consider a pre-bound connection as transaction.
142         return (txObject.getConnectionHolder() != null);
143     }
144 
145     /**
146      * This implementation sets the isolation level but ignores the timeout.
147      */
148     protected void doBegin(Object transaction, TransactionDefinition definition) {
149         DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
150 
151         Connection con = DataSourceUtils.getConnection(this.dataSource, false);
152         if (logger.isDebugEnabled()) {
153             logger.debug("Opened connection [" + con + "] for JDBC transaction");
154         }
155 
156         txObject.setConnectionHolder(new ConnectionHolder(con));
157         txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
158 
159         try {
160             Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
161             txObject.setPreviousIsolationLevel(previousIsolationLevel);
162 
163             // Switch to manual commit if necessary. This is very expensive in some JDBC drivers,
164             // so we don't want to do it unnecessarily (for example if we're configured
165             // Commons DBCP to set it already).
166             if (con.getAutoCommit()) {
167                 txObject.setMustRestoreAutoCommit(true);
168                 if (logger.isDebugEnabled()) {
169                     logger.debug("Switching JDBC connection [" + con + "] to manual commit");
170                 }
171                 con.setAutoCommit(false);
172             }
173 
174             if (definition.getTimeout() != TransactionDefinition.TIMEOUT_DEFAULT) {
175                 txObject.getConnectionHolder().setTimeoutInSeconds(definition.getTimeout());
176             }
177             TransactionSynchronizationManager.bindResource(getDataSource(), txObject.getConnectionHolder());
178         }
179 
180         catch (SQLException ex) {
181             DataSourceUtils.closeConnectionIfNecessary(con, this.dataSource);
182             throw new CannotCreateTransactionException("Could not configure JDBC connection for transaction", ex);
183         }
184     }
185 
186     protected Object doSuspend(Object transaction) {
187         DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
188         txObject.setConnectionHolder(null);
189         return TransactionSynchronizationManager.unbindResource(this.dataSource);
190     }
191 
192     protected void doResume(Object transaction, Object suspendedResources) {
193         ConnectionHolder conHolder = (ConnectionHolder) suspendedResources;
194         TransactionSynchronizationManager.bindResource(this.dataSource, conHolder);
195     }
196 
197     protected void doCommit(DefaultTransactionStatus status) {
198         DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();
199         Connection con = txObject.getConnectionHolder().getConnection();
200         if (status.isDebug()) {
201             logger.debug("Committing JDBC transaction on connection [" + con + "]");
202         }
203         try {
Rate204             con.commit();
205         }
206         catch (SQLException ex) {
207             throw new TransactionSystemException("Could not commit JDBC transaction", ex);
208         }
209     }
210 
211     protected void doRollback(DefaultTransactionStatus status) {
212         DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();
213         Connection con = txObject.getConnectionHolder().getConnection();
214         if (status.isDebug()) {
215             logger.debug("Rolling back JDBC transaction on connection [" + con + "]");
216         }
217         try {
218             con.rollback();
219         }
220         catch (SQLException ex) {
221             throw new TransactionSystemException("Could not roll back JDBC transaction", ex);
222         }
223     }
224 
225     protected void doSetRollbackOnly(DefaultTransactionStatus status) {
226         DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();
227         if (status.isDebug()) {
228             logger.debug("Setting JDBC transaction [" + txObject.getConnectionHolder().getConnection() +
229                     "] rollback-only");
230         }
231         txObject.setRollbackOnly();
232     }
233 
234     protected void doCleanupAfterCompletion(Object transaction) {
235         DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
236 
237         // Remove the connection holder from the thread.
238         TransactionSynchronizationManager.unbindResource(this.dataSource);
239         txObject.getConnectionHolder().clear();
240 
241         // Reset connection.
242         Connection con = txObject.getConnectionHolder().getConnection();
243         try {
244             if (txObject.isMustRestoreAutoCommit()) {
245                 con.setAutoCommit(true);
246             }
247             DataSourceUtils.resetConnectionAfterTransaction(con, txObject.getPreviousIsolationLevel());
248         }
249         catch (SQLException ex) {
250             logger.info("Could not reset JDBC connection after transaction", ex);
251         }
252 
253         if (logger.isDebugEnabled()) {
254             logger.debug("Closing JDBC connection [" + con + "] after transaction");
255         }
256         DataSourceUtils.closeConnectionIfNecessary(con, this.dataSource);
257     }
258 
259 
260     /**
261      * DataSource transaction object, representing a ConnectionHolder.
262      * Used as transaction object by DataSourceTransactionManager.
263      *
264      * <p>Derives from JdbcTransactionObjectSupport to inherit the capability
265      * to manage JDBC 3.0 Savepoints.
266      *
267      * @see ConnectionHolder
268      */
269     private static class DataSourceTransactionObject extends JdbcTransactionObjectSupport {
270 
271         private boolean mustRestoreAutoCommit;
272 
273         public void setMustRestoreAutoCommit(boolean mustRestoreAutoCommit) {
274             this.mustRestoreAutoCommit = mustRestoreAutoCommit;
275         }
276 
277         public boolean isMustRestoreAutoCommit() {
278             return mustRestoreAutoCommit;
279         }
280 
281         public void setRollbackOnly() {
282             getConnectionHolder().setRollbackOnly();
283         }
284 
285         public boolean isRollbackOnly() {
286             return getConnectionHolder().isRollbackOnly();
287         }
288 
289     }
290 }

            
All Examples in File:
Example
Line
Rating (found
useful by...)
204 0% of 0