Hibernate session thread safety - java

I know that sessions are not thread safe. My first question: is it safe to pass an entity to another thread, do some work to it, then pass it back to the original thread and update.
public class Example1 {
MyDao dao;
...
public void doWork() {
MyEntity entity = dao.getEntity();
Runnable job = new Job(entity);
Thread t = new Thread(job);
t.run();
t.join();
dao.merge(entity);
}
}
My second question: is it safe to new up an entity in one thread and save it in another?
public class Example2 {
MyDao dao;
...
public void doWork() {
MyEntity entity = new Entity();
new Thread(new Job(dao, entity)).run();
}
}
public class Job implements Runnable {
private MyDao dao;
private MyEntity entity;
...
#Override
public void run() {
dao.save(entity);
}
}
Edit I forgot to mention that the entities are specifically configured for eager loading

No. The entity is attached to the session and contains proxies linked to the session (in order to lazy-load themselves). Doing that would thus use the session from multiple threads. Since the session is not thread-safe, this is not a good idea.
While the entity is transient (i.e. you've just created it with new), it's not attached to the session, Hibernate doesn't know about it, and the entity is a plain old Java object. So no problem doing that.I don't have all the details of your DAO though. If the method of your DAO is supposed to be invoked as part of an existing transaction, that won't work, since the transaction is tied to the current thread.

Related

EJB Singleton - Lock READ method calling a Lock WRITE method of the same instance

Given a Singleton like this one:
#Singleton
public class waitingTimeManager {
private Map<Integer, Object> waitingTimes;
#PostConstruct
public void setup() {
waitingTimes = new HashMap<>();
}
#Lock(LockType.READ)
public boolean shouldWeWait(Integer id) {
if (waitingTimes.containsKey(id)) {
boolean wait = someLogic(waitingTimes.get(id));
if (!wait) {
// we don't need to wait for it anymore
stopWaiting(id);
}
return wait;
}
return false;
}
#Lock(LockType.WRITE)
public void stopWaiting(Integer id){
waitingTimes.remove(id);
}
}
The initial method shouldWeWait can be accessed at the same time by several threads. The other stopWaiting will need to get a write lock.
Will the call to stopWaiting inside shouldWeWait try to get a WRITE Lock? or simply execute it as it already got the READ Lock initially?
No, it won't try to get write lock.
Container job is done within interceptors, wrapping EJB method calls. For example, when stateless BeanA calls your singleton - it does so through proxy, which makes possible the guarantees given by container (retrieving lock, etc.).
But in this case, it's just a normal method call (stopWaiting), not wrapped by proxy, so no place for magic.

Does a transaction with propogation reqiures new can update a object which locked by another transaction?

#Transactional("transaction1")
public void A(){
Actor actor = selectForUpdate(id);
testService.B(actor);
}
#Transactional("transaction1",propagation = Propagation.REQUIRES_NEW)
public void B(Actor actor){
update(actor);
}
Method A lock actor and call method B, method B begin transaction with propogation requires new.I'd like to know whether or not I can update actor in method B.
No it will not allow you to update with Propagation.REQUIRES_NEW.
However, if you want to achieve this functionality, you can do it by:
#Transactional("transaction1",propagation = Propagation.REQUIRED)
public void B(Actor actor){
update(actor);
}
Read the spring transactional document:
http://docs.spring.io/spring-framework/docs/4.2.x/spring-framework-reference/html/transaction.html

How do I manage hibernate transactions in a timertask?

I am currently trying to make a hibernate query inside of a TimerTask (Runnable). This task makes no saves or updates to the database. It just retrieves a list of jobs. Anytime I run this task, I get HibernateException: Unable to locate current JTA transaction.
I believe this has to do with the fact that it's being started from a runnable because I use this same query outside of this TimerTask.
I can't share the code I am working with because it is for work and proprietary. My research on this issue has only really led me to solutions with Spring, but I am not able to use Spring for this work.
I will attempt to make some pseudo code.
public class JobManager extends TimerTask {
#Override
public void run() {
...
List<String> jobs = Handler.getJobs();
...
}
}
public class Handler {
public static List<String> getJobs() {
return DAO.getJobs();
}
}
public class DAO {
public List<Object> getJobs() {
try {
session = HibernateManager.getSessionFactory().getCurrentSession();
Query myQuery = session.createQuery("query string");
List = myQuery.list();
} catch(HibernateException he) {
log.error(he);
}
return list;
}
}
The exception occurs when the runnable calls getJobs(). This method work everywhere else outside of the TimerTask.
I understand that this is limited information to work with. I can try to accommodate for any other information if it is needed.
I believe every transaction has some time out, so you can not put the regular timer task code inside the running transaction. As it is just reading the data you wont need to start the transaction, just session is enough
I have encountered the same problem and solved by creating the new session
session = sessionFactory.openSession();
EDIT
session.getCurrentSession() takes the current session from the current thread, so it wont work inside timer task. Use openSession()

JPA - How to call method for web service after commit

Sorry for something that is probably very simple, but I'm new to JPA and I'm not sure where to insert a function call for a method that needs to be called after a new record is committed to a database. I have the following:
#POST
#Override
#Consumes({"application/xml", "application/json"})
#Path("...")
#RolesAllowed("...")
public void create(LearningActivity entity){
super.create(entity);
}
I need to call a custom method myMethod() after the above process is completed. I thought I could add it immediately after super.create(entity) but apparently the commit process isn't completed until the whole create() method executes. I've also tried adding #PostPersist to the underlying entity but that's still before the record is committed.
Any help would be appreciated.
I'm not sure where to insert a function call for a method that needs
to be called after a new record is committed to a database
It sound like you need to use Event Listener, there is an event called PostPersist that is executed every time a entity has been commited to the database, you can configure that using the above code.
#Entity
public class X{
#PostPersist
public void myMethod(){
//Do anything before the commit of the transaction that save a new entity of type X
}
#PostUpdate
public void myMethod2(){
//This code will run each time you update and save an entity of type X
}
}
PostPersist is called after the commit has been completed, PrePersist executes when you call persist method.
Based on this article, #PostPersist is called before commit.
The alternative that I found is to create a static helper method that will call a Runnable after current transaction session is committed.
public static void afterTransactionCommitted(final Runnable function) {
if (TransactionSynchronizationManager.isSynchronizationActive()) {
TransactionSynchronizationManager.registerSynchronization(
new TransactionSynchronizationAdapter() {
#Override
public void afterCommit() {
function.run();
}
}
);
} else {
function.run();
}
}
You will use it like
afterTransactionCommitted(() -> myMethod());

Could I have thread safety problems using this aproach?

I'm working with EJB/JPA and I've created a static method called createDataset that will lookup for a Dataset object. Each time that I have to insert, update, remove, etc an entity, I retrieve a DatasetObject calling DatasetFactory.createDataset() and I call the appropriate method (insert, update, etc).
The codes:
public class DatasetFactory {
public static Dataset createDataset() {
try {
return (Dataset) new InitialContext().lookup("java:global/.../Dataset");
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
}
public interface Dataset<T> {
void insert(T entity);
//...
}
#Stateless
#EJB(name = "java:global/.../Dataset", beanInterface = Dataset.class)
public class DatasetBean<T> implements Dataset<T> {
#PersistenceContext(type = PersistenceContextType.TRANSACTION)
private EntityManager entityManager;
#Override
public void insert(T entity) {
entityManager.persist(entity);
}
//...
}
Could I have thread safety problems using this aproach? If so, what modifications should I have to do? Should I put the synchronized modifier in the DatasetFactory.createDataset()?
Thanks a lot!
You don't ever have to synchonize any method of an EJB, because the EJB specification specifies that an EJB instance may not be called by two concurrent threads. The EJB container handles the synchonization and thread safety for you. That's one of the points in using EJBs.
From a thread-safety point of view, your code looks good.
But it looks like you are implementing a DAO (Data Access Object) just you are calling your DAO a Dataset instead and it is not a good idea to implement DAOs using EJBs as the EJB container loads and verifies all your EJBs at startup and this can slow things down. And usually EJBs keep only a certain number of EJBs in memory (EJB pool) but if you don't implement your DAOs as EJBs you can create as many of them as you want and Java's GC cleans them up for you.
if your entitymanager is thread-save then there is no risk with using your insert method

Categories