إنشاء jpa entityManager بدون pressistence.xml ملف التكوين
-
22-09-2019 - |
سؤال
هل هناك طريقة لتهيئة EntityManager
دون تحديد وحدة الثبات؟ هل يمكنك إعطاء جميع الخصائص المطلوبة لإنشاء مدير كيان؟ أنا بحاجة لإنشاء EntityManager
من القيم المحددة للمستخدم في وقت التشغيل. تحديث persistence.xml
وإعادة التجميع ليس خيارًا.
أي فكرة عن كيفية القيام بذلك أكثر من الترحيب!
المحلول
هل هناك طريقة لتهيئة
EntityManager
دون تحديد وحدة الثبات؟
يجب أن تحدد على الأقل وحدة ثبات واحدة في persistence.xml
واصف نشر.
هل يمكنك إعطاء جميع الخصائص المطلوبة لإنشاء ملف
Entitymanager
?
- سمة الاسم مطلوبة. السمات والعناصر الأخرى اختيارية. (مواصفات JPA). لذلك يجب أن يكون هذا الحد الأدنى أو أقل
persistence.xml
ملف:
<persistence>
<persistence-unit name="[REQUIRED_PERSISTENCE_UNIT_NAME_GOES_HERE]">
SOME_PROPERTIES
</persistence-unit>
</persistence>
في بيئات Java EE ،
jta-data-source
وnon-jta-data-source
يتم استخدام العناصر لتحديد اسم JNDI العالمي لمصدر بيانات JTA و/أو غير JTA لاستخدامها من قبل مزود الثبات.
لذلك إذا كان خادم التطبيق المستهدف يدعم JTA (JBOSS ، WebSphere ، Glassfish) ، persistence.xml
يشبه:
<persistence>
<persistence-unit name="[REQUIRED_PERSISTENCE_UNIT_NAME_GOES_HERE]">
<!--GLOBAL_JNDI_GOES_HERE-->
<jta-data-source>jdbc/myDS</jta-data-source>
</persistence-unit>
</persistence>
إذا كان خادم التطبيق المستهدف لا يدعم JTA (TOMCAT) ، persistence.xml
يشبه:
<persistence>
<persistence-unit name="[REQUIRED_PERSISTENCE_UNIT_NAME_GOES_HERE]">
<!--GLOBAL_JNDI_GOES_HERE-->
<non-jta-data-source>jdbc/myDS</non-jta-data-source>
</persistence-unit>
</persistence>
إذا لم يكن مصدر البيانات الخاص بك مرتبطًا بـ JNDI عالمي (على سبيل المثال ، خارج حاوية Java EE) ، فإنك عادةً ما تحدد مزود JPA ، برنامج التشغيل ، URL ، خصائص المستخدم وكلمة المرور. لكن اسم الخاصية يعتمد على مزود JPA. لذلك ، بالنسبة لـ Hibernate كمزود JPA ، الخاص بك persistence.xml
سيبدو الملف مثل:
<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>
سمة نوع المعاملة
بشكل عام ، في بيئات Java EE ، نوع المعاملة من
RESOURCE_LOCAL
يفترض أنه سيتم توفير مصدر بيانات غير JTA. في بيئة Java EE ، إذا لم يتم تحديد هذا العنصر ، فإن الافتراضي هو JTA. في بيئة Java SE ، إذا لم يتم تحديد هذا العنصر ، فهو افتراضي لـRESOURCE_LOCAL
قد يفترض.
- لضمان قابلية تطبيق Java SE ، من الضروري أن تدرج صراحة فصول الثبات المدارة المدرجة في وحدة الثبات (مواصفات JPA)
أنا بحاجة لإنشاء
EntityManager
من القيم المحددة للمستخدم في وقت التشغيل
لذا استخدم هذا:
Map addedOrOverridenProperties = new HashMap();
// Let's suppose we are using Hibernate as JPA provider
addedOrOverridenProperties.put("hibernate.show_sql", true);
Persistence.createEntityManagerFactory(<PERSISTENCE_UNIT_NAME_GOES_HERE>, addedOrOverridenProperties);
نصائح أخرى
نعم ، يمكنك بدون استخدام أي ملف XML باستخدام الربيع مثل هذا داخل فئة التكوين (أو تكوين الربيع المكافئ 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;
}
تمكنت من إنشاء EntityManager
مع Hibernate و PostgreSQL بحتة باستخدام رمز Java (مع تكوين الربيع) فيما يلي:
@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();
}
الدعوة إلى LocalContainerEntityManagerFactoryBean.afterPropertiesSet()
هو أساسى لأنه بخلاف ذلك لم يتم بناء المصنع أبدًا ، وبعد ذلك getObject()
عائدات null
وأنت تطارد بعد NullPointerException
ق طوال اليوم. > :-(
ثم عملت مع الكود التالي:
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();
حيث كان كياني هذا:
@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
}
إليك حل بدون ربيع. مأخوذة من الثوابت 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();
والسيئون 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;
}
};
}
مع JPA العادي ، على افتراض أن لديك PersistenceProvider
التنفيذ (مثل السبات) ، يمكنك استخدام ProsistenceProvider#CreateContainerentityManagerFactory (InsistenceUnitInfo Info ، Map Map) طريقة لتمهيد EntityManagerFactory
دون الحاجة persistence.xml
.
ومع ذلك ، من المزعج أن عليك تنفيذ PersistenceUnitInfo
الواجهة ، لذلك من الأفضل استخدام الربيع أو السبات الذي يدعم كلاهما bootstrapping JPA بدون أ persistence.xml
ملف:
this.nativeEntityManagerFactory = provider.createContainerEntityManagerFactory(
this.persistenceUnitInfo,
getJpaPropertyMap()
);
أين ال المثابرة يتم تنفيذها من قبل Spring محددة اطلاع على اطلاع صف دراسي.
الدفع هذه المقالة للحصول على مظاهرة لطيفة لكيفية تحقيق هذا الهدف مع السبات.
Datanucleus JPA التي أستخدمها لديها أيضًا طريقة للقيام بذلك في مستنداتها. لا حاجة لفصل الربيع ، أو التنفيذ القبيح ل PersistenceUnitInfo
.
ببساطة تفعل على النحو التالي
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);