I have a Singleton-EJB, that reads all objects from a database with a specific state. Then I do something with these objects and set the state to someting else:
#Singleton
public class MyEJB {
#PersistenceContext(unitName = "MyPu")
private EntityManager em;
#Lock(LockType.WRITE)
public void doSomeStuffAndClose() {
List<MyObj> objects = getAllOpenObjects();
for (MyObj obj : objects) {
// do some stuff here...
obj.setClosed(true);
}
}
private List<MyObj> getAllOpenObjects() {
TypedQuery<MyObj> q = em.createQuery("select o from MyObj o "
+ "where o.closed = false", MyObj.class);
return q.getResultList();
}
}
Now, if i would like to ensure that my method cannot be called concurently, I add the annotation #Lock(LockType.WRITE). But the transaction that sets the states in the database is committed AFTER the lock was released and it is possible that the next caller grabs the same objects again.
How could I prevent this?
If you are using Wildfly: This is a bug. https://issues.jboss.org/browse/WFLY-4844 describes your problem which will be fixed in Wildfly 10. There the problem is described as a timer problem which might be the same as yours.
My workaround is to seperate the code that does the work into another bean which is called by the outer (timer) bean. The outer bean method is annotated to not start a transaction (#TransactionAttribute(TransactionAttributeType.NEVER)), so the transaction is started and safely finished in the second new bean.
You could use SELECT FOR UPDATE to serialize the access of the rows.
With JPA 2 use the LockModeType:
http://docs.oracle.com/javaee/6/api/javax/persistence/LockModeType.html
q.setLockMode(LockModeType.PESSIMISTIC_WRITE)
There's no way to do this in JPA (so, in a portable way). Your options might be:
Some JPA implementations allow setting isolation level on a per-query basis (e.g. OpenJPA), some don't (Hibernate). But even in OpenJPA this hint needs to be implemented in a particular database driver, otherwise it has no effect).
Running a native query – consult your database documentation for details.
As a side comment I should say that JPA (and Java EE in general) is not designed with bulk database operations in mind – it's rather for multiple concurrent queries for data items that in most cases don't overlap.
You can invoke from your doSomeStuffAndClose method Stateful Session Bean with implemented SessionSynchronization interface. Than from afterCompletion method in SFSB you can inform singleton bean that data has been commited and can handle another request.
I know that this way we have two really tight coupled beans, but this should solve your problem.
You're using container-managed concurrency (the default). In JavaEE 7 (not sure about older ones, but likely yes) the transaction is guaranteed to commit before the method exits, hence before lock is released. From the JavaEE 7 tutorials:
"Typically, the container begins a transaction immediately before an enterprise bean method starts and commits the transaction just before the method exits. Each method can be associated with a single transaction. Nested or multiple transactions are not allowed within a method."
https://docs.oracle.com/javaee/7/tutorial/doc/transactions003.htm#BNCIJ
If you're experiencing another behavior, check for any cache that might be active (#Cacheable). You may watch another interesting question here: https://stackoverflow.com/questions/26790667/timeout-and-container-managed-concurrency-in-singleton
By the way, LockType(WRITE) is also default, you don't need to explicit it. Hence, getAllObjects is also LockType(WRITE).
Related
I understand that if we use annotation #Transactional. "save()" method is not necessary. Is it exact?
And for my example:
#Transactional
void methodA() {
...
ObjectEntity objectEntity = objectRepository.find();
methodB(objectEntity);
}
void methodB(ObjectEntity obj) {
...
obj.setName("toto");
objectRepository.save(obj); <-- is it necessary?
}
Thanks for your help
It works like following:
save() attaches the entity to the session and at the end of the transaction as long as there were no exceptions it will all be persisted to the database.
Now if you get the object from the DB (e.g. ObjectEntity objectEntity = objectRepository.find();) then that object is already attached and you don't need to call the save() method.
If the object, however, is detached (e.g. ObjectEntity objectEntity = new ObjectEntity();) then you must use the save() method in order to attach it to the session so that changes made to it are persisted to the DB.
[It is a little too late, but I hope it would be helpful to future readers]:
Within a transaction context, an update to a managed instance is reflected in the persistence storage at the commit/flush time, i.e., in your case at the end of methodB(). However, calling save() comes with a cost in scenarios like yours, as stated in Spring Boot Persistence Best Practices:
The presence or absence of save() doesn’t affect the number or type of
queries, but it still has a performance penalty, because the save()
method fires a MergeEvent behind the scenes, which will execute a
bunch of Hibernate-specific internal operations that are useless in
this case. So, in scenarios such as these, avoid the explicit call of
the save() method.
I'm trying to somehow 'debug' my application that use the spring boot cache annotations and for that I would like to know how to find the class that actually implements the interface Cacheable, CacheConfig, etc.
My idea is to confirm that the cache is being populated, emptied etc.
Thanks a lot for your help,
#Cacheable is used to demarcate methods that are cacheable - that is, methods for whom the result is stored into the cache so on subsequent invocations (with the same arguments), the value in the cache is returned without having to actually execute the method. In its simplest form, the annotation declaration requires the name of the cache associated with the annotated method:
#Cacheable("books")
public Book findBook(ISBN isbn) {...}
In the snippet above, the method findBook is associated with the cache named books. Each time the method is called, the cache is checked to see whether the invocation has been already executed and does not have to be repeated. While in most cases, only one cache is declared, the annotation allows multiple names to be specified so that more than one cache are being used. In this case, each of the caches will be checked before executing the method - if at least one cache is hit, then the associated value will be returned.
For more information read the following;
https://docs.spring.io/spring/docs/current/spring-framework-reference/integration.html#cache
Spring used ConcurrentHashMap as the default cache implementation.
public class ConcurrentMapCache extends AbstractValueAdaptingCache
If, on the other hand, you need different cache, then Spring also comes with a built in ehCache wrapper. The good news is that swapping between Spring's caching implementations is easy. In theory it’s all a matter of configuration.
I found several resources to help me with this issue, but I can't seem to mix all the ingredients in order to suit my needs.
I want to "lock" a Cat (or even several) from being petted by other users, if a petting of it (or them) is already in progress. I also want to provide a feedback to the caller, telling him who called the API before him.
#Local
#Singleton // or #Stateful?
public class CatPetterBean_Local implements CatBean_Facade
{
/**
* Key - The ID of the Cat
*/
final private ConcurrentHashMap<Integer, User> pettingState = new ConcurrentHashMap<>();
#TransactionAttribute(TransactionAttributeType.REQUIRED)
#Override
public GzipROWithMsg<Object> pet(final ImmutableSet<Integer> catIds)
{
checkIfTheyAreBeingPetted_AndThrowRuntimeExec(catIds);
<...>
// After petting, they will be saved by the caller bean (e.g. CatPetterBeanImpl)
}
<...>
}
Petting takes a while
Cats retain a state in the DB: ALREADY_PETTED and NOT_PETTED. Once it is already pat, it cannot be petted again. I even thought of loading the Cat from the DB and checking its state on-the-fly, but I think it's more network traffic that way.
How can I take advantage of notions like synchronized keywords, #Lock annotations
No, I am not using Spring
No, This isn't a webapp
Yes, I do lack EE knowledge. I'm asking this question in a process of fast learning.
EJB Singletons have under the hood a locking mechanism, by default, all bean methods are serialized via write locks.
The default concurrency model on EJB Singletons is: #ConcurrencyManagement(ConcurrencyManagementType.CONTAINER), this is the default, no need to annotate the singleton with this. When Container Concurrency Management is in play as I said before every method is write locked. If you want finer control over singleton methods you can annotate them with #Lock(LockType.READ) which means that the method can be accessed concurrently while no one holds a write lock on the bean, or #Lock(LockType.WRITE) giving exclusive access to the current thread.
Alternatively, you can use Bean concurrency management. In this case, you should annotate your singleton class with: #ConcurrencyManagement(ConcurrencyManagementType.BEAN).
In this case, you use synchronized and other Java concurrency goodies. For most of my needs Container Managed concurrency was more than enough.
Another remark to the above code fragment is that #Local doesn't seem appropriate, my guess is that CatBean_Facade should be annotated with #Local.
Correct me if anything is wrong.
Now when we use Spring DAO for ORM templates, when we use #Transactional attribute,
we do not have control over the transaction and/or session when the method is called externally, not within the method.
Lazy loading saves resources - less queries to the db, less memory to keep all the collections fetched in the app memory.
So, if lazy=false, then everything is fetched, all associated collections, that is not effectively, if there are 10,000 records in a linked set.
Now, I have a method in a DAO class that is supposed to return me a User object.
It has collections that represent linked tables of the database.
I need to get a object by id and then query its collections.
Hibernate "failed to lazily initialize a collection" exception occurs when I try to access the linked collection that this DAO method returns.
Explain please, what is a workaround here?
Update: All right, let me ask you this. DAO is an abstract layer, so a method "getUserById(Integer id)" is supposed to return an Object.
What if in some cases I need these linked collections of the User object and in other situation I need those collections.
Are there only two ways:
1) lazy loading = false
2) create different methods: getUserByIdWithTheseCollections(), getUserByIdWithOtherCollections() and inside those methods use your approach?
I mean are there only 2 ways and nothing better?
Update 2: Explain please, what would give me the explicit use of SESSIONFACTORY?
How does it look in practice? We create an instance of DAO object,
then inject it with session factory and this would mean that two consequent
method calls to DAO will run within the same transaction?
It seems to me that anyway, DAO is detached from the classes that make use of it!
The logic and transactions are encapsulated within DAO, right?
You can get the linked collection in transaction to load it while you're still within the transaction:
User user = sessionFactory.getCurrentSession().get(User.class, userId);
user.getLinkedCollection().size();
return user;
As BalusC has pointed out, you can use Hibernate.initialize() instead of size(). That's a lot cleaner.
Then when you return such an entity, the lazy field is already initialized.
Replying to your PS - is using transactions on service level (rather than DAO) level feasible? It seems to be, as doing each DAO call in separate transaction seems to be a waste (and may be incorrect).
I find that it's best to put #Transactional at the service layer, rather than the DAO layer. Otherwise, all your DAO calls are in separate hibernate sessions - all that object equality stuff won't work.
In my opinion best way to solve this problem will be to design application in a session-per-request model. Then, if you even have an object taken from DAO, until your OSIV pattern works you can use the object safely anywhere in application, even in views without bothering this stuff. This is probably better solution that those proposed because:
Hibernate.initialize() or size is a very artificial workaround - what if you want to have User with different collection initialized, would you write another method for getting user?
Service layer transactional model is OK, but the same problem comes when you want to get object extracted from the service layer to use it in controller or view
You could do something like following:
public User getByUserId(Long id, String ... fetch) {
Criteria criteria = createCriteria();
if (fetch != null) {
for (String fieldName : fetch) {
criteria.setFetchMode(fieldName, FetchMode.JOIN); // fetch these fields eagerly
}
}
return criteria.add(Restrictions.eq("id", id)).list();
}
Not sure if 'scope' is the correct term here.
I am using Spring for JPA transaction management (with a Hibernate underneath). My method to preform database transaction is private, but since you can only set #Transactional on a class or on a public method
Since this mechanism is based on proxies, only 'external' method calls coming in through the proxy will be intercepted. This means that 'self-invocation', i.e. a method within the target object calling some other method of the target object, won't lead to an actual transaction at runtime even if the invoked method is marked with #Transactional!
I have set the public entry point of the class as #Transactional.
#Transactional
public void run(parameters) {
//First non-database method, takes a decent amount of time
Data data = getData();
//Call to database
storeData(data);
}
private storeData(data) {
em.persist(data);
}
Is this bad practice? Is Spring keep an open transaction for longer then needed here? I was thinking of move the storeData() method to a DAO class and making it public, but as academic point, I wanted to know if refactoring to public would have any performance benefit.
If there's heavy contention on the DB, keeping transactions as small as possible is definitely crucial -- much more important than public vs private distinctions, which, per se, don't affect performance and scalability. So, be practical...!
The transaction scope is has no effect until your code does something which interacts with the transaction context, in this case the storeData() method. The fact that getData() is non-transactional should not affect the performance on concurrency of your code, since any database locking will only happen when storeData() is reached.
As everyone pointed we should keep transaction as small as possible, so that connection remains available for other request.
Can this be refactored as this
public void run(parameters) {
Data data = getData();
storeData(data);
}
#Transactional
public storeDate(data){em.persist(data)}