jdbcTemplate batchUpdate issue - spring

In my spring batch application i am trying to update the records in Writer using JdbcTemplate batchUpdate. But niether changes are reflecting in DB nor the job gets completed. when i check in JOB_EXECUTION in spring META-TABLES EXIT_CODE shows as UNKNOWN.
List<Object[]> objects = new ArrayList<Object[]>();
for(Item item : items){
Object[] objectsArray = new Object[]{item.getName(),item.getValidToDate(),item.getAccountNo(),item.getCode()};
objects.add(objectsArray);
}
iagJdbcTemplate.batchUpdate(updateSql,objects);
And my update query is like this
UPDATE ACCOUNT_INFO SET ADDRESS= ?,DATE=? WHERE ACCOUNT=? AND CODE=?;
ACCOUNT table has composite primary key which is a combination of ACCOUNT & CODE.
NOTE : When i run the same with INSERT query it just works fine.
Please do let me know where i am going wrong.

Issue is resolved. There is nothing wrong in the jdbcTemplate or in update query. It is some other environment related issue. Same configuration will work fine. No need to change the configurations. Thanks all.

Related

Spring data update just one entity field

i’m new to spring when i try to update just one field of an entity I noticed in logs that hibernate perform two queries, before update it does a SELECT of all fields. Is that ok? Why does Hibernate perform that SELECT? How can i update a field with just one UPDATE query? Additionally when I tried to update a single title in an entity that has another nested entity i end up with a bunch of SELECT. I think it’s not good for performance or I’m wrong?
Something s = somethingRepository.findById(id);
s.setField1(someData);
somethingRepository.save(s);
On the internet I found a solution to make custom query with #Modifying and #Query(“UPDATE …”) but in this way I need to make custom query for every single field. Is there a better solution?
As per the source code you have pasted in the question
Something s = somethingRepository.findById(id);
s.setField1(someData);
somethingRepository.save(s);
if the entity Something which you are asking does not exist in the hibernate first level cache, it will make one SELECT call.
and as you are updating field 1 value then it will make another update call.
It does not matter if you are using save or not because Hibernate dirty checks will ensure that all changes are updated.
otherwise you can use custom method with #Modifying with JPQL and named params. It is more readable than ?1,
#Modifying
#Query("UPDATE Something s SET s.field = :fieldValue WHERE s.id = :id")
void updateField(String fieldValue, UUID id);
Regarding that you are seeing multiple calls "when I tried to update a single title in an entity that has another nested entity". It depends on how you have created the relationship among entities. If you can share the entities and their relationship then only it can be answered accurately.
Because internally the repository.save() method does an upsert. If you go to the inner classes and check you will see that first, it will check whether the entity is present in the database then based on that it will perform add or update. If you don't want the SELECT query to run then you can use the native query offered by the JPA repository. You can do something like this:
#Modifying
#Transactional
#Query("UPDATE <tableName> SET <columnName> = ?1 WHERE <condition>" ,nativeQuery=true)
void updateSomething(String value);

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.

Executing an SQL query in multiple databases through Spring - Hibernate

I have a below problem and I am looking for solution in Spring - MVC and Hibernate only.
Problem Statement: There is UI which is having a text area and Submit button. In text area user can write a SQL query and after submitting, this SQL query has to be executed at multiple databases.
Note: Assume that multiple databases are already configured.
Please tell me the best approach for implementing it.
You might consider 2 options:
AbstractRoutingDataSource
With this solution you are able to switch to the right database before executing queries. So you could write something like
// GOLD database
CustomerContextHolder.setCustomerType(CustomerType.GOLD);
List<Item> goldItems = catalog.getItems();
assertEquals(3, goldItems.size());
System.out.println("gold items: " + goldItems);
// SILVER database
CustomerContextHolder.setCustomerType(CustomerType.SILVER);
List<Item> silverItems = catalog.getItems();
assertEquals(2, silverItems.size());
System.out.println("silver items: " + silverItems);
// DEFAULT database
CustomerContextHolder.clearCustomerType();
List<Item> bronzeItems = catalog.getItems();
assertEquals(1, bronzeItems.size());
System.out.println("bronze items: " + bronzeItems);
Here are some docs:
https://spring.io/blog/2007/01/23/dynamic-datasource-routing/
https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/jdbc/datasource/lookup/AbstractRoutingDataSource.html
http://fedulov.website/2015/10/14/dynamic-datasource-routing-with-spring/
Using multiple transaction manager (one by database)
This involve that you know in advance what Transaction Manager you will need for a specific Service.
https://docs.spring.io/spring/docs/3.0.x/spring-framework-reference/html/transaction.html#tx-multiple-tx-mgrs-with-attransactional
I will assume that you have multiple datasources wired in you application context (?). If so and assuming that they have different qualifiers, you can inject them into another component, typically a service which is invoked from your controller or directly into your controller.
#Autowired
List<DataSource> datasources;
Should do the trick, alternatively through constructor injection. With the latter, you can create a JdbcTemplate per DataSource. Then you loop through the list and execute the same sql query on all datasources.

HibernateEnvers doesn't store current lastmodifieddate in audit table while performing delete operation

I need some help in resolving this issue. The issue is:
I am using HibernateEnvers for Auditing in spring data jpa. For insert and update operations the code is working fine. But in case of delete operation, current lastmodifieddate is not logging. The lastmodified date which is getting logged is of previous operation and not the current system date. I have set this hibernate property
org.hibernate.envers.store_data_at_delete = true
I have tried using #PostRemove and #PreRemove annotated methods to modify lastModifiedDate in entity but it doesn't work.
Please suggest some pointers on this.

Double instances in database after using EntityManager.merge() in Transient Method

I am new with Spring, my application, developed with Spring Roo has a Cron that every day download some files and update a database.
The update is done, after downloading and parsing the files, using merge(),
an Entity class Dataset has a list called resources, after the download I do:
dataset.setResources(resources);
dataset.merge();
and dataset.merge() does the following:
#Transactional
public Dataset Dataset.merge() {
if (this.entityManager == null) this.entityManager = entityManager();
Dataset merged = this.entityManager.merge(this);
this.entityManager.flush();
return merged;
}
I expect that doing dataset.setResources(resources); I would overwrite the filed resources, and so even the database entry would be overwritten.
But I get double entries in the database: every resource appear twice, with different IDs (incremental).
How can I succed in let my application doing updates and not insert? A naive solution would be delete manually the old resource and then call merge(); is this the way or is there some more smart solution?
This situation occurs when you use Hibernate as persistence engine and your entities have version field.
Normally the ID field is what we need for merging a detached object with its persistent state in the database, but Hibernate takes the version field in account and if you don't set it (it is null) Hibernate discards the value of ID field and creates a new object with new ID.
To know if you are affected by this strange feature of Hibernate, set a value in the version field, if an Exception is thrown you got it. In that case the best way to solve it is the data to parse contain the right value of version. Another ways are to disable version checking (see Hibernate ref guide to know about it) or load persistent state before merging.

Resources