How do we set database session variables in Hibernate? - java

When using Hibernate and JPA, I have an existing DAO Abstract Class that sets up an entity manager this way:
#PersistenceContext(unitName = "<name>")
private EntityManager entityManager;
And in certain methods, it's used in the following manner:
public ObjectType findByPrimaryKey(int id) {
return entityManager.find(ObjectType, id);
}
I wanted to set a database configuration parameter in the same transaction as the "find" query. However, I can't seem to find the internal transaction that entityManager uses. I wrote an Aspect that checks for Transactional annotation and sets the variable in there, and added #Transactional on top of findByPrimaryKey method, but that still didn't get set in the session.
Is there something incorrect here or another way to do it? Ideally, want to set a special variable before every query.

Final solution was to combine Spring's "#Transactional" annotation, which automatically opens a transaction, before calling my Data access layer, with an Aspect that pointcuts to "#Transactional" annotation and runs queries within a transaction. Just executing any query within an "#Transactional" method will also work, before calling the Hibernate data access layer.
Without the "#Transactional" annotation, I couldn't control Hibernate's transaction management.

Related

Postgres Hibernate set session variables for row level security

I am having trouble finding information about this issue I am running into. I am interested in implementing row level security on my Postgres db and I am looking for a way to be able to set postgres session variables automatically through some form of an interceptor. Now, I know that with hibernate you are able to do row-level-security using #Filter and #FilterDef, however I would like to additionally set policies on my DB.
A very simple way of doing this would be to execute the SQL statement SET variable=value prior to every query, though I have not been able to find any information on this.
This is being used on a spring-boot application and every request is expected to will have access to a request-specific value of the variable.
Since your application uses spring, you could try accomplishing this in one of a few ways:
Spring AOP
In this approach, you write an advice that you ask spring to apply to specific methods. If your methods use the #Transactional annotation, you could have the advice be applied to those immediately after the transaction has started.
Extended TransactionManager Implementation
Lets assume your transaction is using JpaTransactionManager.
public class SecurityPolicyInjectingJpaTransactionManager extends JpaTransactionManager {
#Autowired
private EntityManager entityManager;
// constructors
#Override
protected void prepareSynchronization(DefaultTransactionStatus status, TransactionDefinition definition) {
super.prepareSynchronization(status, definition);
if (status.isNewTransaction()) {
// Use entityManager to execute your database policy param/values
// I would suggest you also register an after-completion callback synchronization
// This after-completion would clear all the policy param/values
// regardless of whether the transaction succeeded or failed
// since this happens just before it gets returned to the connection pool
}
}
}
Now simply configure your JPA environment to use your custom JpaTransactionManager class.
There are likely others, but these are the two that come to mind that I've explored.

Begin and Rollback transactions with JdbcTemplate

i'm working with spring jdbcTemplate in some desktop aplications.
i'm trying to rollback some database operations, but i don't know how can i manage the transaction with this object(JdbcTemplate). I'm doing multiple inserts and updates through a methods sequence. When any operation fails i need rollback all previous operations.
any idea?
Updated... i tried to use #Transactional, but the rolling back doesn't happend.
Do i need some previous configuration on my JdbcTemplate?
My Example:
#Transactional(rollingbackFor = Exception.class,propagation = Propagation.REQUIRES_NEW)
public void Testing(){
jdbcTemplate.exec("Insert into table Acess_Level(IdLevel,Description) values(1,'Admin')");
jdbcTemplate.exec("Insert into table Acess_Level(IdLevel,Description) values(STRING,'Admin')");
}
The IdLevel is a NUMERIC parameter, so... in our second command will occur an exception. When i see the table in database, i can see the first insert... but, i think this operation should be roll back.
what is wrong?
JdbcTemplate doesn't handle transaction by itself. You should use a TransactionTemplate, or #Transactional annotations : with this, you can then group operations within a transaction, and rollback all operations in case of errors.
#Transactional
public void someMethod() {
jdbcTemplate.update(..)
}
In Spring private methods don't get proxied, so the annotation will not work. See this question: Does Spring #Transactional attribute work on a private method?.
Create a service and put #Transactional on the public methods that you want to be transactional. It would be more normal-looking Spring code to have simple DAO objects that each do one job and have several of them injected than it would to have a complicated DAO object that performed multiple SQL calls within its own transaction.

