It looks to me as though support for multi tenancy has been added to hibernate for nearly six months now and updated at least once since.
It looks fairly trivial to obtain a multi-tenant Session outside of JPA:
Session session = sessionFactory.withOptions().tenantIdentifier( "jboss" ).openSession();
But how would you enable it in an application that uses hibernate via JPA? (If possible).
Thanks in advance.
You can configure it via properties in persistence.xml as follows:
<property name="hibernate.multiTenancy" value="DATABASE"/>
<property name="hibernate.multi_tenant_connection_provider" value="com.example.MyConnectionProvider" />
<property name="hibernate.tenant_identifier_resolver" value="com.example.MyTenantIdResolver" />
If you use SCHEMA as multi-tenancy strategy hibernate.multi_tenant_connection_provider is not needed.
You can also set these properties in your code and pass them in a map to Persistence.createEntityManagerFactory(). In this case you can pass an object instance, not just a class name.
More info in Hibernate documentation.
EntityManager.getDelegate() will return underlying SessionImpl.
Related
I usually use a persistence.xml to configure hibernate, via properties like
<properties>
<property name="javax.persistence.lock.timeout" value="90000"/>
<property name="javax.persistence.query.timeout" value="90000" />
<property name="hibernate.dialect" value="org.hibernate.dialect.SQLServer2012Dialect" />
<!-- ... -->
However, I need to change one property at runtime (more specifically I need to adjust the value of javax.persistence.query.timeout at runtime). Therefore I tried configuring the session manually in situations where I need non-default properties, like that:
Configuration config = new Configuration();
config.addResource("persistence.xml");
config.setProperty("javax.persistence.query.timeout", "100000");
Session session = config.buildSessionFactory().getCurrentSession();
However, this yields the following exception:
org.hibernate.boot.MappingNotFoundException: Mapping (RESOURCE) not found : persistence.xml : origin(persistence.xml)
Which makes sense, as the persistence.xml isn't a normal hibernate resource file. So how do I set the configuration on the basis of the persistenc.xml (I don't want to configure all the properties twice)? Or more generally, how do I reconfigure hibernate at runtime?
Note that this is similar to, but not duplicating (as it's more specific), this post.
It can be overridden/set per query:
query.setHint("javax.persistence.query.timeout", 5000); // 5 seconds
If your query object is of type org.hibernate.Query you can do:
query.setTimeout(5);
https://docs.jboss.org/hibernate/orm/3.2/api/org/hibernate/Query.html#setTimeout(int)
Changing the properties in the EntityManagerFactory at runtime (To affect all queries) will not change the configuration in effect.
You can create a new EntityManagerFactory altogether if you want to, described here:
Changing Persistence Unit dynamically - JPA
I have this hibernate.transaction.manager_lookup_class property in my persistence.xml, Then i have this warning message when running my application.
Using deprecated org.hibernate.transaction.TransactionManagerLookup strategy [hibernate.transaction.manager_lookup_class], use newer org.hibernate.service.jta.platform.spi.JtaPlatform strategy instead [hibernate.transaction.jta.platform]
I don't know what is the different between the 2 properties ? And what is the use of them ?
Could anyone explain the difference and the use of them
I'm using hibernate 4 with websphere 8.5
The JtaPlatform offers more transaction-like integrations besides just the transaction manager, notably:
how to locate transaction manager
how to user transaction
how to register transaction synchronization
You can see the full JtaPlatform interface on GitHub here: https://github.com/hibernate/hibernate-orm/blob/master/hibernate-core/src/main/java/org/hibernate/engine/transaction/jta/platform/spi/JtaPlatform.java
Replace the following:
<property name = "hibernate.transaction.manager_lookup_class" value="org.hibernate.transaction.JBossTransactionManagerLookup"/>
with
<property name = "hibernate.transaction.jta.platform" value ="org.hibernate.service.jta.platform.internal.JBossAppServerJtaPlatform"/>
in the Hibernate configuration/persistence.xml.
I'm trying to write a Hibernate interceptor for auditing purpose, but one that will work with thread local contextual sessions (instead of me calling openSession() every time and passing it an interceptor object).
Any guidelines/sample code on how to do this would be greatly appreciated. (My main problem is to figure out a way to give interceptor object to a contextual session when it's opened for the very first time).
why not using hibernate's audit sulotion? http://docs.jboss.org/envers/docs/index.html
if you use Hibernate only, you can set Interceptor for session with two approach.
//interceptor for global, set interceptor when create sessionFactory with Configure
sessionFactory =
new AnnotationConfiguration().configure()
.setInterceptor(new AuditTrailInterceptor())
.buildSessionFactory()
//interceptor for per Session
Session session = sessionFactory.openSession(new XxxInterceptor())
if you use Spring to create SessionFactory
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="entityInterceptor">
<bean class="your.XxxInterceptor"/>
</property>
<!-- other configuration -->
</bean>
I found one blog post which would help you. http://www.sleberknight.com/blog/sleberkn/entry/using_a_hibernate_interceptor_to
I have a properties set like so :
<context:property-placeholder
location="file:${catalina.home}/conf/my.properties"
ignore-unresolvable="true" />
they are then referenced in app context (specifically app.email) like so :
<bean id="alertMailMessage" class="org.springframework.mail.SimpleMailMessage">
<property name="to">
<value>${app.email}</value>
</property>
</bean>
However when I try to access that property within an actual pojo, not a spring bean - actually a pojo annotated as a hibernate entity (not the alertMailMessage bean) it is coming back as null ?
#Value("${app.email}")
private String defaultEmailAddress;
I want to use the value of property setting "app.email" elsewhere, other than alertMailMessage, whats the best way ? (alertMailMessage is working fine btw)
You can't set it in a hibernate entity, because hibernate entities are not managed by spring.
Use the #Value annotation in your spring service which creates the hibernate entity, and set it manually if needed. But it looks odd to store a default value in the database, so reconsider that.
As a sidenote: you can have hibernate entities managed by spring if using aspectJ and #Configurable, but that may complicate things unnecessarily.
Why it isn't enough to set the #Entity annotation?
Am I missing the point here e.g. performance?
The annotation is not enough because hibernate does not know where your annotated classes live without some sort of explicit declaration. It could, in theory, scan every single class in the classpath and look for the annotation but this would be very very expensive for larger projects.
You can use spring which has a helper that can allow you to specify the package(s) that your hibernate objects are in and it will just scan these packages for #Entity. If you have all your objects in a small number of fixed packages this works well.
E.g.
<bean id="referenceSessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="packagesToScan">
<array>
<value>com.xxx.hibernate.objects</value>
</array>
</property>
</bean>
The above is the Spring declaration. If you aren't familiar with the above syntax you can just construct it programmatically.
AnnotationSessionFactoryBean sfb = new AnnotationSessionFactoryBean();
sfb.setDataSource( ds );
sfb.setHibernateProperties( hibProps);
sfb.setPackagesToScan( ... );
sfb.initialise();
SessionFactory sf = sfb.getObject();
It supports a bunch of config options so you can use raw properties or pass in a pre-config'd datasource.
You don't if you set hibernate.archive.autodetection property to true. There is a performance issue here as Hibernate will search the jar files for the JPA annotation. Note that, it will also initializes those classes.
Yes :)
The hibernate.cfg.xml file is not used to specify your entities, it's used to configure things like hibernate's connection parameters and global settings. The hibernate.cfg.xml file also contains instructions on how to locate the entities. You can list the XML mapping files using <mapping resource=XYZ>, but if you're using JPA annotations like #Entity, then this is unnecessary, Hibernate will auto-detect them.
You can mix annotations and mapping XML if you choose, but that's by no means necessary in most situations.
By default all properly annotated
classes and all hbm.xml files found
inside the archive are added to the
persistence unit configuration. You
can add some external entity through
the class element though.
Hibernate EntityManager Reference Docs