TransactionalCacheManager and how to get TransactionalCache and clear - mybatis

It is possible to take the specific TransactionalCache per transaction and invoke clear? I'm working with spring context but seems that the transactional cache manager is out of it.

It is not possible now (the current version is 3.4.6).
TransactionalCache is a private field of the TransactionCacheManager which is in turn a private field of the CachingExecutor.
The cache is only cleared during queries and updates when mapper configuration (flushCache attribute and query type) instructs mybatis to do so.

Related

Why Spring Data doesn't support returning entity for modifying queries?

When implementing a system which creates tasks that need to be resolved by some workers, my idea would be to create a table which would have some task definition along with a status, e.g. for document review we'd have something like reviewId, documentId, reviewerId, reviewTime.
When documents are uploaded to the system we'd just store the documentId along with a generated reviewId and leave the reviewerId and reviewTime empty. When next reviewer comes along and starts the review we'd just set his id and current time to mark the job as "in progress" (I deliberately skip the case where the reviewer takes a long time, or dies during the review).
When implementing such a use case in e.g. PostgreSQL we could use the UPDATE review SET reviewerId = :reviewerId, reviewTime: reviewTime WHERE reviewId = (SELECT reviewId from review WHERE reviewId is null AND reviewTime is null FOR UPDATE SKIP LOCKED LIMIT 1) RETURNING reviewId, documentId, reviewerId, reviewTime (so basically update the first non-taken row, using SKIP LOCKED to skip any already in-processing rows).
But when moving from native solution to JDBC and beyond, I'm having troubles implementing this:
Spring Data JPA and Spring Data JDBC don't allow the #Modifying query to return anything else than void/boolean/int and force us to perform 2 queries in a single transaction - one for the first pending row, and second one with the update
one alternative would be to use a stored procedure but I really hate the idea of storing such logic so away from the code
other alternative would be to use a persistent queue and skip the database all along but this introduced additional infrastructure components that need to be maintained and learned. Any suggestions are welcome though.
Am I missing something? Is it possible to have it all or do we have to settle for multiple queries or stored procedures?
Why Spring Data doesn't support returning entity for modifying queries?
Because it seems like a rather special thing to do and Spring Data JDBC tries to focus on the essential stuff.
Is it possible to have it all or do we have to settle for multiple queries or stored procedures?
It is certainly possible to do this.
You can implement a custom method using an injected JdbcTemplate.

How do I disable GridFS MD5 calculation in Spring Boot?

Now that the md5 attribute of GridFS files collection is obsolete, drivers are not required to compute it, so I'd like to disable it to spare a few milliseconds maybe...
The MongoDB Java driver does provide an option disableMD5 in GridFSBucketImpl, but since I'm using Spring Boot's GridFsTemplate (spring-data-mongodb 2.1.2.RELEASE) I don't have direct access to it. GridFsTemplate has a method getGridFs() that returns a GridFSBucket configured for the current database and bucket name, but unfortunately this method is private so I can't override it.
So what are my options? Do I have to override all of GridFsTemplate? Did I miss a simple setting somewhere? Should I submit a feature request to Spring?
Update
Obviously GridFsTemplate is not meant to be extended (though all it would take is getGridFs and a couple fields to be protected) so I ended up creating my own CustomGridFsTemplate, which is an almost exact copy of GridFsTemplate except that I call GridFSBucket.withDisableMD5(true) in getGridFs.
I'm not very happy with that, but it works and I don't see a better option for now.
Update 2
I have submitted a Spring feature request, please vote for it! https://jira.spring.io/browse/DATAMONGO-2165
There's currently no better way. Looks like you filed a ticket to extend GridFsTemplate to allow the customizations.

hazelcast spring-data write-through

