1 quick question on Spring JPA repositories transactionality.
I have a service that is not marked as transactional and calls Spring JPA repository method
userRegistrationRepository.deleteByEmail(email);
And it is defined as
#Repository
public interface UserRegistrationRepository extends JpaRepository<UserRegistration, Long> {
UserRegistration findByEmail(String email);
void deleteByEmail(String email);
}
The problem is that it fails with "No EntityManager with actual transaction available for current thread - cannot reliably process 'remove' call; nested exception is javax.persistence.TransactionRequiredException" exception.
Ok, I can solve it by marking the service or deleteByEmail(..) method as transactional, but I just can't understand why it crashes now. Spring documentation explicitly states that "CRUD methods on repository instances are transactional by default." (http://docs.spring.io/spring-data/jpa/docs/current/reference/html/#transactions), but apparently this one is not... So Is this statement related to only members of CrudRepository?
ps: that's for Spring Data JPA 1.9.4
You are right. Only CRUD methods (CrudRepository methods) are by default marked as transactional.
If you are using custom query methods you should explicitly mark it with #Transactional annotation.
#Repository
public interface UserRegistrationRepository extends JpaRepository<UserRegistration, Long> {
UserRegistration findByEmail(String email);
#Transactional
void deleteByEmail(String email);
}
You should also be aware about consequences of marking repository interface methods instead of service methods. If you are using default transaction propagation configuration (Propagation.REQUIRED) then:
The transaction configuration at the repositories will be neglected
then as the outer transaction configuration determines the actual one
used.
http://docs.spring.io/spring-data/jpa/docs/current/reference/html/#transactions
If you want more information about how it is implemented, take a look at default CrudRepository / JpaRepository implementation - SimpleJpaRepository (which you are probably using):
https://github.com/spring-projects/spring-data-jpa/blob/master/src/main/java/org/springframework/data/jpa/repository/support/SimpleJpaRepository.java
The interesting lines are here:
#Transactional(readOnly = true)
public class SimpleJpaRepository<T, ID> implements JpaRepositoryImplementation<T, ID> {
and some of transactional methods here:
#Transactional
public void deleteById(ID id) {
#Transactional
public <S extends T> S save(S entity) {
Related
This question already has answers here:
How are Spring Data repositories actually implemented?
(1 answer)
How does Spring Data JPA work internally
(1 answer)
Closed 3 years ago.
I have a code like this:
Repository
#Repository
public interface EquipmentRepository extends JpaRepository<Equipment, Integer>{
Equipment findById(int id);
}
Service
#Service
public class EquipmentServiceImpl implements EquipmentService {
#Autowired
EquipmentRepository equipmentRepository;
#Override
public Equipment findById(int id) {
return equipmentRepository.findById(id);
}
}
I wonder that why i can call a method of 'interface EquipmentRepository'. EquipmentRepository is a interface, Right ?
Spring Repository is responsible for importing the DAO's into the DI container and also it makes the unchecked exceptions into Spring DataAccessException. The Spring Repository annotation is meta annotated with the #Component annotation so that the repository classes will be taken up for component scanning.
Teams implementing traditional Java EE patterns such as "Data Access
Object" may also apply this stereotype to DAO classes, though care
should be taken to understand the distinction between Data Access
Object and DDD-style repositories before doing so. This annotation is
a general-purpose stereotype and individual teams may narrow their
semantics and use as appropriate.
A class thus annotated is eligible for Spring DataAccessException
translation when used in conjunction with a
PersistenceExceptionTranslationPostProcessor. The annotated class is
also clarified as to its role in the overall application architecture
for the purpose of tooling, aspects, etc.
Source: JavaDoc
but in your case you are also extending the JpaRepository of Spring Data JPA. Spring Data automatically provides implementations of common CRUD operations. The JpaRepository extends the interface CrudRepository which has the methods declared for all basic crud operations.
public interface EquipmentRepository extends JpaRepository<Account, Long> { … }
Defining this interface serves two purposes:
First, by extending JpaRepository we get a bunch of generic CRUD
methods into our type that allows saving Equipments, deleting them and
so on.
Second, this will allow the Spring Data JPA repository infrastructure
to scan the classpath for this interface and create a Spring bean for
it.
The #EnableJpaRepositories scans all packages below com.acme.repositories for interfaces extending JpaRepository and creates a Spring bean for it that is backed by an implementation of SimpleJpaRepository (spring data provides default imlpementations of CRUD repository through this class).
So that is why even when you haven't defined the method , you are able to do crud operations through this setup.
Refer : https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.repositories
folks!
I have two maven modules in my application - domain and persistence.
Domain has a domain object, services and "data provider" interfaces to external endpoints, for example, persistence. Domain contains business logic and has no external dependencies - he know nothing about persistence.
Persistence depends on domain. It implements "data provider" interfaces from domain module. It may be relational db implementation, nosql implementation, file implementation etc.
For example, I have interface PersonRepository in domain, like this:
public interface PersonRepository {
List<Person> findAll();
List<Customer> findByLastName(String lastName);
}
I want to implement data provider interface with Spring Data JPA. I need to write something like that:
public interface PersonRepository extends CrudRepository<Person, Long> {
List<Person> findAll();
List<Person> findByLastName(String lastName);
}
But I don't want to inject spring dependencies to "core domain". I want to stay my domain very lightweight and independent.
Is there way to implement PersonRepository with Spring Data in Persistence module?
Instead of extending the ready-made interfaces by Spring Data you can just copy the methods in your own interface. Normally you would just put a #Repository annotation on it and Spring Data would do its job. But that would reintroduce the dependency.
So what you could do instead is in your Spring Configuration invoke the JpaRepositoryFactory.getRepository yourself. Something like this should work:
#Bean
public PersonRepository(RepositoryFactorySupport factory) {
return factory.getRepository(PersonRepository.class);
}
This will be either in your persistence module or in a third module which does the wiring of all your modules, so the dependencies shouldn't be an issue.
The Spring Data JPA interface can extend multiple interfaces. Something like the following should work.
Defined in your domain module:
public interface PersonRepository {
List<Person> findAll();
List<Customer> findByLastName(String lastName);
}
In your persistence module:
#Reposistory
public interface SpringDataJPAPersonRepository extends CrudRepository<Person, Long>, PersonRepository {
// Any Spring Data JPA specific overrides e.g. #Query
}
Environment :
Tomcat 6
Spring 4
Hibernate 4
Spring MVC
Code :
I have below service layer class :
public interface AbhisheskService {
public List<AbhishekDTO> findByMatchingCriteria(AbhishekDetailsSearchDTO searchDto);
}
#Service("abhishekService")
public class AbhishekServiceImpl implements AbhisheskService {
#Autowired
private AbhishekDao abhishekDao;
#Transactional
public List<AbhishekDTO> findByMatchingCriteria(AbhishekDetailsSearchDTO searchDto) {
return getAbs();
}
public List<AbhishekDTO> getAbs(){
Abhishekdetails absDt = this.abhishekDao.get(4L);
return null;
}
}
The AbhishekDao is a standard DAO layer interface which extends GenericDAO super interface.
public interface AbhishekDao extends GenericDAO<Abhishekdetails, Long>{
public List<Abhishekdetails> findByMatchingCriteria(AbhishekDetailsSearchDTO searchDto);
}
My question is :
findByMatchingCriteria method is marked with #Transactional.
This method calls another method getAbs which is NOT MARKED AS #Transactional and it is invoked within findByMatchingCriteria (self-invocation).
As per my understanding since :
1)findByMatchingCriteria is calling getAbs within itself (self-invocation) , getAbs() method SHOULD NOT run inside transaction. Since it is bypassing dynamically created proxy here
2)Moreever getAbs doesn't have #Transactional annotation on it.
3)But when getAbs calls this.abhishekDao.get(4L) everything works fine and a record with ID 4L is retrieved. The DAO bean is calling sessionFactory.getCurrentSession() inside it to get object from Db. But why is this working ?
Since there SHOULD NOT BE any active transaction.
4)Why is above code working ? A lot of posts on Spring Transaction management state that self invocation will not work. (Even spring docs).
Then why is above set up working ?
Am I amissing anything here ?
Or My understanding of spring transaction is incorrect?
Please repply as I am getting confused here
The way it works is:
- AbhishekServiceImpl bean is wrapped in a proxy.
findByMatchingCriteria is #Transactional, so before the method is invoked Spring gets new database connection from the connection pool and sets auto commit to false.
The transactions are bound to a thread, so the other methods on this thread will use this connection.
The methods findByMatchingCriteria and getAbs are executed
after findByMatchingCriteria Spring calls commit on the connection(or rollback if RuntimeException occurs).
So your code is in transaction that's around findByMatchingCriteria
A case where a transaction will not be created is if you have #Transactional on getAbs , but not on findByMatchingCriteria(reverse the calling) and you call findByMatchingCriteria outside of the service. But if you call only getAbs outside of the service it will be in transaction.
More clear example:
#Service
public class MyServiceImpl implements MyService{
#Autowired
private MyDao myDao;
#Transactional
public List<T> transactionalMethod() {
return this.myDao.get(4L);
}
public List<T> notTransactionalMethod(){
return transactionalMethod();
}
}
In some other class:
#Component
public class SomeClass {
#Autowired
private MyService myService;
public void someMethod(){
myService.transactionalMethod();//will be in transaction. Here actualy you go to the proxy first and then it calls the real method.
myService.notTransactionalMethod();//will not be in transaction and hibernate will throw an error.
//You go to the proxy, but doesent do anything special because the method is not transactional and it calls the real method,
//but here you dont't got trough the proxy so the #Transactional is ignored.
}
}
I have a Spring CrudRepository that is just an interface, and I have a persistence context class where I have defined my data source:
#Configuration
#EnableTransactionManagement
public class PersistenceContext {
#Bean(name="dataSource", destroyMethod = "close")
public DataSource dataSource() throws SQLException {
return ...
public interface DataRepository extends CrudRepository<Data, Long> {
Data findById(long id);
}
Then
#Autowired
protected DataRepository repository;
...
Data data = repository.findById(1234);
Everything works fine but the database model is such that I actually need to call a stored procedure on the same connection before calling findById from the using code. This procedure must take a parameter that a calling code will know but it will differ between calls so it is not possible just to override DataSource.getConnection and return the "prepared connection" there.
Is it any way to "prepare a connection" before making an access code to the Spring repository?
Using AOP would seem to be one approach: an example of using AOP to enrich Spring Data repositories can be found at the below:
https://github.com/spring-projects/spring-data-jpa-examples
If you can get a reference to the injected EntityManager within the advice then you should be able to get the underlying connection from that using one of the methods detailed here:
How can i get the session object if i have the entitymanager
To get a reference to the EntityManager you may have to create a custom repository from which all your repositories inherit:
http://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.custom-behaviour-for-all-repositories
I have classes’ hierarchy like this
public class AccessHistoryJpaDAO extends PaginatedJpaDAO<AccessHistory, Long>
implements AccessHistoryDAO
in AccessHistoryJpaDAO I implemented logIn method which is declared in AccessHistoryDAO interface.
public void logIn(AccessHistory entity) throws DAOException
{
super.save(entity);
}
Then I extends AuthenticationProcessingFilter of spring
public class CustomAuthenticatingFilter extends AuthenticationProcessingFilter
and overridden method
#Override
public Authentication attemptAuthentication(HttpServletRequest request)
throws AuthenticationException
in this method when I call
getAccessHistoryDAO().logIn(entity);
hibernate is not able to persist entity but
when I call direclty
getAccessHistoryDAO().save(entity)
Above method it is persisting entity, well I try to figure it out but no clue, any help will be greatly appreciated. Thank you.
It looks like a very well known problem with Proxy-AOPs.
I guess you have a #Transactional annotation at the save method. But this Annotation is only taken in account if the method is invoked from an OTHER spring bean. If it is invoked from the same spring bean (this.save()) then the AOP Proxy is not invoked and therefore the Transaction is not started.
You can handle the problem in at least three different ways:
put an additional #Transactional annotation at the logIn method, or
use explicit transaction management instead of declarative,
use real AspectJ instead of Spring Proxy-AOP (this is what I do)