001/* 002 * Copyright 2002-2020 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 * https://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 017package org.springframework.orm.jpa.vendor; 018 019import java.util.HashMap; 020import java.util.Map; 021 022import javax.persistence.EntityManager; 023import javax.persistence.EntityManagerFactory; 024import javax.persistence.spi.PersistenceProvider; 025import javax.persistence.spi.PersistenceUnitInfo; 026import javax.persistence.spi.PersistenceUnitTransactionType; 027 028import org.hibernate.cfg.AvailableSettings; 029import org.hibernate.dialect.DB2Dialect; 030import org.hibernate.dialect.DerbyTenSevenDialect; 031import org.hibernate.dialect.H2Dialect; 032import org.hibernate.dialect.HANAColumnStoreDialect; 033import org.hibernate.dialect.HSQLDialect; 034import org.hibernate.dialect.InformixDialect; 035import org.hibernate.dialect.MySQL5Dialect; 036import org.hibernate.dialect.Oracle12cDialect; 037import org.hibernate.dialect.PostgreSQL95Dialect; 038import org.hibernate.dialect.SQLServer2012Dialect; 039import org.hibernate.dialect.SybaseDialect; 040 041import org.springframework.lang.Nullable; 042 043/** 044 * {@link org.springframework.orm.jpa.JpaVendorAdapter} implementation for Hibernate 045 * EntityManager. Developed and tested against Hibernate 5.0, 5.1, 5.2, 5.3, 5.4; 046 * backwards-compatible with Hibernate 4.3 at runtime on a best-effort basis. 047 * 048 * <p>Exposes Hibernate's persistence provider and EntityManager extension interface, 049 * and adapts {@link AbstractJpaVendorAdapter}'s common configuration settings. 050 * Also supports the detection of annotated packages (through 051 * {@link org.springframework.orm.jpa.persistenceunit.SmartPersistenceUnitInfo#getManagedPackages()}), 052 * e.g. containing Hibernate {@link org.hibernate.annotations.FilterDef} annotations, 053 * along with Spring-driven entity scanning which requires no {@code persistence.xml} 054 * ({@link org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean#setPackagesToScan}). 055 * 056 * <p><b>A note about {@code HibernateJpaVendorAdapter} vs native Hibernate settings:</b> 057 * Some settings on this adapter may conflict with native Hibernate configuration rules 058 * or custom Hibernate properties. For example, specify either {@link #setDatabase} or 059 * Hibernate's "hibernate.dialect_resolvers" property, not both. Also, be careful about 060 * Hibernate's connection release mode: This adapter prefers {@code ON_CLOSE} behavior, 061 * aligned with {@link HibernateJpaDialect#setPrepareConnection}, at least for non-JTA 062 * scenarios; you may override this through corresponding native Hibernate properties. 063 * 064 * @author Juergen Hoeller 065 * @author Rod Johnson 066 * @since 2.0 067 * @see HibernateJpaDialect 068 */ 069public class HibernateJpaVendorAdapter extends AbstractJpaVendorAdapter { 070 071 private final HibernateJpaDialect jpaDialect = new HibernateJpaDialect(); 072 073 private final PersistenceProvider persistenceProvider; 074 075 private final Class<? extends EntityManagerFactory> entityManagerFactoryInterface; 076 077 private final Class<? extends EntityManager> entityManagerInterface; 078 079 080 @SuppressWarnings("deprecation") 081 public HibernateJpaVendorAdapter() { 082 this.persistenceProvider = new SpringHibernateJpaPersistenceProvider(); 083 this.entityManagerFactoryInterface = org.hibernate.jpa.HibernateEntityManagerFactory.class; 084 this.entityManagerInterface = org.hibernate.jpa.HibernateEntityManager.class; 085 } 086 087 088 /** 089 * Set whether to prepare the underlying JDBC Connection of a transactional 090 * Hibernate Session, that is, whether to apply a transaction-specific 091 * isolation level and/or the transaction's read-only flag to the underlying 092 * JDBC Connection. 093 * <p>See {@link HibernateJpaDialect#setPrepareConnection(boolean)} for details. 094 * This is just a convenience flag passed through to {@code HibernateJpaDialect}. 095 * <p>On Hibernate 5.1+, this flag remains {@code true} by default like against 096 * previous Hibernate versions. The vendor adapter manually enforces Hibernate's 097 * new connection handling mode {@code DELAYED_ACQUISITION_AND_HOLD} in that case 098 * unless a user-specified connection handling mode property indicates otherwise; 099 * switch this flag to {@code false} to avoid that interference. 100 * <p><b>NOTE: For a persistence unit with transaction type JTA e.g. on WebLogic, 101 * the connection release mode will never be altered from its provider default, 102 * i.e. not be forced to {@code DELAYED_ACQUISITION_AND_HOLD} by this flag.</b> 103 * Alternatively, set Hibernate 5.2's "hibernate.connection.handling_mode" 104 * property to "DELAYED_ACQUISITION_AND_RELEASE_AFTER_TRANSACTION" or even 105 * "DELAYED_ACQUISITION_AND_RELEASE_AFTER_STATEMENT" in such a scenario. 106 * @since 4.3.1 107 * @see PersistenceUnitInfo#getTransactionType() 108 * @see #getJpaPropertyMap(PersistenceUnitInfo) 109 * @see HibernateJpaDialect#beginTransaction 110 */ 111 public void setPrepareConnection(boolean prepareConnection) { 112 this.jpaDialect.setPrepareConnection(prepareConnection); 113 } 114 115 116 @Override 117 public PersistenceProvider getPersistenceProvider() { 118 return this.persistenceProvider; 119 } 120 121 @Override 122 public String getPersistenceProviderRootPackage() { 123 return "org.hibernate"; 124 } 125 126 @Override 127 public Map<String, Object> getJpaPropertyMap(PersistenceUnitInfo pui) { 128 return buildJpaPropertyMap(this.jpaDialect.prepareConnection && 129 pui.getTransactionType() != PersistenceUnitTransactionType.JTA); 130 } 131 132 @Override 133 public Map<String, Object> getJpaPropertyMap() { 134 return buildJpaPropertyMap(this.jpaDialect.prepareConnection); 135 } 136 137 private Map<String, Object> buildJpaPropertyMap(boolean connectionReleaseOnClose) { 138 Map<String, Object> jpaProperties = new HashMap<>(); 139 140 if (getDatabasePlatform() != null) { 141 jpaProperties.put(AvailableSettings.DIALECT, getDatabasePlatform()); 142 } 143 else { 144 Class<?> databaseDialectClass = determineDatabaseDialectClass(getDatabase()); 145 if (databaseDialectClass != null) { 146 jpaProperties.put(AvailableSettings.DIALECT, databaseDialectClass.getName()); 147 } 148 } 149 150 if (isGenerateDdl()) { 151 jpaProperties.put(AvailableSettings.HBM2DDL_AUTO, "update"); 152 } 153 if (isShowSql()) { 154 jpaProperties.put(AvailableSettings.SHOW_SQL, "true"); 155 } 156 157 if (connectionReleaseOnClose) { 158 // Hibernate 5.1+: manually enforce connection release mode ON_CLOSE (the former default) 159 try { 160 // Try Hibernate 5.2+ 161 AvailableSettings.class.getField("CONNECTION_HANDLING"); 162 jpaProperties.put("hibernate.connection.handling_mode", "DELAYED_ACQUISITION_AND_HOLD"); 163 } 164 catch (NoSuchFieldException ex) { 165 // Try Hibernate 5.1 166 try { 167 AvailableSettings.class.getField("ACQUIRE_CONNECTIONS"); 168 jpaProperties.put("hibernate.connection.release_mode", "ON_CLOSE"); 169 } 170 catch (NoSuchFieldException ex2) { 171 // on Hibernate 5.0.x or lower - no need to change the default there 172 } 173 } 174 } 175 176 return jpaProperties; 177 } 178 179 /** 180 * Determine the Hibernate database dialect class for the given target database. 181 * @param database the target database 182 * @return the Hibernate database dialect class, or {@code null} if none found 183 */ 184 @Nullable 185 protected Class<?> determineDatabaseDialectClass(Database database) { 186 switch (database) { 187 case DB2: return DB2Dialect.class; 188 case DERBY: return DerbyTenSevenDialect.class; 189 case H2: return H2Dialect.class; 190 case HANA: return HANAColumnStoreDialect.class; 191 case HSQL: return HSQLDialect.class; 192 case INFORMIX: return InformixDialect.class; 193 case MYSQL: return MySQL5Dialect.class; 194 case ORACLE: return Oracle12cDialect.class; 195 case POSTGRESQL: return PostgreSQL95Dialect.class; 196 case SQL_SERVER: return SQLServer2012Dialect.class; 197 case SYBASE: return SybaseDialect.class; 198 default: return null; 199 } 200 } 201 202 @Override 203 public HibernateJpaDialect getJpaDialect() { 204 return this.jpaDialect; 205 } 206 207 @Override 208 public Class<? extends EntityManagerFactory> getEntityManagerFactoryInterface() { 209 return this.entityManagerFactoryInterface; 210 } 211 212 @Override 213 public Class<? extends EntityManager> getEntityManagerInterface() { 214 return this.entityManagerInterface; 215 } 216 217}