Hibernate升级到5.2 – 创建会话工厂并替换PersistentClass以获取实体类属性
我目前正在将我的Hibernate版本升级到最新版本5.2.10。 我在HibernateUtil中替换了我创建SessionFactory的代码。
4.3.11.Final(上一篇) :
public class HibernateUtil { private HibernateUtil() {} private static SessionFactory sessionFactory; private static Configuration configuration; public static Configuration getConfiguration() { return configuration; } private static SessionFactory buildSessionFactory() { try { if(sessionFactory == null) { configuration = new Configuration(); configuration.configure("hibernate.cfg.xml"); ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder() .applySettings(configuration.getProperties()).build(); sessionFactory = configuration .buildSessionFactory(serviceRegistry); } return sessionFactory; } catch (Throwable ex) { throw new ExceptionInInitializerError(ex); } } public static SessionFactory getSessionFactory() { return buildSessionFactory(); } public static Session getSession() { Session hibernateSession = getSessionFactory().getCurrentSession(); return hibernateSession; } public static void shutdown() { getSessionFactory().close(); } }
5.2.10决赛(新):
public class HibernateUtil { private static StandardServiceRegistry registry; private static SessionFactory sessionFactory; public static SessionFactory getSessionFactory() { return buildSessionFactory(); } public static SessionFactory buildSessionFactory() { if (sessionFactory == null) { try { registry = new StandardServiceRegistryBuilder().configure("hibernate.cfg.xml").build(); MetadataSources sources = new MetadataSources(registry); Metadata metadata = sources.getMetadataBuilder().build(); sessionFactory = metadata.getSessionFactoryBuilder().build(); } catch (Exception e) { e.printStackTrace(); shutdown(); } } return sessionFactory; } public static Session getSession() { Session hibernateSession = getSessionFactory().getCurrentSession(); return hibernateSession; } public static void shutdown() { if (registry != null) { StandardServiceRegistryBuilder.destroy(registry); } } }
现在我有一个方法,通过将DB表名称作为字符串传递来获取列名列表。 我之前在4.3.11.Final这样做过:
public static List getColumnNames(String tableName) { List columnList=null; Map map = HibernateUtil.getSessionFactory().getAllClassMetadata(); Iterator<Entry> itr = map.entrySet().iterator(); while(itr.hasNext()){ ClassMetadata classMetaData = itr.next().getValue(); AbstractEntityPersister aep = (AbstractEntityPersister) classMetaData; if(aep.getTableName().split("\\.")[1].equalsIgnoreCase(tableName)){ columnList = new ArrayList(); String[] propertyNames = classMetaData.getPropertyNames(); for(String property : propertyNames){ try { PersistentClass persistentClass = HibernateUtil .getConfiguration().getClassMapping(classMetaData.getEntityName()); String clmName = ((Column) persistentClass.getProperty(property).getColumnIterator().next()).getName(); columnList.add(clmName); } catch(NoSuchElementException e){ log.error("Element not found idenfied as : "+property); } catch(Exception e){ log.error(e.getMessage()); } } break; } } return columnList; }
现在升级后,它将方法getAllClassMetadata显示为已弃用,并且很难获得PersistentClass对象。 我在这里看到了类似的问题,但我无法弄清楚解决方案。 我必须更改当前代码的哪一部分,以使我的getColumnNames()方法完全像以前一样工作。 我提到了文档,它说要使用EntityManagerFactory.getMetamodel()
但我找不到合适的参考例子。 我还要为此更改SessionFactory创建机制吗?
好问题。 事实上,我非常喜欢它,所以我写了一篇关于它的文章 。
首先,我们需要创建一个新的Integrator
:
public class MetadataExtractorIntegrator implements org.hibernate.integrator.spi.Integrator { public static final MetadataExtractorIntegrator INSTANCE = new MetadataExtractorIntegrator(); private Database database; @Override public void integrate( Metadata metadata, SessionFactoryImplementor sessionFactory, SessionFactoryServiceRegistry serviceRegistry) { database = metadata.getDatabase(); } @Override public void disintegrate( SessionFactoryImplementor sessionFactory, SessionFactoryServiceRegistry serviceRegistry) { } public Database getDatabase() { return database; } }
然后,我们可以配置Hibernate来使用它。
如果您正在使用Hibernate引导机制,那么您可以像这样添加它:
final BootstrapServiceRegistryBuilder bsrb = new BootstrapServiceRegistryBuilder(); bsrb.enableAutoClose(); Integrator integrator = integrator(); if (integrator != null) { bsrb.applyIntegrator( integrator ); } final BootstrapServiceRegistry bsr = bsrb.build(); final StandardServiceRegistryBuilder ssrb = new StandardServiceRegistryBuilder(bsr);
如果你使用JPA进行自举,那么你可以按如下方式进行:
protected EntityManagerFactory newEntityManagerFactory() { PersistenceUnitInfo persistenceUnitInfo = persistenceUnitInfo( getClass().getSimpleName() ); Map configuration = new HashMap<>(); configuration.put("hibernate.integrator_provider", (IntegratorProvider) () -> Collections.singletonList( MetadataExtractorIntegrator.INSTANCE ) ); EntityManagerFactoryBuilderImpl entityManagerFactoryBuilder = new EntityManagerFactoryBuilderImpl( new PersistenceUnitInfoDescriptor(persistenceUnitInfo), configuration ); return entityManagerFactoryBuilder.build(); }
现在,在运行以下测试时:
for(Namespace namespace : MetadataExtractorIntegrator.INSTANCE .getDatabase() .getNamespaces()) { for( Table table : namespace.getTables()) { LOGGER.info( "Table {} has the following columns: {}", table, StreamSupport.stream( Spliterators.spliteratorUnknownSize( table.getColumnIterator(), Spliterator.ORDERED ), false ) .collect( Collectors.toList()) ); } }
Hibernate输出日志中所有当前映射的表:
Table org.hibernate.mapping.Table(post) has the following columns: [ org.hibernate.mapping.Column(id), org.hibernate.mapping.Column(title), org.hibernate.mapping.Column(version) ] Table org.hibernate.mapping.Table(post_comment) has the following columns: [ org.hibernate.mapping.Column(id), org.hibernate.mapping.Column(review), org.hibernate.mapping.Column(version), org.hibernate.mapping.Column(post_id) ] Table org.hibernate.mapping.Table(post_details) has the following columns: [ org.hibernate.mapping.Column(id), org.hibernate.mapping.Column(created_by), org.hibernate.mapping.Column(created_on), org.hibernate.mapping.Column(version) ] Table org.hibernate.mapping.Table(post_tag) has the following columns: [ org.hibernate.mapping.Column(post_id), org.hibernate.mapping.Column(tag_id) ] Table org.hibernate.mapping.Table(tag) has the following columns: [ org.hibernate.mapping.Column(id), org.hibernate.mapping.Column(name), org.hibernate.mapping.Column(version) ]
而已!
最后我感谢弗拉德的文章。 我没有任何更改地采用了积分器代码,并修改了我的HibernateUtil
和getColumns()
方法。 所以这是我的代码:
SessionFactory创建:
public class HibernateUtil { private static final SessionFactory sessionFactory = buildSessionFactory(); public static SessionFactory getSessionFactory() { return buildSessionFactory(); } private static SessionFactory buildSessionFactory() { final BootstrapServiceRegistry bootstrapServiceRegistry = new BootstrapServiceRegistryBuilder().enableAutoClose() .applyIntegrator(MetadataExtractorIntegrator.INSTANCE).build(); final StandardServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder(bootstrapServiceRegistry).configure().build(); return new MetadataSources(serviceRegistry).buildMetadata().buildSessionFactory(); } public static Session getSession() { Session hibernateSession = getSessionFactory().getCurrentSession(); return hibernateSession; } public static void shutdown() { getSessionFactory().close(); } }
元数据提取器(获取列名称):
public static List getColumnNames(String tableName) { List columnList = new ArrayList<>(); for (Namespace namespace : MetadataExtractorIntegrator.INSTANCE.getDatabase().getNamespaces()) { for (Table table : namespace.getTables()) { if (table.getName().equalsIgnoreCase(lookupTableName)) { Iterator iterator = table.getColumnIterator(); while (iterator.hasNext()) { columnList.add(iterator.next().getName()); } break; } } if (!columnList.isEmpty()) break; } return columnList; }
使用hibernate 5获取列名的更简单方法
final AbstractEntityPersister classMetadata = (AbstractEntityPersister) sessionFactory.getClassMetadata(clazz) final String[] names = classMetadata.getPropertyColumnNames(property)
- Hibernate / JPA + Derby – SELECT语句在GROUP BY,ORDER BY或选择列表中包含太多项
- 何时使用Spring JPA(Hibernate)实体管理器将连接返回到连接池?
- Sprint引导数据JPA:没有类型为’java.util.Set ‘的限定bean
- 启动时出现Hibernateexception
- 在hyperjaxb中自定义hibernate属性
- HibernateException:找到同一集合的两个表示
- 调用entityManager.getTransaction()时的EJBException
- Weblogic错误:由以下原因引起:weblogic.transaction.internal.AppSetRollbackOnlyException:在事务上调用setRollbackOnly
- JPA 1还不够好