在从Hibernate 4迁移到Hibernate 5时,我遇到了deprecation,并最终删除了SchemaExport(Configuration)构造函数。在Hibernate 5中,什么是一个好的替代方案?
用例
在测试期间,我们使用设置了一些属性并定义了映射资源的配置创建了一个SchemaExport实例:
// somewhere else `Properties` are filled and passed as a parameter
Properties properties = new Properties();
properties.put("hibernate.dialect", "org.hibernate.dialect.HSQLDialect");
properties.put("hibernate.connection.driver_class", "org.hsqldb.jdbc.JDBCDriver");
// more properties ...
Configuration configuration = new Configuration();
configuration.setProperties(testProperties);
// parameter `String... mappingResources`
for (final String mapping : mappingResources) {
configuration.addResource(mapping);
}
// this doesn't compile
SchemaExport schemaExport = new SchemaExport(configuration);最后一行不能在Hibernate 5上编译,因为构造函数被删除了。
选项
反对者建议使用SchemaExport(MetadataImplementor)构造函数,但我很难找到创建MetadataImplementor实例的好方法。我找到了一些选择,但它们在我看来都很可疑。
在Hibernate中我能找到的唯一的具体实现是MetadataImpl和InFlightMetadataCollectorImpl,但这两个都是在org.hibernate.boot.internal中实现的,所以我假设我不应该使用它们。此外,MetadataImpl有一个庞大的构造函数,我需要在其中提供每一个小细节,而InFlightMetadataCollectorImpl需要一个MetadataBuildingOptions,它有与MetadataImplementor相同的问题(实现是内部的,很难构造)。
或者,看起来MetadataBuilderImpl可能是构造MetadataImplementor的一种方便方法,但它也是内部的。
无论哪种方式,我都找不到如何在MetadataImplementor (或MetadataBuilderImpl )上设置Properties (或它们的条目)。
问题
创建SchemaExport真的需要MetadataImplementor吗?如果是,我如何从支持的API中获取一个,以及如何设置Properties
最终,我们希望使用execute执行一个脚本,但是这里的签名也更改了。我知道现在需要一个ServiceRegistry,所以这也许是一条出路?
编辑
啊,我刚刚看到在5.2 (我想用的)中,SchemaExport甚至不再接受MetadataImplementor --只剩下无参数的构造函数。现在怎么办?
发布于 2017-11-22 20:19:04
在Hibernate中,我们有这个基础测试类:
public class BaseNonConfigCoreFunctionalTestCase extends BaseUnitTestCase {
public static final String VALIDATE_DATA_CLEANUP = "hibernate.test.validateDataCleanup";
private StandardServiceRegistry serviceRegistry;
private MetadataImplementor metadata;
private SessionFactoryImplementor sessionFactory;
private Session session;
protected Dialect getDialect() {
if ( serviceRegistry != null ) {
return serviceRegistry.getService( JdbcEnvironment.class ).getDialect();
}
else {
return BaseCoreFunctionalTestCase.getDialect();
}
}
protected StandardServiceRegistry serviceRegistry() {
return serviceRegistry;
}
protected MetadataImplementor metadata() {
return metadata;
}
protected SessionFactoryImplementor sessionFactory() {
return sessionFactory;
}
protected Session openSession() throws HibernateException {
session = sessionFactory().openSession();
return session;
}
protected Session openSession(Interceptor interceptor) throws HibernateException {
session = sessionFactory().withOptions().interceptor( interceptor ).openSession();
return session;
}
protected Session getSession() {
return session;
}
protected void rebuildSessionFactory() {
releaseResources();
buildResources();
}
protected void cleanupCache() {
if ( sessionFactory != null ) {
sessionFactory.getCache().evictAllRegions();
}
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// JUNIT hooks
@BeforeClassOnce
@SuppressWarnings( {"UnusedDeclaration"})
protected void startUp() {
buildResources();
}
protected void buildResources() {
final StandardServiceRegistryBuilder ssrb = constructStandardServiceRegistryBuilder();
serviceRegistry = ssrb.build();
afterStandardServiceRegistryBuilt( serviceRegistry );
final MetadataSources metadataSources = new MetadataSources( serviceRegistry );
applyMetadataSources( metadataSources );
afterMetadataSourcesApplied( metadataSources );
final MetadataBuilder metadataBuilder = metadataSources.getMetadataBuilder();
initialize( metadataBuilder );
configureMetadataBuilder( metadataBuilder );
metadata = (MetadataImplementor) metadataBuilder.build();
applyCacheSettings( metadata );
afterMetadataBuilt( metadata );
final SessionFactoryBuilder sfb = metadata.getSessionFactoryBuilder();
initialize( sfb, metadata );
configureSessionFactoryBuilder( sfb );
sessionFactory = (SessionFactoryImplementor) sfb.build();
afterSessionFactoryBuilt( sessionFactory );
}
protected final StandardServiceRegistryBuilder constructStandardServiceRegistryBuilder() {
final BootstrapServiceRegistryBuilder bsrb = new BootstrapServiceRegistryBuilder();
bsrb.applyClassLoader( getClass().getClassLoader() );
// by default we do not share the BootstrapServiceRegistry nor the StandardServiceRegistry,
// so we want the BootstrapServiceRegistry to be automatically closed when the
// StandardServiceRegistry is closed.
bsrb.enableAutoClose();
configureBootstrapServiceRegistryBuilder( bsrb );
final BootstrapServiceRegistry bsr = bsrb.build();
afterBootstrapServiceRegistryBuilt( bsr );
final Map settings = new HashMap();
addSettings( settings );
final StandardServiceRegistryBuilder ssrb = new StandardServiceRegistryBuilder( bsr );
initialize( ssrb );
ssrb.applySettings( settings );
configureStandardServiceRegistryBuilder( ssrb );
return ssrb;
}
protected void addSettings(Map settings) {
}
/**
* Apply any desired config to the BootstrapServiceRegistryBuilder to be incorporated
* into the built BootstrapServiceRegistry
*
* @param bsrb The BootstrapServiceRegistryBuilder
*/
@SuppressWarnings({"SpellCheckingInspection", "UnusedParameters"})
protected void configureBootstrapServiceRegistryBuilder(BootstrapServiceRegistryBuilder bsrb) {
}
/**
* Hook to allow tests to use the BootstrapServiceRegistry if they wish
*
* @param bsr The BootstrapServiceRegistry
*/
@SuppressWarnings("UnusedParameters")
protected void afterBootstrapServiceRegistryBuilt(BootstrapServiceRegistry bsr) {
}
@SuppressWarnings("SpellCheckingInspection")
private void initialize(StandardServiceRegistryBuilder ssrb) {
final Dialect dialect = BaseCoreFunctionalTestCase.getDialect();
ssrb.applySetting( AvailableSettings.CACHE_REGION_FACTORY, CachingRegionFactory.class.getName() );
ssrb.applySetting( AvailableSettings.USE_NEW_ID_GENERATOR_MAPPINGS, "true" );
if ( createSchema() ) {
ssrb.applySetting( AvailableSettings.HBM2DDL_AUTO, "create-drop" );
final String secondSchemaName = createSecondSchema();
if ( StringHelper.isNotEmpty( secondSchemaName ) ) {
if ( !H2Dialect.class.isInstance( dialect ) ) {
// while it may be true that only H2 supports creation of a second schema via
// URL (no idea whether that is accurate), every db should support creation of schemas
// via DDL which SchemaExport can create for us. See how this is used and
// whether that usage could not just leverage that capability
throw new UnsupportedOperationException( "Only H2 dialect supports creation of second schema." );
}
Helper.createH2Schema( secondSchemaName, ssrb.getSettings() );
}
}
ssrb.applySetting( AvailableSettings.DIALECT, dialect.getClass().getName() );
}
protected boolean createSchema() {
return true;
}
protected String createSecondSchema() {
// poorly named, yes, but to keep migration easy for existing BaseCoreFunctionalTestCase
// impls I kept the same name from there
return null;
}
/**
* Apply any desired config to the StandardServiceRegistryBuilder to be incorporated
* into the built StandardServiceRegistry
*
* @param ssrb The StandardServiceRegistryBuilder
*/
@SuppressWarnings({"SpellCheckingInspection", "UnusedParameters"})
protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) {
}
/**
* Hook to allow tests to use the StandardServiceRegistry if they wish
*
* @param ssr The StandardServiceRegistry
*/
@SuppressWarnings("UnusedParameters")
protected void afterStandardServiceRegistryBuilt(StandardServiceRegistry ssr) {
}
protected void applyMetadataSources(MetadataSources metadataSources) {
for ( String mapping : getMappings() ) {
metadataSources.addResource( getBaseForMappings() + mapping );
}
for ( Class annotatedClass : getAnnotatedClasses() ) {
metadataSources.addAnnotatedClass( annotatedClass );
}
for ( String annotatedPackage : getAnnotatedPackages() ) {
metadataSources.addPackage( annotatedPackage );
}
for ( String ormXmlFile : getXmlFiles() ) {
metadataSources.addInputStream( Thread.currentThread().getContextClassLoader().getResourceAsStream( ormXmlFile ) );
}
}
protected static final String[] NO_MAPPINGS = new String[0];
protected String[] getMappings() {
return NO_MAPPINGS;
}
protected String getBaseForMappings() {
return "org/hibernate/test/";
}
protected static final Class[] NO_CLASSES = new Class[0];
protected Class[] getAnnotatedClasses() {
return NO_CLASSES;
}
protected String[] getAnnotatedPackages() {
return NO_MAPPINGS;
}
protected String[] getXmlFiles() {
return NO_MAPPINGS;
}
protected void afterMetadataSourcesApplied(MetadataSources metadataSources) {
}
protected void initialize(MetadataBuilder metadataBuilder) {
metadataBuilder.enableNewIdentifierGeneratorSupport( true );
metadataBuilder.applyImplicitNamingStrategy( ImplicitNamingStrategyLegacyJpaImpl.INSTANCE );
}
protected void configureMetadataBuilder(MetadataBuilder metadataBuilder) {
}
protected boolean overrideCacheStrategy() {
return true;
}
protected String getCacheConcurrencyStrategy() {
return null;
}
protected final void applyCacheSettings(Metadata metadata) {
if ( !overrideCacheStrategy() ) {
return;
}
if ( getCacheConcurrencyStrategy() == null ) {
return;
}
for ( PersistentClass entityBinding : metadata.getEntityBindings() ) {
if ( entityBinding.isInherited() ) {
continue;
}
boolean hasLob = false;
final Iterator props = entityBinding.getPropertyClosureIterator();
while ( props.hasNext() ) {
final Property prop = (Property) props.next();
if ( prop.getValue().isSimpleValue() ) {
if ( isLob( ( (SimpleValue) prop.getValue() ).getTypeName() ) ) {
hasLob = true;
break;
}
}
}
if ( !hasLob ) {
( ( RootClass) entityBinding ).setCacheConcurrencyStrategy( getCacheConcurrencyStrategy() );
}
}
for ( Collection collectionBinding : metadata.getCollectionBindings() ) {
boolean isLob = false;
if ( collectionBinding.getElement().isSimpleValue() ) {
isLob = isLob( ( (SimpleValue) collectionBinding.getElement() ).getTypeName() );
}
if ( !isLob ) {
collectionBinding.setCacheConcurrencyStrategy( getCacheConcurrencyStrategy() );
}
}
}
private boolean isLob(String typeName) {
return "blob".equals( typeName )
|| "clob".equals( typeName )
|| "nclob".equals( typeName )
|| Blob.class.getName().equals( typeName )
|| Clob.class.getName().equals( typeName )
|| NClob.class.getName().equals( typeName )
|| BlobType.class.getName().equals( typeName )
|| ClobType.class.getName().equals( typeName )
|| NClobType.class.getName().equals( typeName );
}
protected void afterMetadataBuilt(Metadata metadata) {
}
private void initialize(SessionFactoryBuilder sfb, Metadata metadata) {
// todo : this is where we need to apply cache settings to be like BaseCoreFunctionalTestCase
// it reads the class/collection mappings and creates corresponding
// CacheRegionDescription references.
//
// Ultimately I want those to go on MetadataBuilder, and in fact MetadataBuilder
// already defines the needed method. But for the [pattern used by the
// tests we need this as part of SessionFactoryBuilder
}
protected void configureSessionFactoryBuilder(SessionFactoryBuilder sfb) {
}
protected void afterSessionFactoryBuilt(SessionFactoryImplementor sessionFactory) {
}
@AfterClassOnce
@SuppressWarnings( {"UnusedDeclaration"})
protected void shutDown() {
releaseResources();
}
protected void releaseResources() {
if ( sessionFactory != null ) {
try {
sessionFactory.close();
}
catch (Exception e) {
System.err.println( "Unable to release SessionFactory : " + e.getMessage() );
e.printStackTrace();
}
}
sessionFactory = null;
if ( serviceRegistry != null ) {
try {
StandardServiceRegistryBuilder.destroy( serviceRegistry );
}
catch (Exception e) {
System.err.println( "Unable to release StandardServiceRegistry : " + e.getMessage() );
e.printStackTrace();
}
}
serviceRegistry=null;
}
@OnFailure
@OnExpectedFailure
@SuppressWarnings( {"UnusedDeclaration"})
public void onFailure() {
if ( rebuildSessionFactoryOnError() ) {
rebuildSessionFactory();
}
}
protected boolean rebuildSessionFactoryOnError() {
return true;
}
@Before
public final void beforeTest() throws Exception {
prepareTest();
}
protected void prepareTest() throws Exception {
}
@After
public final void afterTest() throws Exception {
completeStrayTransaction();
if ( isCleanupTestDataRequired() ) {
cleanupTestData();
}
cleanupTest();
cleanupSession();
assertAllDataRemoved();
}
private void completeStrayTransaction() {
if ( session == null ) {
// nothing to do
return;
}
if ( ( (SessionImplementor) session ).isClosed() ) {
// nothing to do
return;
}
if ( !session.isConnected() ) {
// nothing to do
return;
}
final TransactionCoordinator.TransactionDriver tdc =
( (SessionImplementor) session ).getTransactionCoordinator().getTransactionDriverControl();
if ( tdc.getStatus().canRollback() ) {
session.getTransaction().rollback();
}
}
protected boolean isCleanupTestDataRequired() {
return false;
}
protected void cleanupTestData() throws Exception {
doInHibernate(this::sessionFactory, s -> {
s.createQuery("delete from java.lang.Object").executeUpdate();
});
}
private void cleanupSession() {
if ( session != null && ! ( (SessionImplementor) session ).isClosed() ) {
session.close();
}
session = null;
}
public class RollbackWork implements Work {
public void execute(Connection connection) throws SQLException {
connection.rollback();
}
}
protected void cleanupTest() throws Exception {
}
@SuppressWarnings( {"UnnecessaryBoxing", "UnnecessaryUnboxing"})
protected void assertAllDataRemoved() {
if ( !createSchema() ) {
return; // no tables were created...
}
if ( !Boolean.getBoolean( VALIDATE_DATA_CLEANUP ) ) {
return;
}
Session tmpSession = sessionFactory.openSession();
try {
List list = tmpSession.createQuery( "select o from java.lang.Object o" ).list();
Map<String,Integer> items = new HashMap<String,Integer>();
if ( !list.isEmpty() ) {
for ( Object element : list ) {
Integer l = items.get( tmpSession.getEntityName( element ) );
if ( l == null ) {
l = 0;
}
l = l + 1 ;
items.put( tmpSession.getEntityName( element ), l );
System.out.println( "Data left: " + element );
}
fail( "Data is left in the database: " + items.toString() );
}
}
finally {
try {
tmpSession.close();
}
catch( Throwable t ) {
// intentionally empty
}
}
}
public void inSession(Consumer<SessionImplementor> action) {
log.trace( "#inSession(action)" );
inSession( sessionFactory(), action );
}
public void inTransaction(Consumer<SessionImplementor> action) {
log.trace( "#inTransaction(action)" );
inTransaction( sessionFactory(), action );
}
public void inSession(SessionFactoryImplementor sfi, Consumer<SessionImplementor> action) {
log.trace( "##inSession(SF,action)" );
try (SessionImplementor session = (SessionImplementor) sfi.openSession()) {
log.trace( "Session opened, calling action" );
action.accept( session );
log.trace( "called action" );
}
finally {
log.trace( "Session close - auto-close lock" );
}
}
public void inTransaction(SessionFactoryImplementor factory, Consumer<SessionImplementor> action) {
log.trace( "#inTransaction(factory, action)");
try (SessionImplementor session = (SessionImplementor) factory.openSession()) {
log.trace( "Session opened, calling action" );
inTransaction( session, action );
log.trace( "called action" );
}
finally {
log.trace( "Session close - auto-close lock" );
}
}
public void inTransaction(SessionImplementor session, Consumer<SessionImplementor> action) {
log.trace( "inTransaction(session,action)" );
final Transaction txn = session.beginTransaction();
log.trace( "Started transaction" );
try {
log.trace( "Calling action in txn" );
action.accept( session );
log.trace( "Called action - in txn" );
log.trace( "Committing transaction" );
txn.commit();
log.trace( "Committed transaction" );
}
catch (Exception e) {
log.tracef(
"Error calling action: %s (%s) - rolling back",
e.getClass().getName(),
e.getMessage()
);
try {
txn.rollback();
}
catch (Exception ignore) {
log.trace( "Was unable to roll back transaction" );
// really nothing else we can do here - the attempt to
// rollback already failed and there is nothing else
// to clean up.
}
throw e;
}
}
}它引导Metadata和ServiceRegistry。
因此,我们可以这样调用SchemaExport:
new SchemaExport().create( EnumSet.of( TargetType.DATABASE ), metadata() );发布于 2018-02-16 09:21:11
从其他答案中提炼出来,我不得不做以下几点:
StandardServiceRegistry standardRegistry = new StandardServiceRegistryBuilder()
.applySetting("hibernate.hbm2ddl.auto", "create")
.applySetting("hibernate.dialect", "org.hibernate.dialect.MySQLDialect")
.applySetting("hibernate.id.new_generator_mappings", "true")
.build();
MetadataSources sources = new MetadataSources(standardRegistry);
managedClassNames.forEach(sources::addAnnotatedClass);
MetadataImplementor metadata = (MetadataImplementor) sources
.getMetadataBuilder()
.build();
SchemaExport export = new SchemaExport(metadata);希望这能帮上忙
发布于 2020-06-27 20:57:23
我喜欢已经发布的淡化答案。但是这里有一些更多的细节,包括一些新的内置Hibernate枚举,这些枚举允许您在不依赖于hbm2ddl等属性文件类型设置的情况下,更有编程地使用SchemaExport类创建数据库表。
使用属性的HashMap
通常,我喜欢将所有的数据库设置都包含在Properties类型的对象中,比如Hashtable or HashMap。然后将HashMap传递给ServiceRegistry。
Map<String, String> settings = new HashMap<>();
settings.put("connection.driver_class", "com.mysql.jdbc.Driver");
settings.put("dialect", "org.hibernate.dialect.MySQLDialect");
settings.put("hibernate.connection.url", "jdbc:mysql://localhost/hibernate_examples");
settings.put("hibernate.connection.username", "root");
settings.put("hibernate.connection.password", "password");
ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().applySettings(settings).build();将JPA实体添加到MetadataSources
然后将所有带注释的JPA类添加到MetadataSources对象中:
MetadataSources metadata = new MetadataSources(serviceRegistry);
metadata.addAnnotatedClass(Player.class);使用Action和TargetType枚举
完成所有这些工作之后,就可以创建SchemaExport类并调用它的execute方法了。在执行此操作时,您可以使用TargetType.DATABASE枚举和Action.BOTH枚举,而不是将hbm2ddl放入以下设置中:
applySetting("hibernate.hbm2ddl.auto", "create")下面是它的外观:
EnumSet<TargetType> enumSet = EnumSet.of(TargetType.DATABASE);
SchemaExport schemaExport = new SchemaExport();
schemaExport.execute(enumSet, Action.BOTH, metadata.buildMetadata());如果这篇文章太长了,我很抱歉,但下面是完整的版本5 Hibernate SchemaExport代码:
Map<String, String> settings = new HashMap<>();
settings.put("connection.driver_class", "com.mysql.jdbc.Driver");
settings.put("dialect", "org.hibernate.dialect.MySQLDialect");
settings.put("hibernate.connection.url", "jdbc:mysql://localhost/jpa");
settings.put("hibernate.connection.username", "root");
settings.put("hibernate.connection.password", "password");
settings.put("hibernate.show_sql", "true");
settings.put("hibernate.format_sql", "true");
ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().applySettings(settings).build();
MetadataSources metadata = new MetadataSources(serviceRegistry);
//metadata.addAnnotatedClass(Player.class);
EnumSet<TargetType> enumSet = EnumSet.of(TargetType.DATABASE);
SchemaExport schemaExport = new SchemaExport();
schemaExport.execute(enumSet, Action.BOTH, metadata.buildMetadata());源代码可以在GitHub上找到。
https://stackoverflow.com/questions/47432115
复制相似问题