I am using Spring-Boot, Spring-Data/JPA with Hazelcast client/server topology. In parts of my test application, I am calculating time when performing CRUD operations on the client side (the server is the one interacting with a relational db). I configured the map(Store) to be write-behind by setting write-delay-seconds to 10.
Spring-Data's save() returns the persisted entity. In the client app, therefore, the application flow will be blocked until the (server) returns the persisted entity.
Would like to know is there is an alternative in which case the client does NOT have to wait for the entity to persist. Was under the impression that once new data is stored in the Map, persisting to the backed happens asynchronously -> the client app would NOT have to wait.
Map config in hazelast.xml:
<map name="com.foo.MyMap">
<map-store enabled="true" initial-mode="EAGER">
<class-name>com.foo.MyMapStore</class-name>
<write-delay-seconds>10</write-delay-seconds>
</map-store>
</map>
#NeilStevenson I don't find your response particularly helpful. I asked on an earlier post about where and how to generate the Map keys. You pointed me to the documentation which fails to shed any light on this topic. Same goes for the hazelcast (and other) examples.
The point of having the cache in the 1st place, is to avoid hitting the database. When we add data (via save()), we need to also generate an unique key for the Map. This key also becomes the Entity.Id in the database table. Since, again, its the hazelcast client that generates these Ids, there is no need to wait for the record to be persisted in the backend.
The only reason to wait for save() to return the persisted object would be to catch any exceptions NOT because of the ID.
That unfortunately is how it is meant to work, see https://docs.spring.io/spring-data/commons/docs/current/api/org/springframework/data/repository/CrudRepository.html#save-S-.
Potentially the external store mutates the saved entry in some way.
Although you know it won't do this, there isn't a variant on the save defined.
So the answer seems to be this is not currently available in the general purpose Spring repository definition. Why not raise a feature request for the Spring Data team ?

Hibernate Search: Get all fields for faceting

I want to place facet requests to (some) indexed fields. In order to place a facet request, I need to know the name of the corresponding field.
Is there a way to programmatically get a list of field names annotated with #Field?
The answer to your question will depend on the version of Search you are using. If you are using a pre Search 5 release where it was possible to facet on any #Field (with the documented restrictions), then you can use the public metadata API to get all configured fields.
The entry point into the public metadata API is via SearchFactory.getIndexedTypeDescriptor(Class<?> entityType) which returns an IndexedTypeDescriptor for the specified entity type. You can then iterate the configured properties and for each properties get the list of configured fields.
As of Search 5, however, facet fields needs to be marked at configuration time using #Facet(s). Only properties with this annotation can be faceted upon. Obviously the public metadata API should expose this as well. Unfortunately, this is not yet implemented - HSEARCH-1853.
There is a workaround if you are happy to use some internal APIs which might change in the future. You would only need this until HSEARCH-1853 is implemented at which stage you could switch to this public (and supported) API.
Search also maintains something which is called an internal metadata API which it uses for all its inner workings. It is basically just a richer model of the public API which is more restrictive on what's exposed. Bottom lines, you want to get hold of the org.hibernate.search.engine.metadata.impl.FacetMetadata. To do so you need to get hold of the DocumentBuilderIndexedEntity which gives you access to the internal org.hibernate.search.engine.metadata.impl.TypeMetadata. Via this type metadata you can get access to PropertyMetadata, then DocumentFieldMetadata and finally FacetMetadata.
To get hold of the DocumentBuilderIndexedEntity, you could do something like this:
ExtendedSearchIntegrator integrator = ContextHelper.getSearchintegratorBySFI( sessionFactory );
IndexManager[] indexManagers = integrator.getIndexBinding( clazz ).getIndexManagers();
DirectoryBasedIndexManager indexManager = (DirectoryBasedIndexManager) indexManagers[0];
EntityIndexBinding indexBinding = indexManager.getIndexBinding(clazz);
DocumentBuilderIndexedEntity documentBuilder = indexBinding.getDocumentBuilder();
Note, the internal API might change at any stage. No guarantees regarding backwards compatibility and evolution of the API are given.

Camel-JPA: mark as entity as consumed (without updating table record)

I am stuck (again ;-) with some JPA related problem and hope that anyone here can help (Camel in Action couldn't...):
I consume from a JPA endpoint using a namedQuery.
I cannot delete consumed entries, thus I am using the "consumeDelete=false" option.
But how can I prevent reading the same entry multiple times?
I am aware of the "#consumed" annotation, but since I am not allowed to modify/update the original database entries, I haven't figured out how I can mark a entry as "consumed"...
Any ideas?
thanks,
M
If you cannot change the data in the database anyhow to reflect that you have consumed the record already, then you would need to "store" this information elsewhere.
You can use the idempotent consumer EIP pattern
http://camel.apache.org/idempotent-consumer.html
You would then need to use a memory/file/another database/table to store id's of already consumed messages, and use that with the idempotent consumer pattern.
You can use #Consumed in your entity class with any method name and change the value of field to your desire value. for example
#Consumed
public void updateConsumedStatus() {
this.status = false;
}
Please check here too
http://camel.apache.org/jpa.html