Czy istnieje sposób na zainicjowanie EntityManager
bez zdefiniowanej jednostki trwałości?
W deskryptorze wdrażania należy zdefiniować co najmniej jedną jednostkę trwałości persistence.xml
.
Czy możesz podać wszystkie wymagane właściwości, aby utworzyć Entitymanager
?
- Atrybut nazwy jest wymagany. Pozostałe atrybuty i elementy są opcjonalne. (Specyfikacja JPA). Powinien to być mniej więcej twój minimalny
persistence.xml
plik:
<persistence>
<persistence-unit name="[REQUIRED_PERSISTENCE_UNIT_NAME_GOES_HERE]">
SOME_PROPERTIES
</persistence-unit>
</persistence>
W środowiskach Java EE elementy jta-data-source
i non-jta-data-source
są używane do określenia globalnej nazwy JNDI źródła danych JTA i / lub innego źródła danych, które ma być używane przez dostawcę trwałości.
Jeśli więc twój docelowy serwer aplikacji obsługuje JTA (JBoss, Websphere, GlassFish), Twój persistence.xml
wygląd będzie wyglądał następująco:
<persistence>
<persistence-unit name="[REQUIRED_PERSISTENCE_UNIT_NAME_GOES_HERE]">
<jta-data-source>jdbc/myDS</jta-data-source>
</persistence-unit>
</persistence>
Jeśli docelowy serwer aplikacji nie obsługuje JTA (Tomcat), Twój persistence.xml
wygląd wygląda następująco:
<persistence>
<persistence-unit name="[REQUIRED_PERSISTENCE_UNIT_NAME_GOES_HERE]">
<non-jta-data-source>jdbc/myDS</non-jta-data-source>
</persistence-unit>
</persistence>
Jeśli źródło danych nie jest powiązane z globalnym JNDI (na przykład poza kontenerem Java EE), zwykle definiuje się dostawcę JPA, sterownik, adres URL, właściwości użytkownika i hasło. Ale nazwa właściwości zależy od dostawcy JPA. Tak więc dla Hibernate jako dostawcy JPA persistence.xml
plik będzie wyglądał następująco:
<persistence>
<persistence-unit name="[REQUIRED_PERSISTENCE_UNIT_NAME_GOES_HERE]">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<class>br.com.persistence.SomeClass</class>
<properties>
<property name="hibernate.connection.driver_class" value="org.apache.derby.jdbc.ClientDriver"/>
<property name="hibernate.connection.url" value="jdbc:derby://localhost:1527/EmpServDB;create=true"/>
<property name="hibernate.connection.username" value="APP"/>
<property name="hibernate.connection.password" value="APP"/>
</properties>
</persistence-unit>
</persistence>
Atrybut typu transakcji
Ogólnie w środowiskach Java EE typ transakcji RESOURCE_LOCAL
zakłada, że zostanie dostarczone źródło danych inne niż JTA. W środowisku Java EE, jeśli ten element nie jest określony, wartością domyślną jest JTA. W środowisku Java SE, jeśli ten element nie jest określony, RESOURCE_LOCAL
można przyjąć wartość domyślną .
- Aby zapewnić przenośność aplikacji Java SE, konieczne jest jawne podanie zarządzanych klas trwałości, które są zawarte w jednostce trwałości (specyfikacja JPA)
Muszę utworzyć EntityManager
z wartości określonych przez użytkownika w czasie wykonywania
Więc użyj tego:
Map addedOrOverridenProperties = new HashMap();
addedOrOverridenProperties.put("hibernate.show_sql", true);
Persistence.createEntityManagerFactory(<PERSISTENCE_UNIT_NAME_GOES_HERE>, addedOrOverridenProperties);
Tak, możesz bez używania żadnego pliku xml, używając spring w taki sposób, jak to w klasie @Configuration (lub jej odpowiednika spring config xml):
@Bean public LocalContainerEntityManagerFactoryBean emf(){ properties.put("javax.persistence.jdbc.driver", dbDriverClassName); properties.put("javax.persistence.jdbc.url", dbConnectionURL); properties.put("javax.persistence.jdbc.user", dbUser); //if needed LocalContainerEntityManagerFactoryBean emf = new LocalContainerEntityManagerFactoryBean(); emf.setPersistenceProviderClass(org.eclipse.persistence.jpa.PersistenceProvider.class); //If your using eclipse or change it to whatever you're using emf.setPackagesToScan("com.yourpkg"); //The packages to search for Entities, line required to avoid looking into the persistence.xml emf.setPersistenceUnitName(SysConstants.SysConfigPU); emf.setJpaPropertyMap(properties); emf.setLoadTimeWeaver(new ReflectiveLoadTimeWeaver()); //required unless you know what your doing return emf; }
źródło
properties
?Oto rozwiązanie bez Springa. Stałe pobierane są z
org.hibernate.cfg.AvailableSettings
:entityManagerFactory = new HibernatePersistenceProvider().createContainerEntityManagerFactory( archiverPersistenceUnitInfo(), ImmutableMap.<String, Object>builder() .put(JPA_JDBC_DRIVER, JDBC_DRIVER) .put(JPA_JDBC_URL, JDBC_URL) .put(DIALECT, Oracle12cDialect.class) .put(HBM2DDL_AUTO, CREATE) .put(SHOW_SQL, false) .put(QUERY_STARTUP_CHECKING, false) .put(GENERATE_STATISTICS, false) .put(USE_REFLECTION_OPTIMIZER, false) .put(USE_SECOND_LEVEL_CACHE, false) .put(USE_QUERY_CACHE, false) .put(USE_STRUCTURED_CACHE, false) .put(STATEMENT_BATCH_SIZE, 20) .build()); entityManager = entityManagerFactory.createEntityManager();
I niesławny
PersistenceUnitInfo
private static PersistenceUnitInfo archiverPersistenceUnitInfo() { return new PersistenceUnitInfo() { @Override public String getPersistenceUnitName() { return "ApplicationPersistenceUnit"; } @Override public String getPersistenceProviderClassName() { return "org.hibernate.jpa.HibernatePersistenceProvider"; } @Override public PersistenceUnitTransactionType getTransactionType() { return PersistenceUnitTransactionType.RESOURCE_LOCAL; } @Override public DataSource getJtaDataSource() { return null; } @Override public DataSource getNonJtaDataSource() { return null; } @Override public List<String> getMappingFileNames() { return Collections.emptyList(); } @Override public List<URL> getJarFileUrls() { try { return Collections.list(this.getClass() .getClassLoader() .getResources("")); } catch (IOException e) { throw new UncheckedIOException(e); } } @Override public URL getPersistenceUnitRootUrl() { return null; } @Override public List<String> getManagedClassNames() { return Collections.emptyList(); } @Override public boolean excludeUnlistedClasses() { return false; } @Override public SharedCacheMode getSharedCacheMode() { return null; } @Override public ValidationMode getValidationMode() { return null; } @Override public Properties getProperties() { return new Properties(); } @Override public String getPersistenceXMLSchemaVersion() { return null; } @Override public ClassLoader getClassLoader() { return null; } @Override public void addTransformer(ClassTransformer transformer) { } @Override public ClassLoader getNewTempClassLoader() { return null; } }; }
źródło
Udało mi się stworzyć za
EntityManager
pomocą Hibernate i PostgreSQL wyłącznie przy użyciu kodu Java (z konfiguracją Spring):@Bean public DataSource dataSource() { final PGSimpleDataSource dataSource = new PGSimpleDataSource(); dataSource.setDatabaseName( "mytestdb" ); dataSource.setUser( "myuser" ); dataSource.setPassword("mypass"); return dataSource; } @Bean public Properties hibernateProperties(){ final Properties properties = new Properties(); properties.put( "hibernate.dialect", "org.hibernate.dialect.PostgreSQLDialect" ); properties.put( "hibernate.connection.driver_class", "org.postgresql.Driver" ); properties.put( "hibernate.hbm2ddl.auto", "create-drop" ); return properties; } @Bean public EntityManagerFactory entityManagerFactory( DataSource dataSource, Properties hibernateProperties ){ final LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean(); em.setDataSource( dataSource ); em.setPackagesToScan( "net.initech.domain" ); em.setJpaVendorAdapter( new HibernateJpaVendorAdapter() ); em.setJpaProperties( hibernateProperties ); em.setPersistenceUnitName( "mytestdomain" ); em.setPersistenceProviderClass(HibernatePersistenceProvider.class); em.afterPropertiesSet(); return em.getObject(); }
Telefon
LocalContainerEntityManagerFactoryBean.afterPropertiesSet()
jest niezbędny, ponieważ w przeciwnym razie fabryka nigdy nie zostanie zbudowana, a potemgetObject()
wróci,null
a ty gonisz za nią przezNullPointerException
cały dzień. > :-(Następnie działał z następującym kodem:
PageEntry pe = new PageEntry(); pe.setLinkName( "Google" ); pe.setLinkDestination( new URL( "http://www.google.com" ) ); EntityTransaction entTrans = entityManager.getTransaction(); entTrans.begin(); entityManager.persist( pe ); entTrans.commit();
Gdzie moja istota była taka:
@Entity @Table(name = "page_entries") public class PageEntry { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private long id; private String linkName; private URL linkDestination; // gets & setters omitted }
źródło
W przypadku zwykłego JPA, zakładając, że masz
PersistenceProvider
implementację (np. Hibernate), możesz użyć metody PersistenceProvider # createContainerEntityManagerFactory (PersistenceUnitInfo info, Map map) , aby załadować plikEntityManagerFactory
bez konieczności używania plikupersistence.xml
.Jednak denerwujące jest to, że musisz zaimplementować
PersistenceUnitInfo
interfejs, więc lepiej jest użyć Spring lub Hibernate, które obsługują ładowanie JPA bezpersistence.xml
pliku:this.nativeEntityManagerFactory = provider.createContainerEntityManagerFactory( this.persistenceUnitInfo, getJpaPropertyMap() );
Gdzie PersistenceUnitInfo jest implementowana przez klasę MutablePersistenceUnitInfo specyficzną dla Spring .
źródło
MutablePersistenceUnitInfo
nie działa, ponieważ niektóre metody zgłaszają wyjątek UnsupportedOperationException . Również wspomniany artykuł jest nieco nieaktualny:getPersistenceUnitRootUrl
nie może zwrócić wartości null, w przeciwnym razie Hibernate nie skanuje ścieżki klas (Hibernate 5.2.8).getPersistenceUnitRootUrl
lubgetJarFileUrls
. Później wysiewa się na stackoverflow.com/a/42372648/48136DataNucleus JPA, którego używam, również ma sposób na zrobienie tego w swoich dokumentach . Nie potrzeba wiosny ani brzydkiej implementacji
PersistenceUnitInfo
.Po prostu wykonaj następujące czynności
import org.datanucleus.metadata.PersistenceUnitMetaData; import org.datanucleus.api.jpa.JPAEntityManagerFactory; PersistenceUnitMetaData pumd = new PersistenceUnitMetaData("dynamic-unit", "RESOURCE_LOCAL", null); pumd.addClassName("mydomain.test.A"); pumd.setExcludeUnlistedClasses(); pumd.addProperty("javax.persistence.jdbc.url", "jdbc:h2:mem:nucleus"); pumd.addProperty("javax.persistence.jdbc.user", "sa"); pumd.addProperty("javax.persistence.jdbc.password", ""); pumd.addProperty("datanucleus.schema.autoCreateAll", "true"); EntityManagerFactory emf = new JPAEntityManagerFactory(pumd, null);
źródło
Możesz również uzyskać EntityManager za pomocą adnotacji PersistenceContext lub Autowired, ale pamiętaj, że nie będzie to bezpieczne wątkowo.
@PersistenceContext private EntityManager entityManager;
źródło