001: /*
002: * Copyright 2002-2006 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.jpa.vendor;
018:
019: import java.sql.Connection;
020: import java.sql.SQLException;
021:
022: import javax.persistence.EntityManager;
023: import javax.persistence.PersistenceException;
024:
025: import oracle.toplink.essentials.internal.sessions.AbstractSession;
026: import oracle.toplink.essentials.sessions.Session;
027: import oracle.toplink.essentials.sessions.UnitOfWork;
028:
029: import org.springframework.jdbc.datasource.ConnectionHandle;
030: import org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy;
031: import org.springframework.jdbc.datasource.SimpleConnectionHandle;
032: import org.springframework.orm.jpa.DefaultJpaDialect;
033: import org.springframework.transaction.TransactionDefinition;
034: import org.springframework.transaction.TransactionException;
035:
036: /**
037: * {@link org.springframework.orm.jpa.JpaDialect} implementation for
038: * Oracle TopLink Essentials. Developed and tested against TopLink Essentials v2.
039: *
040: * <p>By default, this class acquires a TopLink transaction to get the JDBC connection
041: * early. This allows mixing JDBC and JPA/TopLink operations in the same transaction.
042: * In some cases, this eager acquisition of a transaction/connection may impact
043: * scalability. In that case, set the "lazyDatabaseTransaction" flag to true if you
044: * do not require mixing JDBC and JPA operations in the same transaction. Otherwise,
045: * use a {@link org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy}
046: * to ensure that the cost of connection acquisition is near zero until code actually
047: * needs a JDBC Connection.
048: *
049: * @author Rod Johnson
050: * @author Juergen Hoeller
051: * @since 2.0
052: * @see #setLazyDatabaseTransaction
053: * @see LazyConnectionDataSourceProxy
054: */
055: public class TopLinkJpaDialect extends DefaultJpaDialect {
056:
057: private boolean lazyDatabaseTransaction = false;
058:
059: /**
060: * Set whether to lazily start a database transaction within a TopLink
061: * transaction.
062: * <p>By default, database transactions are started early. This allows
063: * for reusing the same JDBC Connection throughout an entire transaction,
064: * including read operations, and also for exposing TopLink transactions
065: * to JDBC access code (working on the same DataSource).
066: * <p>It is only recommended to switch this flag to "true" when no JDBC access
067: * code is involved in any of the transactions, and when it is acceptable to
068: * perform read operations outside of the transactional JDBC Connection.
069: * @see oracle.toplink.sessions.UnitOfWork#beginEarlyTransaction()
070: */
071: public void setLazyDatabaseTransaction(
072: boolean lazyDatabaseTransaction) {
073: this .lazyDatabaseTransaction = lazyDatabaseTransaction;
074: }
075:
076: @Override
077: public Object beginTransaction(EntityManager entityManager,
078: TransactionDefinition definition)
079: throws PersistenceException, SQLException,
080: TransactionException {
081:
082: super .beginTransaction(entityManager, definition);
083: if (!definition.isReadOnly() && !this .lazyDatabaseTransaction) {
084: // This is the magic bit. As with the existing Spring TopLink integration,
085: // begin an early transaction to force TopLink to get a JDBC connection
086: // so that Spring can manage transactions with JDBC as well as TopLink.
087: UnitOfWork uow = (UnitOfWork) getSession(entityManager);
088: uow.beginEarlyTransaction();
089: }
090: // Could return the UOW, if there were any advantage in having it later.
091: return null;
092: }
093:
094: @Override
095: public ConnectionHandle getJdbcConnection(EntityManager em,
096: boolean readOnly) throws PersistenceException, SQLException {
097:
098: AbstractSession session = (AbstractSession) getSession(em);
099: // The connection was already acquired eagerly in beginTransaction,
100: // unless lazyDatabaseTransaction was set to true.
101: Connection con = session.getAccessor().getConnection();
102: return (con != null ? new SimpleConnectionHandle(con) : null);
103: }
104:
105: /**
106: * Get a traditional TopLink Session from the given EntityManager.
107: */
108: protected Session getSession(EntityManager em) {
109: oracle.toplink.essentials.ejb.cmp3.EntityManager emi = (oracle.toplink.essentials.ejb.cmp3.EntityManager) em;
110: return emi.getActiveSession();
111: }
112:
113: }
|