Lazy loading working in non-transactional class/method in Hibernate

I am working in Spring-Hibernate application. Flow is as usual: Controller --> Service --> DAO.
I have annotated Service layer class with #Transactional, thereby marking every method transactional in that class.In service class, I made a DAO call to get some domain object and then converting it into DTO/VO object which will be passed to controller.For converting domain object to DTO, I have written another custom static class(class having only static methods) like ObjectMapper which will do this conversion.
Now, domain object has some child object(One to Many) which is lazily loaded. So, when in ObjectMapper, i access that child getter method, an extra database call is issued, which is working fine.
What I don't understand is that since ObjectMapper is not transactional, I was expecting some exception to be thrown like Session is closed while making database call to fetch child object from database.I am using getCurrentSession of Session Factory in DAO.
Can someone please explain me this behavior?
I suppose you either call your ObjectMapper from the transactional Service method (you should) or if not, maybe you are enabled "hibernate.enable_lazy_load_no_trans" which keeps the hibernate session open
As long as the call to the static class/method, which transforms your objects, is made in the transactional method of the DAO, the session is still open and will be used for the database calls.

EJB: Using EntityManager in PostConstruct method

After constructing the bean, I want to retrieve data from the database, using the EntityManager. It is not possible in the constructor, because the EntityManager is injected after the constructor is called. So I tried to do it in a method annotated with #PostConstruct. According to the API, a PostConstruct Methods gets called after all injection are done. Executing the query works, but it always returns an empty list. If I use the same query in an other method, it returns the correct result. Does anybody know, why it does not work in the PostConstruct method?
#Stateful(mappedName = "price")
#Singleton
#Startup
public class PriceManagementBean implements PriceManagement {
#PersistenceContext
private EntityManager em;
private List<PriceStep> priceSteps = Collections.synchronizedList(new ArrayList<PriceStep>());
public PriceManagementBean(){
}
#PostConstruct
public void init(){
javax.persistence.Query query = em.createQuery("SELECT ps FROM PriceStep ps");
List<PriceStep> res = query.getResultList();
.....
}
}
Does anybody know, why it does not work in the PostConstruct method?
Reason 1
You cannot create a bean that is at the same time #Stateful and #Singleton(Well you can but it will make no sense since Singletons are also Stateful), that is one of the reasons you are having trouble. There is no exceptions, but there is a conflict in there, you need to fix that first.
Just remember:
A Singleton bean is a bean that mantains its state. There is only one instance of a Singleton in an application and it is shared among all the users of the app. Also since it is a shared(maybe better say concurrent) bean, there is need to implement some kind of locking mechanism using the #Lock annotation.
A Stateful bean is a bean that mantains each state after a transaction. When working with
Stateful beans each user gets a copy of the bean which will last as long as the session - lasts or until a method annotated with #Remove is called
Reason 2
Even if it works, you will be unable to access the results, because you are storing them in an object called res which is only accessible from inside the method init(). I suppose you would like to assign that returned value to the variable priceSteps.
Anyway there are many things wrong in your code, for not saying everything. I don't know what are your system requirements, but here i would give you a simple solution that will allow you to access the database:
I suppose you are trying to in some way return the data in the life cycle of the bean because you want to avoid sending queries again and again if the bean is #Stateful.
The thing is, you don't have to do that, you can still make your bean #Stateless and avoid stressing your database with many queries.
What you need to do is create a #NamedQuery.
So annotate your entity PriceStep with #NamedQuery and there enter the query string you wrote. In this link you will find information about how to use #NamedQueries:
http://docs.oracle.com/cd/B31017_01/web.1013/b28221/ent30qry001.htm
The next thing i would suggest you is to annotate your class PriceManagementBean as *#Stateless*. Don't worry if in each request a new entityManager is created, that does not stress the database at all, because it interacts with the domain model.
You don't need #PostConstruct, you just call your #NamedQuery whenever you need it and that's it. The app server will cache it and give it back to each user that requires it without interacting with the database all time.
Here a codesnipet:
#Entity
#NamedQuery(
name="allPriceSteps",
queryString="SELECT ps FROM PriceStep ps"
)
public class PriceStep implements Serializable {
...
}
Now the bean:
#Stateless
public class PriceManagementBean implements PriceManagement {
#PersistenceContext
private EntityManager em;
public List<PriceStep> getAllPriceSteps() {
Query query = em.createNamedQuery("allPriceSteps");
return query.getResultList();
}
}
I hope this is useful. If you give more information about your system requirements we could give you advice on a best practice.
Based on your requirement please try the following
Remove #Stateful [CAN'T use both at a time]
#Startup will initialize singleton bean during APPLICATION INIT [Please note the application was NOT fully initialized]. This might caused some issue in loading EntityManager and i assume the EntityManager bridge was not completely initialized. Try to call the init after complete application startup [i.e.,] Remove #Startup

