I would like to know if the following is considered safe.
Usual Spring service class that accesses a bunch of DAOS / hibernate entities:
#Transactional
public class MyService {
...
public SomeObject readStuffFromDB(String key) {
...
//return some records from the DB via hibernate entity etc
}
A class in the application that has the service wired in:
public class ServiceHolder {
private MyService myService;
private SomeOtherObject multiThreadedMethod() {
...
//calls myService.readStuffFromDB() and uses the results
//to return something useful
}
multiThreadedMethod will be called from multiple threadpool threads. I would like to know if the multiThreadedMethod is safe in its calls to myService.
It is NOT making any modifications to the DB - only reading.
What happens if two threads call myService.readStuffFromDB() at exactly the same time? Will a concurrent modification exception be thrown from somewhere?
I've been running it with no issues but I'm not 100% sure it will always work.
Yes you will call the same object in the same time as long as your service bean is defined as singleton (which is default and proper), but you should not rely on local variables in you services. So the methods should be written that way they can work independently (you don't need a mutual exclusion here). If you called db and tried do any operations nothing would happen because every thread would receive a new instance of entity manager. If you modified db in the same time and any type of db exception was thrown you would get a rollback exception which is perfectly fine.
entityManager.persist() will do more or less entityManager.getEntityManagerAssignedToCurrentThread().persist()
It is a proxy not real object. So you are safe :)
Related
I want to have a service which keeps a list inmemory so I don't need to access the database everytime. The service is accessed by a controller. Is this a valid approach or am I missing something? What about concurrent access here (from the controller)? Is this (stateful service) an anti-pattern?
#Service
public class ServiceCached {
private List<SomeObject> someObjects;
#PostConstruct
public void initOnce() {
someObjects = /** longer running loading methodd **/
}
public List<SomeObject> retrieveObjects() {
return someObjects;
}
}
Thanks!
I wouldn't call it an anti-pattern, but in my opinion loading the list from the database in a #PostConstruct method is not a good idea as you slow down the start up of your application, I'd rather use a lazy loading mechanism, but this would potentially introduce some concurrent access issues that would need to be handled.
In your example concurrent access from the controller should not be a problem as the list is loaded from a #PostConstruct method and the controller would depend on this service, therefore this service would need to be fully constructed before it is injected into the controller, therefore the list would already be loaded.
Preferably I'd suggest using Spring Caching: Caching Data with Spring, Documentation, Useful guide
Usage example:
#Cacheable("books")
public Book getByIsbn(String isbn) {
simulateSlowService();
return new Book(isbn, "Some book");
}
This way you do not need to take care of loading and evicting the objects. Once set up, the caching framework will take care of this for you.
I have my services like this annotated with #Transactional
#Transactional
#Service
public class Contact_Service {
....
In my Controller i don't have #Transactional and sometimes i use some persistence layer methods directely to search and persist my object and everything is okey :
#Controller
public class GestionAO {
....
#RequestMapping(...)
public String alerte() {
contact_respository.findOne(...) ;
...
contact_respository.save(...) ;
My question since my controller is not in a transaction will i got some problems ?
Can my object don't get saved in some cases ?
Will i got concurrence problem ?
Looks fine now when you have only one save call. If there are multiple DML or DDL operations executed from the Controller you will lose on not having transaction management. You will lose on the ACID behavior that transactions offer.
The purpose of having #Transactional annotation is to perform multiple database operations in a single transaction. If one operation fails, entire transaction should be roll-backed. Otherwise this can cause data integrity issues.
And the most important thing is to have #Transactional on service layer methods. Because that's one layer who knows unit of work and use cases. In some cases you will have to call multiple DAO layer methods, those all operations are called from service layer and mostly from single method. So it is always better to annotate your service layer methods as #Transactional.
To sum it up, You must have #Transactional annotations on service layer methods.
you should only annotate service with #Transactional. to make sure all of db operations under single transaction, it is recommended to add a new method in service which contains all you db operations, and just call this new method in controller.
I am testing service methods that are placed in controllers in spring applications. It seems to me that my problem is that one essential service method call is done in class which is anotated #Component and the method call is inside #PostConstruct anotated method.
#Component
public final class Helper
#PostConstruct
public void initialize() {
stuff = service.getNessesaryStuff();
}
The contents of the stuff are coming from a database and they vary in each test. That's why database is populated with needed data before each test. Without the data the other service methods are not working. I have checked that the right data goes to database exactly like intended, but it does not affect right away. I need to run same test couple of times before it gets the right data and passes.
Any fix?
When running the application, Helper class is created itself. When running tests, I need to make a bean of it to avoid NullPointerExceptions.
I use spring 3.2 and Hibernate 4 in my project. When i query table i get a "No Session found for current thread" message. I try to use #Transactional annotation(it get success) but i don't want to put #Transactional to every service implementation.
Is there an another way?
In other words "How can i do a simple "insert" operation without using #Transaction?"
Thx...
You should not have #Transactional on you DAO methods, in fact you should never be accessing your DAO methods directly, you should be using an #Service. A service will use zero or more DAO classes to perform operations, only after all operations are completed will the transaction be committed.
#Repository
public class CustomerDao() {
// dao methods here, they are not transactional but will be run within a sevice transaction
}
#Service
#Transactional
public class CustomerService() {
private final CustomerDao customerDao;
#Autowired
public CustomerService(CustomerDao customerDao) {
this.customerDao = customerDao;
}
//service methods here (they are all transactional because we have annotated the class)
}
#Transactional is used for making a java code call in transaction so that in case any exception occurred during the process then all database changes will be rolled back. In ideal scenario every service which you think should be independent should have #Transactional annotation. Hibernate also want each database calls in transaction thats why they have implemented in such a way that Transaction will be required for each database query to be successful. I am not sure why you wanted your service to be out of transaction still they would like to fire database calls.
I thought the Spring annotations were supposed to work out of the box in a Grails environment, but I cannot get it to work at all. I also tried the afterProperties method, which did not work either.
Can anyone spot a mistake? Is there some configuration I need to do?
package dashboard
import javax.annotation.PostConstruct
class EmailJobSchedulerService
{
def grailsApplication
#PostConstruct
def init() {
def cronExpression = grailsApplication.config.emailAt8AmTrigger
println(cronExpression)
EmailSubscribersJob.schedule(cronExpression, new HashMap())
}
}
Try changing it to
#PostConstruct
void init() {
(i.e. void instead of def). I'm not sure whether Spring specifically enforces this but the specification of #PostConstruct states that among other things "The return type of the method MUST be void".
Edit: uchamp's comment is correct, I just tried the same test and indeed the #PostConstruct annotated method is called only the first time the service bean is used and, not necessarily immediately at startup. You can add
static lazyInit = false
to the service class to force it to be initialized eagerly at startup. This doesn't appear to be documented in the user guide, I deduced it by reading the code.
Note that "used" in the previous paragraph doesn't necessarily mean you have to call a method on it. The service bean will be initialized the first time it is fetched from the application context, either directly or because it has been autowired into another bean that is being initialized. For example, injecting the service into BootStrap using
def emailJobSchedulerService
would be enough to fire the #PostConstruct method, you don't have to actually call any of the service's methods from the BootStrap.init closure. Similarly, if your service were injected into any controllers then the init would fire the first time one of those controllers handled a request (any request, it doesn't have to be an action that calls the service).
Just adding on the answer from #Ian - For some reason i had:
#PostConstruct
private void init() {
This also failed silently and gave strange behavior. Solution was to remove "private":
#PostConstruct
void init() {