Delete and add data to the mysql database with spring hibernate 4 in single transaction - spring

I want to update entire database in mysql database through my spring application (hibernate 4, spring 1.4.5).
Steps:
1. delete entire data from DB
2. update new record
3. rollback if 1 or 2 fails
How do I achieve with #Transactional?
I have used org.springframework.transaction.annotation.Transactional and propagation = MANDATORY.
But I can see the table get deleted while it is still in the same Transactional Method.
#Transactional(propagation = Propagation.MANDATORY)
private void testMtd(List<Data> data){
repository.deleteAll();
repository.save(data);
}
How can I overcome this problem?

Annotating the Application started class (main class) with #EnableTransactionManagement will work.

Related

Spring boot , Spring data JPA concurrent access

I am trying to create a Restful API with Spring boot and Spring data JPA to do the CRUD operations. The database will be Oracle relational database.Now for concurrent access , If we only use spring transactions using #Transactional, will that serve our purpose of concurrent CRUD operations.
I see there are JPA Optimistic and pessimistic locking strategy version column. My specific question is , for concurrent CRUD operations do we need both Spring transactions and JPA locking strategy? OR only configuring Spring transactions accordingly will be sufficient?
Try to start with the following simple approach that IMO will be suitable in many cases: Optimistic locking with Spring Retry.
1) Add version property annotated with #Version to your entities (you can do it in base abstract entity class, for example, to simplify the process):
#Entity
public class MyEntity {
#Id
#GeneratedValue
private Long id;
#Version
private Long version;
// other stuff
}
In this case when you, for example, will update your entity then Hibernate will use the current value of version property in condition clause of update query, and increment this value to store the entity with it. For example this code of some service:
#Transactional
public Optional<MyEntity> update(Long id, MyEntity source) {
return myEntityRepository
.findById(id)
.map(target -> mapper.updateEntity(source, target));
}
will generate the following SQL queries:
1. select * from my_entities where id = ?;
2. update my_entities set ..., version = <version value from query #1> + 1 where id = ? and version = <version value from query #1>;
So if another concurrent process manages to update this entity first, then your method fails with an exception (OptimisticLockException).
2) To manage to exceptions in that method, add #Retryable annotation to it (and #EnableRetry annotation on your config or application class):
#Retryable(maxAttempts = 2)
#Transactional
public Optional<MyEntity> update(Long id, MyEntity source) {
// ...
}
In this case, if an exception rises in that method it will be called again in a new transaction to repeat the operation.
Additional info:
Optimistic Locking in JPA
Guide to Spring Retry
My Spring Retry demo
Optimistic lock is default strategy of JPA. Optimistic locking is can be used for most of the applications. Optimistic lock is much more easier and efficient. Pessimistic lock need to be used in cases like, where you need to know Collision before committing your transaction.
So you do not need to configure a locking strategy.

In a Spring Boot #Transactional Class, how to perform commits to different repositories after changes to the Hibernate DAO object in between commits?

I need to do the following in my #Transactional Class
Do changes to data (empty logs field) inside a DAO object and save to PostGresql DB
Revert the changes and save to ElasticSearch (with the id generated in the same DAO object from first commit return result).
Here is how the code is
emptylogsField(testCaseResponses); //Data modifications
Iterable<TestCaseResponse> result =
PGRepository.saveAll(converter.convertToEntities(testCaseResponses));
PGRepository.flush();
putBackLogs(result); // Data modifications
result = ESRepository.saveAll(result);
The problem is the same data is getting saved in both repositories. The flush() is not working? Please help.

Spring Data Neo4J #Index(unique = true) does not working

I want to make userName property in User node as a unique.
I used below code but it doesn't create a unique constraint in the Neo4j database.
#Property(name = "name")
#Index(unique = true)
private String usreName;
FYI, I'm using the Neo4j Server version: 3.3.6 (community) With Spring Boot 2.
but if I create a constraint in the Neo4j Browser by myself, it works.
CREATE CONSTRAINT ON (user:User) ASSERT user.userName IS UNIQUE
Is there a way to force Spring Data Neo4J to create unique properties, without creating them by myself in Database?
You need to configure the auto index manager if you want the application code create the constraints.
You can find the best fitting option in the documentation:
https://docs.spring.io/spring-data/neo4j/docs/current/reference/html/#reference:indexing:creation
Just a note on this topic: Think about the auto index creation like Hibernate's DDL support. It is a helper at development time. You should not use assert and update in production environments but only validate.
Reason
In Spring Data Neo4j 4, index management concerns were removed from
the mapping framework entirely.
(from Index Management in Spring Data Neo4j)
Solution
#Autowired
private SessionFactory sessionFactory;
#PostConstruct
public void createIndexesAndConstraints() {
Session session = sessionFactory.openSession();
Result result = session.query("CREATE INDEX ON :User(userName)", Collections.EMPTY_MAP);
}
You can configure the mode our auto index manager works in through application.properties
spring.data.neo4j.auto-index=validate # or
# spring.data.neo4j.auto-index=update
# spring.data.neo4j.auto-index=assert
Default mode is none. Apart from that, what #meistermeier says applies.
Also, Neo4jOperations was deprecated in SDN 4 something and has been removed in SDN 5. Use Session instead for operations "near" the database.
Thank you #ThirstForKnowledg for your answer. But I have 3 other Questions:
1- I'm using Spring Boot 2, and I can not see Neo4jOperations in my classpath to import it.
2- Should I put this in my Entity node or in another bean?
3- What about after running my application two or more times? I think it would cause an exception for the second time or more.