manual commits with #Transactional attribute

I use spring+hibernate template to process entities. There is rather big amount of entities to be loaded all at once, so I retrieve an iterator from hibernate template.
Every entity should be processed as a single unit of work. I tried to put entity processing in a separate transaction (propagation = REQUIRED_NEW). However I ended with exception stating that proxy is bounded to two sessions. This is due to suspended transaction used for iterator lazy loading. I am using the same bean for lazy loading and for processing entities. (May be it should be refactored into two separate daos: one for lazy loading and one for processing?)
Then I tried to use single transaction that is committed after each entity is processed. Much better here, there are no exceptions during entity processing, but after processing is finished and method returns, exception is thrown from spring transaction managing code.
#Transactional
public void processManyManyEntities() {
org.hibernate.Sesstion hibernateSession = myDao.getHibernateTemplate().getSessionFactory().getCurrentSession();
Iterator<Entity> entities = myDao.findEntitesForProcessing();
while (entities.hasNext()) {
Entity entity = entities.next();
hibernateSession.beginTransaction();
anotherBean.processSingleEntity(entity);
hibernateSession.getTransaction().commit();
}
}
processSingleEntity is a method in another bean annotated with #Transactional, so there is one transaction for all entities. I checked what transaction causes an exception: it is the very first transaction returned from hibernateSession.beginTransaction(), so it just not updated in transaction manager.
There are several questions:
is it possible to avoid session bind exception without refactoring the dao? that is not relevant question as problem is with Session and hibernate not with dao
is it possible to update transaction in the transaction manager? solved
is it possible to use the same transaction (for anotherBean.processSingleEntity(entity);) without #Transactional annotation on processManyManyEntities?
I would prefer to remove the #Transactional annotation on "processManyManyEntities()", and, to eagerly load all data from "findEntitesForProcessing".
If your want each entity of data to be transactional in "processSingleEntity", the #Transactinoal on "processSingleEntity" is fine. You don't have to annotate the #Transactional on "processManyManyEntities()". But in case of lazy loading, eager loading is a necessary mean to prevent the source data from loading in another session, say, in "processSingleEntity".
Since the transaction for each entity of data, the transactional boundary in loading of source data is not the case of your transaction. Don't let the "lazy loading" to complicate your intent of transaction for modification of data.
That is possible to update transaction in transaction manager. All you need to do is get SessionHolder instance from TransactionSynchronizationManager.getResource(sessionFactory) and set transaction in the session holder to the current. That makes possible to commit transaction whenever it is necessary and allows transaction to be committed by spring transaction manager after method return.

Categories