Polish contribution

Closes gh-7796
This commit is contained in:
Stephane Nicoll 2017-01-03 11:25:17 +01:00
parent 24c83d12da
commit fe89af5e82
6 changed files with 86 additions and 35 deletions

View File

@ -23,9 +23,8 @@ import org.springframework.orm.jpa.vendor.Database;
* Mapper between {@link Database} and {@link DatabaseDriver}. * Mapper between {@link Database} and {@link DatabaseDriver}.
* *
* @author Eddú Meléndez * @author Eddú Meléndez
* @version 1.5.0
*/ */
public enum DatabasePlatform { enum DatabasePlatform {
DB2(Database.DB2, DatabaseDriver.DB2), DB2(Database.DB2, DatabaseDriver.DB2),

View File

@ -41,8 +41,6 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.Primary; import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.support.JdbcUtils;
import org.springframework.jdbc.support.MetaDataAccessException;
import org.springframework.orm.jpa.JpaTransactionManager; import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.JpaVendorAdapter; import org.springframework.orm.jpa.JpaVendorAdapter;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
@ -104,14 +102,7 @@ public abstract class JpaBaseConfiguration implements BeanFactoryAware {
public JpaVendorAdapter jpaVendorAdapter() { public JpaVendorAdapter jpaVendorAdapter() {
AbstractJpaVendorAdapter adapter = createJpaVendorAdapter(); AbstractJpaVendorAdapter adapter = createJpaVendorAdapter();
adapter.setShowSql(this.properties.isShowSql()); adapter.setShowSql(this.properties.isShowSql());
try { adapter.setDatabase(this.properties.determineDatabase(this.dataSource));
String jdbcUrl = (String) JdbcUtils.extractDatabaseMetaData(this.dataSource,
"getURL");
adapter.setDatabase(this.properties.determineDatabase(jdbcUrl));
}
catch (MetaDataAccessException ex) {
throw new IllegalStateException("Unable to detect database type", ex);
}
adapter.setDatabasePlatform(this.properties.getDatabasePlatform()); adapter.setDatabasePlatform(this.properties.getDatabasePlatform());
adapter.setGenerateDdl(this.properties.isGenerateDdl()); adapter.setGenerateDdl(this.properties.isGenerateDdl());
return adapter; return adapter;

View File

@ -21,10 +21,15 @@ import java.util.Map;
import javax.sql.DataSource; import javax.sql.DataSource;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.boot.autoconfigure.jdbc.EmbeddedDatabaseConnection; import org.springframework.boot.autoconfigure.jdbc.EmbeddedDatabaseConnection;
import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.NestedConfigurationProperty; import org.springframework.boot.context.properties.NestedConfigurationProperty;
import org.springframework.boot.jdbc.DatabaseDriver; import org.springframework.boot.jdbc.DatabaseDriver;
import org.springframework.jdbc.support.JdbcUtils;
import org.springframework.jdbc.support.MetaDataAccessException;
import org.springframework.orm.jpa.vendor.Database; import org.springframework.orm.jpa.vendor.Database;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
@ -40,6 +45,8 @@ import org.springframework.util.StringUtils;
@ConfigurationProperties(prefix = "spring.jpa") @ConfigurationProperties(prefix = "spring.jpa")
public class JpaProperties { public class JpaProperties {
private static final Log logger = LogFactory.getLog(JpaProperties.class);
/** /**
* Additional native properties to set on the JPA provider. * Additional native properties to set on the JPA provider.
*/ */
@ -55,7 +62,7 @@ public class JpaProperties {
* Target database to operate on, auto-detected by default. Can be alternatively set * Target database to operate on, auto-detected by default. Can be alternatively set
* using the "databasePlatform" property. * using the "databasePlatform" property.
*/ */
private Database database = Database.DEFAULT; private Database database;
/** /**
* Initialize the schema on startup. * Initialize the schema on startup.
@ -128,17 +135,28 @@ public class JpaProperties {
} }
/** /**
* Return the database form the jdbc url or the value for `spring.jpa.database`. * Determine the {@link Database} to use based on this configuration and the primary
* @param jdbcUrl the url from `spring.datasource.url` * {@link DataSource}.
* @param dataSource the auto-configured data source
* @return {@code Database} * @return {@code Database}
*/ */
public Database determineDatabase(String jdbcUrl) { public Database determineDatabase(DataSource dataSource) {
DatabasePlatform databasePlatform = DatabasePlatform.fromDatabaseDriver( if (this.database != null) {
DatabaseDriver.fromJdbcUrl(jdbcUrl)); return this.database;
if (databasePlatform != null) {
return databasePlatform.getDatabase();
} }
return this.database; try {
String jdbcUrl = (String) JdbcUtils.extractDatabaseMetaData(dataSource,
"getURL");
DatabasePlatform databasePlatform = DatabasePlatform.fromDatabaseDriver(
DatabaseDriver.fromJdbcUrl(jdbcUrl));
if (databasePlatform != null) {
return databasePlatform.getDatabase();
}
}
catch (MetaDataAccessException ex) {
logger.warn("Unable to determine jdbc url from datasource", ex);
}
return Database.DEFAULT;
} }
public static class Hibernate { public static class Hibernate {

View File

@ -64,10 +64,10 @@ public class CustomHibernateJpaAutoConfigurationTests {
// Set up environment so we get a MySQL database but don't require server to be // Set up environment so we get a MySQL database but don't require server to be
// running... // running...
EnvironmentTestUtils.addEnvironment(this.context, EnvironmentTestUtils.addEnvironment(this.context,
"spring.datasource.driverClassName:com.mysql.jdbc.Driver", "spring.datasource.database:mysql",
"spring.datasource.url:jdbc:mysql://localhost/nonexistent", "spring.datasource.url:jdbc:mysql://localhost/nonexistent",
"spring.datasource.initialize:false", "spring.jpa.database:MYSQL"); "spring.datasource.initialize:false", "spring.jpa.database:MYSQL");
this.context.register(TestConfiguration.class, MockDataSourceConfiguration.class, this.context.register(TestConfiguration.class, DataSourceAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class,
HibernateJpaAutoConfiguration.class); HibernateJpaAutoConfiguration.class);
this.context.refresh(); this.context.refresh();
@ -114,7 +114,6 @@ public class CustomHibernateJpaAutoConfigurationTests {
@Test @Test
public void testDefaultDatabaseForH2() throws Exception { public void testDefaultDatabaseForH2() throws Exception {
EnvironmentTestUtils.addEnvironment(this.context, EnvironmentTestUtils.addEnvironment(this.context,
"spring.datasource.driverClassName:org.h2.Driver",
"spring.datasource.url:jdbc:h2:mem:testdb", "spring.datasource.url:jdbc:h2:mem:testdb",
"spring.datasource.initialize:false"); "spring.datasource.initialize:false");
this.context.register(TestConfiguration.class, DataSourceAutoConfiguration.class, this.context.register(TestConfiguration.class, DataSourceAutoConfiguration.class,

View File

@ -16,6 +16,8 @@
package org.springframework.boot.autoconfigure.orm.jpa; package org.springframework.boot.autoconfigure.orm.jpa;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.Map; import java.util.Map;
@ -38,6 +40,8 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.entry; import static org.assertj.core.api.Assertions.entry;
import static org.mockito.BDDMockito.given; import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
/** /**
* Tests for {@link JpaProperties}. * Tests for {@link JpaProperties}.
@ -168,16 +172,36 @@ public class JpaPropertiesTests {
} }
@Test @Test
public void determineH2DatabaseWhenJdbcUrlIsProvided() { public void determineDatabaseNoCheckIfDatabaseIsSet() throws SQLException {
JpaProperties properties = load(HibernateVersion.V5,
"spring.jpa.database=postgresql");
DataSource dataSource = mockStandaloneDataSource();
Database database = properties.determineDatabase(dataSource);
assertThat(database).isEqualTo(Database.POSTGRESQL);
verify(dataSource, never()).getConnection();
}
@Test
public void determineDatabaseWithKnownUrl() {
JpaProperties properties = load(HibernateVersion.V5); JpaProperties properties = load(HibernateVersion.V5);
Database database = properties.determineDatabase("jdbc:h2:mem:testdb"); Database database = properties.determineDatabase(
mockDataSource("jdbc:h2:mem:testdb"));
assertThat(database).isEqualTo(Database.H2); assertThat(database).isEqualTo(Database.H2);
} }
@Test @Test
public void determineDefaultDatabaseWhenJdbcUrlIsProvided() { public void determineDatabaseWithKnownUrlAndUserConfig() {
JpaProperties properties = load(HibernateVersion.V5, "spring.jpa.database=mysql");
Database database = properties.determineDatabase(
mockDataSource("jdbc:h2:mem:testdb"));
assertThat(database).isEqualTo(Database.MYSQL);
}
@Test
public void determineDatabaseWithUnknownUrl() {
JpaProperties properties = load(HibernateVersion.V5); JpaProperties properties = load(HibernateVersion.V5);
Database database = properties.determineDatabase("jdbc:unknown://localhost"); Database database = properties.determineDatabase(
mockDataSource("jdbc:unknown://localhost"));
assertThat(database).isEqualTo(Database.DEFAULT); assertThat(database).isEqualTo(Database.DEFAULT);
} }
@ -188,6 +212,21 @@ public class JpaPropertiesTests {
return ds; return ds;
} }
private DataSource mockDataSource(String jdbcUrl) {
DataSource ds = mock(DataSource.class);
try {
DatabaseMetaData metadata = mock(DatabaseMetaData.class);
given(metadata.getURL()).willReturn(jdbcUrl);
Connection connection = mock(Connection.class);
given(connection.getMetaData()).willReturn(metadata);
given(ds.getConnection()).willReturn(connection);
}
catch (SQLException e) {
//Do nothing
}
return ds;
}
private JpaProperties load(HibernateVersion hibernateVersion, String... environment) { private JpaProperties load(HibernateVersion hibernateVersion, String... environment) {
HibernateVersion.setRunning(hibernateVersion); HibernateVersion.setRunning(hibernateVersion);
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();

View File

@ -1797,20 +1797,25 @@ annotation, e.g.
=== Configure JPA properties === Configure JPA properties
Spring Data JPA already provides some vendor-independent configuration options (e.g. Spring Data JPA already provides some vendor-independent configuration options (e.g.
for SQL logging) and Spring Boot exposes those, and a few more for hibernate as external for SQL logging) and Spring Boot exposes those, and a few more for hibernate as external
configuration properties. The most common options to set are: configuration properties. Some of them are automatically detected according to the context
so you shouldn't have to set them.
The `spring.jpa.hibernate.ddl-auto` is a special case in that it has different defaults
depending on whether you are using an embedded database (`create-drop`) or not (`none`).
The dialect to use is also automatically detected based on the current `DataSource` but
you can set `spring.jpa.database` yourself if you want to be explicit and bypass that
check on startup.
The most common options to set are:
[indent=0,subs="verbatim,quotes,attributes"] [indent=0,subs="verbatim,quotes,attributes"]
---- ----
spring.jpa.hibernate.ddl-auto=create-drop
spring.jpa.hibernate.naming.physical-strategy=com.example.MyPhysicalNamingStrategy spring.jpa.hibernate.naming.physical-strategy=com.example.MyPhysicalNamingStrategy
spring.jpa.database=H2
spring.jpa.show-sql=true spring.jpa.show-sql=true
---- ----
The `ddl-auto` setting is a special case in that it has different defaults depending on In addition all properties in `+spring.jpa.properties.*+` are passed through as normal JPA
whether you are using an embedded database (`create-drop`) or not (`none`). In addition properties (with the prefix stripped) when the local `EntityManagerFactory` is created.
all properties in `+spring.jpa.properties.*+` are passed through as normal JPA properties
(with the prefix stripped) when the local `EntityManagerFactory` is created.
Spring Boot provides a consistent naming strategy regardless of the Hibernate generation Spring Boot provides a consistent naming strategy regardless of the Hibernate generation
that you are using. If you are using Hibernate 4, you can customize it using that you are using. If you are using Hibernate 4, you can customize it using