Optimistic Locking in Spring Data JDBC - spring-data

I noticed that Spring Data JDBC doesn't seem to implemented Optimistic Locking (something like a JPA's #Version annotation).
I was thinking on creating a #Modifying query which considers the version field and returns boolean to check manually if the update was successful or not. But I'm afraid this approach is limited to simple entities, not aggregates implying multiple tables.
What's the best way to implement optimistic locking for aggregates?

It depends on your situation. If you just have 7 aggregates of which 5 are single entity aggregates go for the #Modifying solution for the single aggregates and write custom methods for the other 2.
If you have more aggregates consisting of more then one class consider properly implementing it and submitting a PR. The issue is already there: https://jira.spring.io/projects/DATAJDBC/issues/DATAJDBC-219
The main code changes will be in SqlGenerator which would need to add a where clause for aggregate roots if they have a version attribute.
If you are interested in doing a PR and need more assistance, please leave comment on the issue.

Related

Can couchbase be used as the underlying JobRepository for spring-batch?

We have a requirement where we have to read a batch of a entitytype from the database, submit info about each entity to a service which will callback later with some data to update in the caller entity, save all the caller entities with the updated data. We thought of using spring-batch however we use Couchbase as our database which is eventually consistent and has no support for transactions.
I was going through the spring-batch documentation and I came across the Spring Batch Meta-Data ERD diagram here :
https://docs.spring.io/spring-batch/4.1.x/reference/html/index-single.html#metaDataSchema
With the above information in mind, my question is:
Can Couchbase be used as the underlying job-repository for spring-batch? What are the things I should keep in mind if its possible to use it? Any links to example implementations would be welcome.
The JobRepository needs to be transactional in order for Spring Batch to work properly. Here is an excerpt from the Transaction Configuration for the JobRepository section of the reference documentation:
The behavior of the framework is not well defined if the repository methods are not transactional.
Since Couchbase has no support for transactions as you mentioned, it is not possible to use it as an underlying datasource for the JobRepository.

JPA Entity CRUD type Operations support in MyBatis

Due to some odd reason, I cannot go with JPA vendor like Hibernate, etc and I must use MyBatis.
Is there any implementation where we can enrich similar facility of CRUD operation in Mybatis?
(Like GenericDAO save, persist, merge, etc)
I have managed to come up with single interface implementation of CRUD type of operations (like Generic DAO) but still each table has to write it's own query in XML file (as table name, column names are different).
Will that make sense to come up with generic implementation?
Where I can give any table object for any CRUD operation through only 4 XML queries. (insert, update, read, delete) passing arguments of table name, column names, column values..etc.
Does it look like re-inventing the wheel in MyBatis or does MyBatis has some similar support?
you can try Mybatis Plus.This is for these cases.
MyBatis is not an ORM, instead it maps the result from SQL statements to objects.
You need to write SQL.
You will have a hard time if you try and apply the JPA model to working in MyBatis. You need to learn how MyBatis works instead.
You may be interested in the MyBatis Generator. Here is a screenshot of the introduction paragraph.
And here is the URL.
The generator looks at the Physical tables in an RDBMS and generates the CRUD mapping.That is half the job done. The other half is to utilize these mappings in your actual code.
Let this assumption also be cleared. The generator generates only the CRUD. For more complex operations like aggregations or joins et al, you may need to write the mappers on your own.

Combining Spring Data query builder with Spring Data JPA Specifications?