JPA / JTA / #Transactional Spring annotation

I am reading the transaction management Using Spring framework. In first combination I used Spring + hiberante and used Hibernate's API's to control the transaction (Hibenate API's). Next, I wanted to test using #Transactional annotation, and it did work.
I am getting confused on:
Do JPA , JTA, Hibernate have their "own" way of transaction
management. As an example, consider if I use Spring + Hibernate, in
that case would u use "JPA" transactions?
Like we have JTA, is it true to say we can use Spring and JTA to
control transactions?
The #Transactional annotation, is that specific to Spring
Framework? From what I understood, this annotation is Spring
Framework specific. If this is correct, is #Transactional using
JPA/JTA to do the transaction control?
I do read online to clear my doubts, however something I don't get direct answer. Any inputs would be great help.
#Transactional in case of Spring->Hibernate using JPA i.e.
#Transactional Annotations should be placed around all operations that are inseparable.
So lets take example:
We have 2 model's i.e. Country and City.
Relational Mapping of Country and City model is like one Country can have multiple Cities so mapping is like,
#OneToMany(fetch = FetchType.LAZY, mappedBy="country")
private Set<City> cities;
Here Country mapped to multiple cities with fetching them Lazily.
So here comes role of #Transactinal when we retrieve Country object from database then we will get all the data of Country object but will not get Set of cities because we are fetching cities LAZILY.
//Without #Transactional
public Country getCountry(){
Country country = countryRepository.getCountry();
//After getting Country Object connection between countryRepository and database is Closed
}
When we want to access Set of Cities from country object then we will get null values in that Set because object of Set created only this Set is not initialize with there data to get values of Set we use #Transactional i.e.,
//with #Transactional
#Transactional
public Country getCountry(){
Country country = countryRepository.getCountry();
//below when we initialize cities using object country so that directly communicate with database and retrieve all cities from database this happens just because of #Transactinal
Object object = country.getCities().size();
}
So basically #Transactional is Service can make multiple call in single transaction without closing connection with end point.
Hope this will helpful to you.

Spring Transactional annotation, Hibernate and persist

I've a misunderstanding of Spring #Transactional annotation and persist. I am using Spring 3.1, with JPA and Hibernate. I thought that persist meant, add the entity to the persistence context (but don't execute any query until commit or flush), and that the #Transactional annotation meant, wrap the method with a transaction.
However, in this short example, when the execution pointer reaches persist, it fails with an exception, since name can't be null (db constraint).
import javax.persistence.EntityManager;
#PersistenceContext
private EntityManager entityManager;
#Transactional
public void test() {
Brand brand = new Brand();
entityManager.persist(brand);
brand.setName("test");
}
If I swap setName() and persist(), everything works. However, I don't understand why the other way around doesn't since I thought that any query would be built and executed at the end of the method.
Can someone please explain?
In JPA, once an object passed to persist() it becomes "managed", as part of becoming managed JPA implementation must generate an id for the persistent object.
If id generation is based on auto-increment (GenerationType.IDENTITY), then an insert statement needs to be issued to the db to get and assign the key. When the id generation is based on sequence / table then ids are managed and assigne by the JPA Implementation managed id pools, in which case a straight insert is not a requirement.
Having an object is passed to persist() and has become managed, any changes to it is persistent fields must be flushed to the database at the and of the transaction. In your case if the id generation is Identity then an insert must be followed an update. If the id generation is some other method then, a single insert statement is sufficient. If the transaction is rolled back, no SQL should be get sent to database at all.
This is the implementation in Batoo JPA.
Hope this makes sense.
Its committed at end of method thanks to transactional annotation. But the new record is created on persist, and any exceptions can be thrown.
Before the end of method it can still be rolled back; I normally annotate with rollback for exception.
The persist executes the "insert" query. The transacation annotation is just for starting a transaction and if a exception occurs roll back the transaction.

Resources