Source Code Cross Referenced for HibernateTransactionManager.java in  » J2EE » spring-framework-2.0.6 » org » springframework » orm » hibernate » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » J2EE » spring framework 2.0.6 » org.springframework.orm.hibernate 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         * Copyright 2002-2007 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.orm.hibernate;
018:
019:        import java.sql.Connection;
020:
021:        import javax.sql.DataSource;
022:
023:        import net.sf.hibernate.FlushMode;
024:        import net.sf.hibernate.HibernateException;
025:        import net.sf.hibernate.Interceptor;
026:        import net.sf.hibernate.JDBCException;
027:        import net.sf.hibernate.Session;
028:        import net.sf.hibernate.SessionFactory;
029:
030:        import org.springframework.beans.BeansException;
031:        import org.springframework.beans.factory.BeanFactory;
032:        import org.springframework.beans.factory.BeanFactoryAware;
033:        import org.springframework.beans.factory.InitializingBean;
034:        import org.springframework.dao.DataAccessException;
035:        import org.springframework.jdbc.datasource.ConnectionHolder;
036:        import org.springframework.jdbc.datasource.DataSourceUtils;
037:        import org.springframework.jdbc.datasource.JdbcTransactionObjectSupport;
038:        import org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy;
039:        import org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator;
040:        import org.springframework.jdbc.support.SQLExceptionTranslator;
041:        import org.springframework.transaction.CannotCreateTransactionException;
042:        import org.springframework.transaction.IllegalTransactionStateException;
043:        import org.springframework.transaction.TransactionDefinition;
044:        import org.springframework.transaction.TransactionSystemException;
045:        import org.springframework.transaction.support.AbstractPlatformTransactionManager;
046:        import org.springframework.transaction.support.DefaultTransactionStatus;
047:        import org.springframework.transaction.support.ResourceTransactionManager;
048:        import org.springframework.transaction.support.TransactionSynchronizationManager;
049:
050:        /**
051:         * {@link org.springframework.transaction.PlatformTransactionManager}
052:         * implementation for a single Hibernate {@link net.sf.hibernate.SessionFactory}.
053:         * Binds a Hibernate Session from the specified factory to the thread, potentially
054:         * allowing for one thread-bound Session per factory. {@link SessionFactoryUtils}
055:         * and {@link HibernateTemplate} are aware of thread-bound Sessions and participate
056:         * in such transactions automatically. Using either of those is required for
057:         * Hibernate access code that needs to support this transaction handling mechanism.
058:         *
059:         * <p>Supports custom isolation levels, and timeouts that get applied as appropriate
060:         * Hibernate query timeouts. To support the latter, application code must either use
061:         * {@link HibernateTemplate} (which by default applies the timeouts) or call
062:         * {@link SessionFactoryUtils#applyTransactionTimeout} for each created
063:         * Hibernate {@link net.sf.hibernate.Query} object.
064:         *
065:         * <p>This transaction manager is appropriate for applications that use a single
066:         * Hibernate SessionFactory for transactional data access, but it also supports
067:         * direct DataSource access within a transaction (i.e. plain JDBC code working
068:         * with the same DataSource). This allows for mixing services which access Hibernate
069:         * and services which use plain JDBC (without being aware of Hibernate)!
070:         * Application code needs to stick to the same simple Connection lookup pattern as
071:         * with {@link org.springframework.jdbc.datasource.DataSourceTransactionManager}
072:         * (i.e. {@link org.springframework.jdbc.datasource.DataSourceUtils#getConnection}
073:         * or going through a
074:         * {@link org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy}).
075:         *
076:         * <p>Note: To be able to register a DataSource's Connection for plain JDBC code,
077:         * this instance needs to be aware of the DataSource ({@link #setDataSource}).
078:         * The given DataSource should obviously match the one used by the given
079:         * SessionFactory. To achieve this, configure both to the same JNDI DataSource,
080:         * or preferably create the SessionFactory with {@link LocalSessionFactoryBean} and
081:         * a local DataSource (which will be autodetected by this transaction manager).
082:         *
083:         * <p>JTA (usually through {@link org.springframework.transaction.jta.JtaTransactionManager})
084:         * is necessary for accessing multiple transactional resources within the same
085:         * transaction. The DataSource that Hibernate uses needs to be JTA-enabled in
086:         * such a scenario (see container setup). Normally, JTA setup for Hibernate is
087:         * somewhat container-specific due to the JTA TransactionManager lookup, required
088:         * for proper transactional handling of the SessionFactory-level read-write cache.
089:         *
090:         * <p>Fortunately, there is an easier way with Spring: {@link SessionFactoryUtils}
091:         * (and thus {@link HibernateTemplate}) registers synchronizations with Spring's
092:         * {@link org.springframework.transaction.support.TransactionSynchronizationManager}
093:         * (as used by {@link org.springframework.transaction.jta.JtaTransactionManager}),
094:         * for proper after-completion callbacks. Therefore, as long as Spring's
095:         * JtaTransactionManager drives the JTA transactions, Hibernate does not require
096:         * any special configuration for proper JTA participation. Note that there are
097:         * special restrictions with EJB CMT and restrictive JTA subsystems: See
098:         * {@link org.springframework.transaction.jta.JtaTransactionManager}'s javadoc for details.
099:         *
100:         * <p>On JDBC 3.0, this transaction manager supports nested transactions via JDBC 3.0
101:         * Savepoints. The {@link #setNestedTransactionAllowed} "nestedTransactionAllowed"}
102:         * flag defaults to "false", though, as nested transactions will just apply to the
103:         * JDBC Connection, not to the Hibernate Session and its cached objects. You can
104:         * manually set the flag to "true" if you want to use nested transactions for
105:         * JDBC access code which participates in Hibernate transactions (provided that
106:         * your JDBC driver supports Savepoints). <i>Note that Hibernate itself does not
107:         * support nested transactions! Hence, do not expect Hibernate access code to
108:         * semantically participate in a nested transaction.</i>
109:         *
110:         * <p>Note: Spring's Hibernate support in this package requires Hibernate 2.1.
111:         * Dedicated Hibernate3 support can be found in a separate package:
112:         * <code>org.springframework.orm.hibernate3</code>.
113:         *
114:         * @author Juergen Hoeller
115:         * @since 02.05.2003
116:         * @see #setSessionFactory
117:         * @see #setDataSource
118:         * @see LocalSessionFactoryBean
119:         * @see SessionFactoryUtils#getSession
120:         * @see SessionFactoryUtils#applyTransactionTimeout
121:         * @see SessionFactoryUtils#releaseSession
122:         * @see HibernateTemplate#execute
123:         * @see org.springframework.jdbc.datasource.DataSourceUtils#getConnection
124:         * @see org.springframework.jdbc.datasource.DataSourceUtils#applyTransactionTimeout
125:         * @see org.springframework.jdbc.datasource.DataSourceUtils#releaseConnection
126:         * @see org.springframework.jdbc.core.JdbcTemplate
127:         * @see org.springframework.jdbc.datasource.DataSourceTransactionManager
128:         * @see org.springframework.transaction.jta.JtaTransactionManager
129:         */
130:        public class HibernateTransactionManager extends
131:                AbstractPlatformTransactionManager implements 
132:                ResourceTransactionManager, BeanFactoryAware, InitializingBean {
133:
134:            private SessionFactory sessionFactory;
135:
136:            private DataSource dataSource;
137:
138:            private boolean autodetectDataSource = true;
139:
140:            private Object entityInterceptor;
141:
142:            private SQLExceptionTranslator jdbcExceptionTranslator;
143:
144:            /**
145:             * Just needed for entityInterceptorBeanName.
146:             * @see #setEntityInterceptorBeanName
147:             */
148:            private BeanFactory beanFactory;
149:
150:            /**
151:             * Create a new HibernateTransactionManager instance.
152:             * A SessionFactory has to be set to be able to use it.
153:             * @see #setSessionFactory
154:             */
155:            public HibernateTransactionManager() {
156:            }
157:
158:            /**
159:             * Create a new HibernateTransactionManager instance.
160:             * @param sessionFactory SessionFactory to manage transactions for
161:             */
162:            public HibernateTransactionManager(SessionFactory sessionFactory) {
163:                this .sessionFactory = sessionFactory;
164:                afterPropertiesSet();
165:            }
166:
167:            /**
168:             * Set the SessionFactory that this instance should manage transactions for.
169:             */
170:            public void setSessionFactory(SessionFactory sessionFactory) {
171:                this .sessionFactory = sessionFactory;
172:            }
173:
174:            /**
175:             * Return the SessionFactory that this instance should manage transactions for.
176:             */
177:            public SessionFactory getSessionFactory() {
178:                return this .sessionFactory;
179:            }
180:
181:            /**
182:             * Set the JDBC DataSource that this instance should manage transactions for.
183:             * The DataSource should match the one used by the Hibernate SessionFactory:
184:             * for example, you could specify the same JNDI DataSource for both.
185:             * <p>If the SessionFactory was configured with LocalDataSourceConnectionProvider,
186:             * i.e. by Spring's LocalSessionFactoryBean with a specified "dataSource",
187:             * the DataSource will be autodetected: You can still explictly specify the
188:             * DataSource, but you don't need to in this case.
189:             * <p>A transactional JDBC Connection for this DataSource will be provided to
190:             * application code accessing this DataSource directly via DataSourceUtils
191:             * or JdbcTemplate. The Connection will be taken from the Hibernate Session.
192:             * <p>The DataSource specified here should be the target DataSource to manage
193:             * transactions for, not a TransactionAwareDataSourceProxy. Only data access
194:             * code may work with TransactionAwareDataSourceProxy, while the transaction
195:             * manager needs to work on the underlying target DataSource. If there's
196:             * nevertheless a TransactionAwareDataSourceProxy passed in, it will be
197:             * unwrapped to extract its target DataSource.
198:             * @see #setAutodetectDataSource
199:             * @see LocalDataSourceConnectionProvider
200:             * @see LocalSessionFactoryBean#setDataSource
201:             * @see org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy
202:             * @see org.springframework.jdbc.datasource.DataSourceUtils
203:             * @see org.springframework.jdbc.core.JdbcTemplate
204:             */
205:            public void setDataSource(DataSource dataSource) {
206:                if (dataSource instanceof  TransactionAwareDataSourceProxy) {
207:                    // If we got a TransactionAwareDataSourceProxy, we need to perform transactions
208:                    // for its underlying target DataSource, else data access code won't see
209:                    // properly exposed transactions (i.e. transactions for the target DataSource).
210:                    this .dataSource = ((TransactionAwareDataSourceProxy) dataSource)
211:                            .getTargetDataSource();
212:                } else {
213:                    this .dataSource = dataSource;
214:                }
215:            }
216:
217:            /**
218:             * Return the JDBC DataSource that this instance manages transactions for.
219:             */
220:            public DataSource getDataSource() {
221:                return this .dataSource;
222:            }
223:
224:            /**
225:             * Set whether to autodetect a JDBC DataSource used by the Hibernate SessionFactory,
226:             * if set via LocalSessionFactoryBean's <code>setDataSource</code>. Default is "true".
227:             * <p>Can be turned off to deliberately ignore an available DataSource,
228:             * to not expose Hibernate transactions as JDBC transactions for that DataSource.
229:             * @see #setDataSource
230:             * @see LocalSessionFactoryBean#setDataSource
231:             */
232:            public void setAutodetectDataSource(boolean autodetectDataSource) {
233:                this .autodetectDataSource = autodetectDataSource;
234:            }
235:
236:            /**
237:             * Set the bean name of a Hibernate entity interceptor that allows to inspect
238:             * and change property values before writing to and reading from the database.
239:             * Will get applied to any new Session created by this transaction manager.
240:             * <p>Requires the bean factory to be known, to be able to resolve the bean
241:             * name to an interceptor instance on session creation. Typically used for
242:             * prototype interceptors, i.e. a new interceptor instance per session.
243:             * <p>Can also be used for shared interceptor instances, but it is recommended
244:             * to set the interceptor reference directly in such a scenario.
245:             * @param entityInterceptorBeanName the name of the entity interceptor in
246:             * the bean factory
247:             * @see #setBeanFactory
248:             * @see #setEntityInterceptor
249:             */
250:            public void setEntityInterceptorBeanName(
251:                    String entityInterceptorBeanName) {
252:                this .entityInterceptor = entityInterceptorBeanName;
253:            }
254:
255:            /**
256:             * Set a Hibernate entity interceptor that allows to inspect and change
257:             * property values before writing to and reading from the database.
258:             * Will get applied to any new Session created by this transaction manager.
259:             * <p>Such an interceptor can either be set at the SessionFactory level,
260:             * i.e. on LocalSessionFactoryBean, or at the Session level, i.e. on
261:             * HibernateTemplate, HibernateInterceptor, and HibernateTransactionManager.
262:             * It's preferable to set it on LocalSessionFactoryBean or HibernateTransactionManager
263:             * to avoid repeated configuration and guarantee consistent behavior in transactions.
264:             * @see LocalSessionFactoryBean#setEntityInterceptor
265:             * @see HibernateTemplate#setEntityInterceptor
266:             * @see HibernateInterceptor#setEntityInterceptor
267:             */
268:            public void setEntityInterceptor(Interceptor entityInterceptor) {
269:                this .entityInterceptor = entityInterceptor;
270:            }
271:
272:            /**
273:             * Return the current Hibernate entity interceptor, or <code>null</code> if none.
274:             * Resolves an entity interceptor bean name via the bean factory,
275:             * if necessary.
276:             * @throws IllegalStateException if bean name specified but no bean factory set
277:             * @throws BeansException if bean name resolution via the bean factory failed
278:             * @see #setEntityInterceptor
279:             * @see #setEntityInterceptorBeanName
280:             * @see #setBeanFactory
281:             */
282:            public Interceptor getEntityInterceptor()
283:                    throws IllegalStateException, BeansException {
284:                if (this .entityInterceptor instanceof  Interceptor) {
285:                    return (Interceptor) entityInterceptor;
286:                } else if (this .entityInterceptor instanceof  String) {
287:                    if (this .beanFactory == null) {
288:                        throw new IllegalStateException(
289:                                "Cannot get entity interceptor via bean name if no bean factory set");
290:                    }
291:                    String beanName = (String) this .entityInterceptor;
292:                    return (Interceptor) this .beanFactory.getBean(beanName,
293:                            Interceptor.class);
294:                } else {
295:                    return null;
296:                }
297:            }
298:
299:            /**
300:             * Set the JDBC exception translator for this transaction manager.
301:             * Applied to SQLExceptions (wrapped by Hibernate's JDBCException)
302:             * thrown by flushing on commit.
303:             * <p>The default exception translator is either a SQLErrorCodeSQLExceptionTranslator
304:             * if a DataSource is available, or a SQLStateSQLExceptionTranslator else.
305:             * @param jdbcExceptionTranslator the exception translator
306:             * @see java.sql.SQLException
307:             * @see net.sf.hibernate.JDBCException
308:             * @see SessionFactoryUtils#newJdbcExceptionTranslator
309:             * @see org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator
310:             * @see org.springframework.jdbc.support.SQLStateSQLExceptionTranslator
311:             */
312:            public void setJdbcExceptionTranslator(
313:                    SQLExceptionTranslator jdbcExceptionTranslator) {
314:                this .jdbcExceptionTranslator = jdbcExceptionTranslator;
315:            }
316:
317:            /**
318:             * Return the JDBC exception translator for this transaction manager.
319:             * <p>Creates a default SQLErrorCodeSQLExceptionTranslator or SQLStateSQLExceptionTranslator
320:             * for the specified SessionFactory, if no exception translator explicitly specified.
321:             * @see #setJdbcExceptionTranslator
322:             */
323:            public synchronized SQLExceptionTranslator getJdbcExceptionTranslator() {
324:                if (this .jdbcExceptionTranslator == null) {
325:                    if (getDataSource() != null) {
326:                        this .jdbcExceptionTranslator = new SQLErrorCodeSQLExceptionTranslator(
327:                                getDataSource());
328:                    } else {
329:                        this .jdbcExceptionTranslator = SessionFactoryUtils
330:                                .newJdbcExceptionTranslator(getSessionFactory());
331:                    }
332:                }
333:                return this .jdbcExceptionTranslator;
334:            }
335:
336:            /**
337:             * The bean factory just needs to be known for resolving entity interceptor
338:             * bean names. It does not need to be set for any other mode of operation.
339:             * @see #setEntityInterceptorBeanName
340:             */
341:            public void setBeanFactory(BeanFactory beanFactory) {
342:                this .beanFactory = beanFactory;
343:            }
344:
345:            public void afterPropertiesSet() {
346:                if (getSessionFactory() == null) {
347:                    throw new IllegalArgumentException(
348:                            "Property 'sessionFactory' is required");
349:                }
350:                if (this .entityInterceptor instanceof  String
351:                        && this .beanFactory == null) {
352:                    throw new IllegalArgumentException(
353:                            "'beanFactory' is required for 'entityInterceptorBeanName'");
354:                }
355:
356:                // Check for SessionFactory's DataSource.
357:                if (this .autodetectDataSource && getDataSource() == null) {
358:                    DataSource sfds = SessionFactoryUtils
359:                            .getDataSource(getSessionFactory());
360:                    if (sfds != null) {
361:                        // Use the SessionFactory's DataSource for exposing transactions to JDBC code.
362:                        if (logger.isInfoEnabled()) {
363:                            logger
364:                                    .info("Using DataSource ["
365:                                            + sfds
366:                                            + "] of Hibernate SessionFactory for HibernateTransactionManager");
367:                        }
368:                        setDataSource(sfds);
369:                    }
370:                }
371:            }
372:
373:            public Object getResourceFactory() {
374:                return getSessionFactory();
375:            }
376:
377:            protected Object doGetTransaction() {
378:                HibernateTransactionObject txObject = new HibernateTransactionObject();
379:                txObject.setSavepointAllowed(isNestedTransactionAllowed());
380:
381:                SessionHolder sessionHolder = (SessionHolder) TransactionSynchronizationManager
382:                        .getResource(getSessionFactory());
383:                if (sessionHolder != null) {
384:                    if (logger.isDebugEnabled()) {
385:                        logger.debug("Found thread-bound Session ["
386:                                + sessionHolder.getSession()
387:                                + "] for Hibernate transaction");
388:                    }
389:                    txObject.setSessionHolder(sessionHolder, false);
390:                }
391:
392:                if (getDataSource() != null) {
393:                    ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager
394:                            .getResource(getDataSource());
395:                    txObject.setConnectionHolder(conHolder);
396:                }
397:
398:                return txObject;
399:            }
400:
401:            protected boolean isExistingTransaction(Object transaction) {
402:                return ((HibernateTransactionObject) transaction)
403:                        .hasTransaction();
404:            }
405:
406:            protected void doBegin(Object transaction,
407:                    TransactionDefinition definition) {
408:                HibernateTransactionObject txObject = (HibernateTransactionObject) transaction;
409:
410:                if (txObject.hasConnectionHolder()
411:                        && !txObject.getConnectionHolder()
412:                                .isSynchronizedWithTransaction()) {
413:                    throw new IllegalTransactionStateException(
414:                            "Pre-bound JDBC Connection found! HibernateTransactionManager does not support "
415:                                    + "running within DataSourceTransactionManager if told to manage the DataSource itself. "
416:                                    + "It is recommended to use a single HibernateTransactionManager for all transactions "
417:                                    + "on a single DataSource, no matter whether Hibernate or JDBC access.");
418:                }
419:
420:                Session session = null;
421:
422:                try {
423:                    if (txObject.getSessionHolder() == null
424:                            || txObject.getSessionHolder()
425:                                    .isSynchronizedWithTransaction()) {
426:                        Interceptor entityInterceptor = getEntityInterceptor();
427:                        Session newSession = (entityInterceptor != null ? getSessionFactory()
428:                                .openSession(entityInterceptor)
429:                                : getSessionFactory().openSession());
430:                        if (logger.isDebugEnabled()) {
431:                            logger.debug("Opened new Session [" + newSession
432:                                    + "] for Hibernate transaction");
433:                        }
434:                        txObject.setSessionHolder(
435:                                new SessionHolder(newSession), true);
436:                    }
437:
438:                    txObject.getSessionHolder().setSynchronizedWithTransaction(
439:                            true);
440:                    session = txObject.getSessionHolder().getSession();
441:
442:                    Connection con = session.connection();
443:                    Integer previousIsolationLevel = DataSourceUtils
444:                            .prepareConnectionForTransaction(con, definition);
445:                    txObject.setPreviousIsolationLevel(previousIsolationLevel);
446:
447:                    if (definition.isReadOnly()
448:                            && txObject.isNewSessionHolder()) {
449:                        // Just set to NEVER in case of a new Session for this transaction.
450:                        session.setFlushMode(FlushMode.NEVER);
451:                    }
452:
453:                    if (!definition.isReadOnly()
454:                            && !txObject.isNewSessionHolder()) {
455:                        // We need AUTO or COMMIT for a non-read-only transaction.
456:                        FlushMode flushMode = session.getFlushMode();
457:                        if (FlushMode.NEVER.equals(flushMode)) {
458:                            session.setFlushMode(FlushMode.AUTO);
459:                            txObject.getSessionHolder().setPreviousFlushMode(
460:                                    flushMode);
461:                        }
462:                    }
463:
464:                    // Add the Hibernate transaction to the session holder.
465:                    txObject.getSessionHolder().setTransaction(
466:                            session.beginTransaction());
467:
468:                    // Register transaction timeout.
469:                    int timeout = determineTimeout(definition);
470:                    if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
471:                        txObject.getSessionHolder()
472:                                .setTimeoutInSeconds(timeout);
473:                    }
474:
475:                    // Register the Hibernate Session's JDBC Connection for the DataSource, if set.
476:                    if (getDataSource() != null) {
477:                        ConnectionHolder conHolder = new ConnectionHolder(con);
478:                        if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
479:                            conHolder.setTimeoutInSeconds(timeout);
480:                        }
481:                        if (logger.isDebugEnabled()) {
482:                            logger
483:                                    .debug("Exposing Hibernate transaction as JDBC transaction ["
484:                                            + con + "]");
485:                        }
486:                        TransactionSynchronizationManager.bindResource(
487:                                getDataSource(), conHolder);
488:                        txObject.setConnectionHolder(conHolder);
489:                    }
490:
491:                    // Bind the session holder to the thread.
492:                    if (txObject.isNewSessionHolder()) {
493:                        TransactionSynchronizationManager.bindResource(
494:                                getSessionFactory(), txObject
495:                                        .getSessionHolder());
496:                    }
497:                }
498:
499:                catch (Exception ex) {
500:                    SessionFactoryUtils.closeSession(session);
501:                    throw new CannotCreateTransactionException(
502:                            "Could not open Hibernate Session for transaction",
503:                            ex);
504:                }
505:            }
506:
507:            protected Object doSuspend(Object transaction) {
508:                HibernateTransactionObject txObject = (HibernateTransactionObject) transaction;
509:                txObject.setSessionHolder(null, false);
510:                SessionHolder sessionHolder = (SessionHolder) TransactionSynchronizationManager
511:                        .unbindResource(getSessionFactory());
512:                txObject.setConnectionHolder(null);
513:                ConnectionHolder connectionHolder = null;
514:                if (getDataSource() != null) {
515:                    connectionHolder = (ConnectionHolder) TransactionSynchronizationManager
516:                            .unbindResource(getDataSource());
517:                }
518:                return new SuspendedResourcesHolder(sessionHolder,
519:                        connectionHolder);
520:            }
521:
522:            protected void doResume(Object transaction,
523:                    Object suspendedResources) {
524:                SuspendedResourcesHolder resourcesHolder = (SuspendedResourcesHolder) suspendedResources;
525:                if (TransactionSynchronizationManager
526:                        .hasResource(getSessionFactory())) {
527:                    // From non-transactional code running in active transaction synchronization
528:                    // -> can be safely removed, will be closed on transaction completion.
529:                    TransactionSynchronizationManager
530:                            .unbindResource(getSessionFactory());
531:                }
532:                TransactionSynchronizationManager
533:                        .bindResource(getSessionFactory(), resourcesHolder
534:                                .getSessionHolder());
535:                if (getDataSource() != null) {
536:                    TransactionSynchronizationManager.bindResource(
537:                            getDataSource(), resourcesHolder
538:                                    .getConnectionHolder());
539:                }
540:            }
541:
542:            protected void doCommit(DefaultTransactionStatus status) {
543:                HibernateTransactionObject txObject = (HibernateTransactionObject) status
544:                        .getTransaction();
545:                if (status.isDebug()) {
546:                    logger
547:                            .debug("Committing Hibernate transaction on Session ["
548:                                    + txObject.getSessionHolder().getSession()
549:                                    + "]");
550:                }
551:                try {
552:                    txObject.getSessionHolder().getTransaction().commit();
553:                } catch (net.sf.hibernate.TransactionException ex) {
554:                    // assumably from commit call to the underlying JDBC connection
555:                    throw new TransactionSystemException(
556:                            "Could not commit Hibernate transaction", ex);
557:                } catch (HibernateException ex) {
558:                    // assumably failed to flush changes to database
559:                    throw convertHibernateAccessException(ex);
560:                }
561:            }
562:
563:            protected void doRollback(DefaultTransactionStatus status) {
564:                HibernateTransactionObject txObject = (HibernateTransactionObject) status
565:                        .getTransaction();
566:                if (status.isDebug()) {
567:                    logger
568:                            .debug("Rolling back Hibernate transaction on Session ["
569:                                    + txObject.getSessionHolder().getSession()
570:                                    + "]");
571:                }
572:                try {
573:                    txObject.getSessionHolder().getTransaction().rollback();
574:                } catch (net.sf.hibernate.TransactionException ex) {
575:                    throw new TransactionSystemException(
576:                            "Could not roll back Hibernate transaction", ex);
577:                } catch (HibernateException ex) {
578:                    // Shouldn't really happen, as a rollback doesn't cause a flush.
579:                    throw convertHibernateAccessException(ex);
580:                } finally {
581:                    if (!txObject.isNewSessionHolder()) {
582:                        // Clear all pending inserts/updates/deletes in the Session.
583:                        // Necessary for pre-bound Sessions, to avoid inconsistent state.
584:                        txObject.getSessionHolder().getSession().clear();
585:                    }
586:                }
587:            }
588:
589:            protected void doSetRollbackOnly(DefaultTransactionStatus status) {
590:                HibernateTransactionObject txObject = (HibernateTransactionObject) status
591:                        .getTransaction();
592:                if (status.isDebug()) {
593:                    logger.debug("Setting Hibernate transaction on Session ["
594:                            + txObject.getSessionHolder().getSession()
595:                            + "] rollback-only");
596:                }
597:                txObject.setRollbackOnly();
598:            }
599:
600:            protected void doCleanupAfterCompletion(Object transaction) {
601:                HibernateTransactionObject txObject = (HibernateTransactionObject) transaction;
602:
603:                // Remove the session holder from the thread.
604:                if (txObject.isNewSessionHolder()) {
605:                    TransactionSynchronizationManager
606:                            .unbindResource(getSessionFactory());
607:                }
608:
609:                // Remove the JDBC connection holder from the thread, if exposed.
610:                if (getDataSource() != null) {
611:                    TransactionSynchronizationManager
612:                            .unbindResource(getDataSource());
613:                }
614:
615:                try {
616:                    Connection con = txObject.getSessionHolder().getSession()
617:                            .connection();
618:                    DataSourceUtils.resetConnectionAfterTransaction(con,
619:                            txObject.getPreviousIsolationLevel());
620:                } catch (HibernateException ex) {
621:                    logger
622:                            .info(
623:                                    "Could not access JDBC Connection of Hibernate Session",
624:                                    ex);
625:                }
626:
627:                Session session = txObject.getSessionHolder().getSession();
628:                if (txObject.isNewSessionHolder()) {
629:                    if (logger.isDebugEnabled()) {
630:                        logger.debug("Closing Hibernate Session [" + session
631:                                + "] after transaction");
632:                    }
633:                    SessionFactoryUtils.closeSessionOrRegisterDeferredClose(
634:                            session, getSessionFactory());
635:                } else {
636:                    if (logger.isDebugEnabled()) {
637:                        logger
638:                                .debug("Not closing pre-bound Hibernate Session ["
639:                                        + session + "] after transaction");
640:                    }
641:                    if (txObject.getSessionHolder().getPreviousFlushMode() != null) {
642:                        session.setFlushMode(txObject.getSessionHolder()
643:                                .getPreviousFlushMode());
644:                    }
645:                }
646:                txObject.getSessionHolder().clear();
647:            }
648:
649:            /**
650:             * Convert the given HibernateException to an appropriate exception from
651:             * the org.springframework.dao hierarchy. Can be overridden in subclasses.
652:             * @param ex HibernateException that occured
653:             * @return the corresponding DataAccessException instance
654:             * @see #convertJdbcAccessException(net.sf.hibernate.JDBCException)
655:             */
656:            protected DataAccessException convertHibernateAccessException(
657:                    HibernateException ex) {
658:                if (ex instanceof  JDBCException) {
659:                    return convertJdbcAccessException((JDBCException) ex);
660:                }
661:                return SessionFactoryUtils.convertHibernateAccessException(ex);
662:            }
663:
664:            /**
665:             * Convert the given JDBCException to an appropriate exception from the
666:             * <code>org.springframework.dao</code> hierarchy.
667:             * Uses a JDBC exception translator. Can be overridden in subclasses.
668:             * @param ex JDBCException that occured, wrapping a SQLException
669:             * @return the corresponding DataAccessException instance
670:             * @see #setJdbcExceptionTranslator
671:             */
672:            protected DataAccessException convertJdbcAccessException(
673:                    JDBCException ex) {
674:                return getJdbcExceptionTranslator().translate(
675:                        "Hibernate operation: " + ex.getMessage(), null,
676:                        ex.getSQLException());
677:            }
678:
679:            /**
680:             * Hibernate transaction object, representing a SessionHolder.
681:             * Used as transaction object by HibernateTransactionManager.
682:             *
683:             * <p>Derives from JdbcTransactionObjectSupport in order to inherit the
684:             * capability to manage JDBC 3.0 Savepoints for underlying JDBC Connections.
685:             *
686:             * @see SessionHolder
687:             */
688:            private static class HibernateTransactionObject extends
689:                    JdbcTransactionObjectSupport {
690:
691:                private SessionHolder sessionHolder;
692:
693:                private boolean newSessionHolder;
694:
695:                public void setSessionHolder(SessionHolder sessionHolder,
696:                        boolean newSessionHolder) {
697:                    this .sessionHolder = sessionHolder;
698:                    this .newSessionHolder = newSessionHolder;
699:                }
700:
701:                public SessionHolder getSessionHolder() {
702:                    return this .sessionHolder;
703:                }
704:
705:                public boolean isNewSessionHolder() {
706:                    return this .newSessionHolder;
707:                }
708:
709:                public boolean hasTransaction() {
710:                    return (this .sessionHolder != null && this .sessionHolder
711:                            .getTransaction() != null);
712:                }
713:
714:                public void setRollbackOnly() {
715:                    getSessionHolder().setRollbackOnly();
716:                    if (hasConnectionHolder()) {
717:                        getConnectionHolder().setRollbackOnly();
718:                    }
719:                }
720:
721:                public boolean isRollbackOnly() {
722:                    return getSessionHolder().isRollbackOnly()
723:                            || (hasConnectionHolder() && getConnectionHolder()
724:                                    .isRollbackOnly());
725:                }
726:            }
727:
728:            /**
729:             * Holder for suspended resources.
730:             * Used internally by <code>doSuspend</code> and <code>doResume</code>.
731:             */
732:            private static class SuspendedResourcesHolder {
733:
734:                private final SessionHolder sessionHolder;
735:
736:                private final ConnectionHolder connectionHolder;
737:
738:                private SuspendedResourcesHolder(SessionHolder sessionHolder,
739:                        ConnectionHolder conHolder) {
740:                    this .sessionHolder = sessionHolder;
741:                    this .connectionHolder = conHolder;
742:                }
743:
744:                private SessionHolder getSessionHolder() {
745:                    return this .sessionHolder;
746:                }
747:
748:                private ConnectionHolder getConnectionHolder() {
749:                    return this.connectionHolder;
750:                }
751:            }
752:
753:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.