Spring Data allows you to declare methods like findByLastname() in your repository interface and it generates the queries from the method name automatically for you.
Is it possible to somehow have these automatically-generated queries also accept a Specification, so that additional restrictions can be made on the data before it's returned?
That way, I could for example call findByLastname("Ted", isGovernmentWorker()), which would find all users that have the last name Ted AND who satisfy the isGovernmentWorker() specification.
I need this because I'd like the automated query creation provided by Spring Data and because I still need to be able to apply arbitrary specifications at runtime.
There is no such feature. Specifications can only be applied on JpaSpecificationExecutor operations.
Update
The data access operations are generated by a proxy. Thus if we want to group the operations (as in findByName + Criteria) in a single SELECT call, the proxy must understand and support this kind of usage; which it does not.
The intended usage, when employing Specification API would look like this for your case:
findAll(Specifications.where(hasLastName("Ted")).and(isGovernmentWorker())
Spring data allows you to implement custom repository and use Specifications or QueryDSL.
Please see this article.
So at the end you will have one YourCustomerRepository and appropriate YourRepositoryImpl implementation, where you will put your findByLastname("Ted", isGovernmentWorker()) method.
And then YourRepository should extend YourCustomerRepository interface.

Correct approach to using JPA 2

I saw this link at Nabble where someone (James Sutherland) stated to someone that they were "executing a delete all JPQL query. This is basically similar to executing your own SQL, you are responsible for executing the query correctly to maintain your constraints.
This is not the normal way to delete objects in JPA. In JPA you normally read the object, then call remove() on it.".
I was wondering if this is true or not; based on how difficult it's been to remove more than simple tables, I'd start thinking this is correct.
My thoughts thus far are to do it like this:
Perform select statements, however particular they may be (e.g.
select all students where student courses > 4 and marks >= 60 and
student registration between 2011 and 2012).
Display/edit/delete
objects (so EntityManager merge/persist/remove)
Rinse, lather, and so on
Does this sound reasonable as an approach to how one is suppose to use the JPA or am I off base?
The cascading of remove was discussed here: Google App Engine - DELETE JPQL Query and Cascading. Also for instance doing batch updates won't update version column when optimistic locking is used. Thus batch updates/deletes are a bit crippled in JPA.
But I wouldn't say This is not the normal way to delete objects in JPA. When I need to delete 2, 20 or 200 objects based on some condition selecting and fetching them first just to call remove() on each is a bad idea most of the time.
After all batch updates/deletes are there in the specification for a reason.

Create new or update existing entity at one go with JPA

A have a JPA entity that has timestamp field and is distinguished by a complex identifier field. What I need is to update timestamp in an entity that has already been stored, otherwise create and store new entity with the current timestamp.
As it turns out the task is not as simple as it seems from the first sight. The problem is that in concurrent environment I get nasty "Unique index or primary key violation" exception. Here's my code:
// Load existing entity, if any.
Entity e = entityManager.find(Entity.class, id);
if (e == null) {
// Could not find entity with the specified id in the database, so create new one.
e = entityManager.merge(new Entity(id));
}
// Set current time...
e.setTimestamp(new Date());
// ...and finally save entity.
entityManager.flush();
Please note that in this example entity identifier is not generated on insert, it is known in advance.
When two or more of threads run this block of code in parallel, they may simultaneously get null from entityManager.find(Entity.class, id) method call, so they will attempt to save two or more entities at the same time, with the same identifier resulting in error.
I think that there are few solutions to the problem.
Sure I could synchronize this code block with a global lock to prevent concurrent access to the database, but would it be the most efficient way?
Some databases support very handy MERGE statement that updates existing or creates new row if none exists. But I doubt that OpenJPA (JPA implementation of my choice) supports it.
Event if JPA does not support SQL MERGE, I can always fall back to plain old JDBC and do whatever I want with the database. But I don't want to leave comfortable API and mess with hairy JDBC+SQL combination.
There is a magic trick to fix it using standard JPA API only, but I don't know it yet.
Please help.
You are referring to the transaction isolation of JPA transactions. I.e. what is the behaviour of transactions when they access other transactions' resources.
According to this article:
READ_COMMITTED is the expected default Transaction Isolation level for using [..] EJB3 JPA
This means that - yes, you will have problems with the above code.
But JPA doesn't support custom isolation levels.
This thread discusses the topic more extensively. Depending on whether you use Spring or EJB, I think you can make use of the proper transaction strategy.