Related
For some reason with this setup, when saving the transaction with a nested ticket. It will create both and then connect the two. However when I use the transaction repository to find the transaction it will have an attached ticket however when I use the ticket repository and find the ticket, it doesn't have the attached transaction. I generated this relationship with jhipster jdl, not sure what is going wrong here.
Transaction.java
...
#JsonIgnoreProperties(value = { "person", "event", "transaction", "nameTags" }, allowSetters = true)
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(unique = true)
private Ticket tickets;
public Ticket getTickets() {
return this.tickets;
}
public Transaction tickets(Ticket ticket) {
this.setTickets(ticket);
return this;
}
public void setTickets(Ticket ticket) {
this.tickets = ticket;
}
...
Ticket.java
...
#JsonIgnoreProperties(value = { "tickets", "membershipLevel", "person", "event" }, allowSetters = true)
#OneToOne(mappedBy = "tickets")
private Transaction transaction;
public Transaction getTransaction() {
return this.transaction;
}
public Ticket transaction(Transaction transaction) {
this.setTransaction(transaction);
return this;
}
public void setTransaction(Transaction transaction) {
if (this.transaction != null) {
this.transaction.setTickets(null);
}
if (transaction != null) {
transaction.setTickets(this);
}
this.transaction = transaction;
}
...
Edit:
Here is the generated SQL output, it is showing here just a normal select wihtout joins from both but transaction has the ticket_id in the transaction table while ticket is doing the same but has no reference and would need to do a join but is not.
Hibernate: insert into ticket (cost_per_ticket, count, event_id, person_id, picked_up, id) values (?, ?, ?, ?, ?, ?)
Hibernate: insert into transaction (cost_sub_items_purchased, date, donation, event_id, event_donation, generic_sub_items_purchased, membership_level_id, notes, number_of_memberships, person_id, tickets_id, total_amount, id) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
Hibernate: select transactio0_.id as id1_23_, transactio0_.cost_sub_items_purchased as cost_sub2_23_, transactio0_.date as date3_23_, transactio0_.donation as donation4_23_, transactio0_.event_id as event_i10_23_, transactio0_.event_donation as event_do5_23_, transactio0_.generic_sub_items_purchased as generic_6_23_, transactio0_.membership_level_id as members11_23_, transactio0_.notes as notes7_23_, transactio0_.number_of_memberships as number_o8_23_, transactio0_.person_id as person_12_23_, transactio0_.tickets_id as tickets13_23_, transactio0_.total_amount as total_am9_23_ from transaction transactio0_
Hibernate: select ticket0_.id as id1_22_, ticket0_.cost_per_ticket as cost_per2_22_, ticket0_.count as count3_22_, ticket0_.event_id as event_id5_22_, ticket0_.person_id as person_i6_22_, ticket0_.picked_up as picked_u4_22_ from ticket ticket0_
Spring Boot 2.4.0, DB is MySql 8.
Data is fetched every 15 seconds from remote with REST and storing it to MySql DB with saveAll().
Which call the save() method for all the given entities.
All data has set ID.
And I am expecting that if there is no such id at DB - it will be inserted.
If such ID is already presented at DB - it will be updated.
Here is snipped from the console:
Hibernate:
insert
into
iot_entity
(controller_ref, description, device_id, device_ref, entity_type_ref, hw_address, hw_serial, image_ref, inventory_nr, ip6address1, ip6address2, ip_address1, ip_address2, latlng, location, mac_address, name, params, status, tenant, type, id)
values
(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
...
2020-12-05 23:18:28.269 ERROR 15752 --- [ restartedMain] o.h.e.jdbc.batch.internal.BatchingBatch : HHH000315: Exception executing batch [java.sql.BatchUpdateException: Duplicate entry '1' for key 'iot_entity.PRIMARY'], SQL: insert into iot_entity (controller_ref, description, device_id, device_ref, entity_type_ref, hw_address, hw_serial, image_ref, inventory_nr, ip6address1, ip6address2, ip_address1, ip_address2, latlng, location, mac_address, name, params, status, tenant, type, id) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
2020-12-05 23:18:28.269 WARN 15752 --- [ restartedMain] o.h.engine.jdbc.spi.SqlExceptionHelper : SQL Error: 1062, SQLState: 23000
2020-12-05 23:18:28.269 ERROR 15752 --- [ restartedMain] o.h.engine.jdbc.spi.SqlExceptionHelper : Duplicate entry '1' for key 'iot_entity.PRIMARY'
2020-12-05 23:18:28.269 DEBUG 15752 --- [ restartedMain] o.s.orm.jpa.JpaTransactionManager : Initiating transaction rollback after commit exception
org.springframework.dao.DataIntegrityViolationException: could not execute batch; SQL [insert into iot_entity (controller_ref, description, device_id, device_ref, entity_type_ref, hw_address, hw_serial, image_ref, inventory_nr, ip6address1, ip6address2, ip_address1, ip_address2, latlng, location, mac_address, name, params, status, tenant, type, id) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)]; constraint [iot_entity.PRIMARY]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute batch
Here is how to fetch and to save look like:
#Override
#SneakyThrows
#Scheduled(fixedDelay = 15_000)
#Transactional(propagation = Propagation.REQUIRES_NEW)
public void fetchAndStoreData() {
IotEntity[] entities = restTemplate.getForObject(properties.getIotEntitiesUrl(), IotEntity[].class);
log.debug("ENTITIES:\n{}", mapper.writerWithDefaultPrettyPrinter().writeValueAsString(entities));
if (entities != null && entities.length > 0) {
entityRepository.saveAll(List.of(entities));
} else {
log.warn("NO entities data FETCHED !!!");
}
}
This method runs every 15 seconds.
Entity:
#Data
#Entity
#NoArgsConstructor
#EqualsAndHashCode(of = {"id"})
#ToString(of = {"id", "deviceId", "entityTypeRef", "ipAddress1"})
public class IotEntity implements Serializable {
private static final long serialVersionUID = 1L;
#Id
private Integer id;
// other fields
and Repository:
public interface EntityRepository extends JpaRepository<IotEntity, Integer> {
}
Here is snipped for iot entity at JSON format:
2020-12-05 23:18:44.261 DEBUG 15752 --- [pool-3-thread-1] EntityService : ENTITIES:
[ {
"id" : 1,
"controllerRef" : null,
"name" : "Local Controller Unterföhring",
"description" : "",
"deviceId" : "",
...
So ID is definitely set.
Also, batching is enabled for a project. It shouldn't have any impact on saving.
I could not understand why it tries to insert a new entity instead of update the existing one?
Why it couldn't distinguish the difference between the old and new entities?
UPDATE:
Implemented Persistable for Entity:
#Data
#Entity
#NoArgsConstructor
#EqualsAndHashCode(of = {"id"})
#ToString(of = {"id", "deviceId", "entityTypeRef", "ipAddress1"})
public class IotEntity implements Serializable, Persistable<Integer> {
private static final long serialVersionUID = 1L;
#Id
private Integer id;
#Override
public boolean isNew() {
return false;
}
#Override
public Integer getId() {
return this.id;
}
However, it fails with the same exception - Duplicate entry '1' for key 'iot_entity.PRIMARY'
If I will add #GeneratedValue like the following:
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
It wouldn't fail. However, it will update the ID value by itself.
For example, it fetched with id = 15:
[ {
"id" : 15,
"carParkRef" : 15,
"name" : "UF Haus 1/2",
And should be saved like following:
In fact it has id = 2 instead:
And it is incorrect.
Tried to add to storing service:
private final EntityManager entityManager;
...
List.of(carParks).forEach(entityManager::merge);
Fails with the same exception (with or without implementing Persistable). It tries to insert the value - insert into ... Duplicate entry '15' for key '... .PRIMARY'
Snippet from application.yml:
spring:
# ===============================
# = DATA SOURCE
# ===============================
datasource:
url: jdbc:mysql://localhost:3306/demo_db
username: root
password: root
initialization-mode: always
# ===============================
# = JPA / HIBERNATE
# ===============================
jpa:
show-sql: true
generate-ddl: true
hibernate:
ddl-auto: update
properties:
hibernate:
format_sql: true
generate_statistics: true
Here you could see pom file content.
How to fix this issue?
The problem is likely that, since the #Id is not marked with #GeneratedValue, Spring Data assumes all detached (transient) entities passed to save()/saveAll() should have EntityManager.persist() invoked on them.
Try making IotEntity implement Persistable and returning false from isNew(). This will tell Spring Data to always use EntityManager.merge() instead, which should have the desired effect (i.e. inserting nonexistent entities and updating existing ones).
Looks like I found the root of this behaviour.
Main App launcher look like:
#AllArgsConstructor
#SpringBootApplication
public class Application implements CommandLineRunner {
private final DataService dataService;
private final QrReaderServer qrReaderServer;
private final MonitoringService monitoringService;
#Override
public void run(String... args) {
dataService.fetchAndStoreData();
monitoringService.launchMonitoring();
qrReaderServer.launchServer();
}
All 3 steps have strict execution sequence. And the first one has to repeat for updating data locally if it is needed. Two other just servers which work with stored data only.
Where the first method look like:
#Scheduled(fixedDelay = 15_000)
public void fetchAndStoreData() {
log.debug("START_DATA_FETCH");
carParkService.fetchAndStoreData();
entityService.fetchAndStoreData();
assignmentService.fetchAndStoreData();
permissionService.fetchAndStoreData();
capacityService.fetchAndStoreData();
log.debug("END_DATA_FETCH");
}
Also, this execution is scheduled as well.
When the app starts it tried to execute this fetching twice:
2020-12-14 14:00:46.208 DEBUG 16656 --- [pool-3-thread-1] c.s.s.s.data.impl.DataServiceImpl : START_DATA_FETCH
2020-12-14 14:00:46.208 DEBUG 16656 --- [ restartedMain] c.s.s.s.data.impl.DataServiceImpl : START_DATA_FETCH
2 threads run at the same catch and store in parallel - trying to insert data. (tables are recreated at every start).
All later fetches are fine, they are executed only by #Sceduled thread.
If comment #Sceduled - it will work fine without any Exceptions.
SOLUTION:
Added additional boolean property to service class:
#Getter
private static final AtomicBoolean ifDataNotFetched = new AtomicBoolean(true);
#Override
#Scheduled(fixedDelay = 15_000)
#Order(value = Ordered.HIGHEST_PRECEDENCE)
public void fetchAndStoreData() {
ifDataNotFetched.set(true);
log.debug("START_DATA_FETCH");
// fetch and store data with `saveAll()`
log.debug("END_DATA_FETCH");
ifDataNotFetched.set(false);
}
And control the value after the application is started:
#Value("${sharepark.remote-data-fetch-timeout}")
private int dataFetchTimeout;
private static int fetchCounter;
#Override
public void run(String... args) {
waitRemoteDataStoring();
monitoringService.launchMonitoring();
qrReaderServer.launchServer();
}
private void waitRemoteDataStoring() {
do {
try {
if (fetchCounter == dataFetchTimeout) {
log.warn("Data fetch timeout reached: {}", dataFetchTimeout);
}
Thread.sleep(1_000);
++fetchCounter;
log.debug("{} Wait for data fetch one more second...", fetchCounter);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
} while (DataServiceImpl.getIfDataNotFetched().get() && fetchCounter <= dataFetchTimeout);
}
Spring Data JPA uses combination of #version #Id field to decide the whether to merge or insert.
null #id and null #version would mean new record hence insert
if #id is present #version field is used to decide whether to merge or insert.
Update is only invoked when (update .... where id = xxx and version = 0)
Beacuse you have #id and #version missing, its trying to insert, because underlysing system decided this is new record and when run sql u get error.
Can you pls try with #GeneratedValue(strategy = GenerationType.AUTO)
This worked for me.
I have the following Entity Relations:
#AllArgsConstructor
#NoArgsConstructor
#Builder
#Data
#Entity
public class BatchProcessRecord implements Serializable, Cloneable {
...
#ManyToOne
#JoinColumn(name = "batch_process_id")
private BatchProcess batchProcess;
}
#AllArgsConstructor
#NoArgsConstructor
#Builder
#Data
#Entity
public class BatchProcess implements Serializable, Cloneable {
#Id #GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "batchProcess")
private List<BatchProcessRecord> records;
}
And the following code that saves the entities:
// Create batch process
BatchProcess batchProcess = BatchProcess.builder()
....
.records(records)
.build();
// Save entity
batchProcessRepository.save(batchProcess);
In the console, it generates the inserts as expected (with 2 children), but without filling batch_process_id (JoinColumn).
What is happening?
Console:
Hibernate: insert into batch_process (batch_end_date, batch_entries_count, batch_entries_with_issues, batch_name, batch_start_date, report_file_download_date, report_file_name, result_file_name, result_file_upload_date, status) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
Hibernate: insert into batch_process_record (address_number, batch_process_id, city, first_name, full_street_address, last_name, maternal_name, post_directional, pre_directional, reference_number, ssn, state, street_type, zip_code) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
Hibernate: insert into batch_process_record (address_number, batch_process_id, city, first_name, full_street_address, last_name, maternal_name, post_directional, pre_directional, reference_number, ssn, state, street_type, zip_code) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
2
Repository:
public interface BatchProcessRepository extends
JpaRepository<BatchProcess, Long> {
}
I'm using eclipselink in my web application (i use vaadin with oracle as DATABASE) but i'm facing a problem with the Id values.
I have this simple schema :
encaiss (#MappedSuperclass contains just Id)
|
|
Encaissement (it extends encaiss so as to have the ID)
/ \
/ \
Encaissement_Technique (extends Encaissement) Encaissement_espece
/ \
/ \
Encaissement_Cheque Encaissement_Virement (both extend Encaissement_Technique to have the ID)
When i create an instance of Encaissement_virement for example, the Id generated is random eventhough i set allocationSize = 1, initialValue = 1.
Those are the entities :
====================Entity encaiss (contains just the ID)==============
#MappedSuperclass
public abstract class encaiss {
#Id
#GeneratedValue(strategy=GenerationType.AUTO, generator="encaiss_seq_gen")
#SequenceGenerator(name="encaiss_seq_gen", sequenceName="ENCAISSEMENT_SEQ", allocationSize = 1, initialValue = 1)
protected long id_encaissement;
public long getId_encaissement() {
return id_encaissement;
}
public void setId_encaissement(long id_encaissement) {
this.id_encaissement = id_encaissement;
}
}
============================entity Encaissement=======================
#Entity
#Inheritance(strategy=InheritanceType.JOINED)
#DiscriminatorColumn(name="ENCAISS_TYPE")
#Table(name="ENCAISSEMENT")
public class Encaissement extends encaiss implements Serializable{
#Column(name="LIBELLE")
protected String libelle;
#Column(name="PIECE_JOINTE")
protected String piece_jointe;
#Temporal(TemporalType.DATE)
#Column(name="DATE_ENCAISSEMENT")
protected Date date_encaissement;
#Embedded
protected Avis_Recette avis_recette;
public Encaissement(String libelle, String piece_jointe, Date date_encaissement){
this.libelle=libelle;
this.piece_jointe=piece_jointe;
this.date_encaissement=date_encaissement;
}
public Encaissement(){
}
}
====================entity Encaissement_Technique======================
#Entity
#DiscriminatorValue("Technique")
#Inheritance(strategy=InheritanceType.JOINED)
#DiscriminatorColumn(name="ENCAISS_TECHNIQUE_TYPE")
#Table(name="ENCAISSEMENT_TECHNIQUE")
public class Encaissement_Technique extends Encaissement implements Serializable{
public Encaissement_Technique(){
}
}
====================entity Encaissement_Cheque========================
#Entity
#DiscriminatorValue("C")
#Table(name="ENCAISSEMENT_CHEQUE")
public class Encaissement_Cheque extends Encaissement_Technique{
#Column(name="ETAT_AVISCREDIT")
private String etat_avisCredit;
#Embedded
private Cheque cheque;
public Encaissement_Cheque(String etat_avisCredit, Date date_encaissement){
this.etat_avisCredit=etat_avisCredit;
this.date_encaissement=date_encaissement;
}
public Encaissement_Cheque(){
}
}
====================entity Encaissement_Virement=======================
#Entity
#DiscriminatorValue("V")
#Table(name="ENCAISSEMENT_VIREMENT")
public class Encaissement_Virement extends Encaissement_Technique{
#Temporal(TemporalType.DATE)
#Column(name="DATE_VIREMENT")
private Date date_virement;
public Encaissement_Virement(Date date_virement, String libelle, String piece_jointe, Float primCoass, Date date_encaissement){
this.date_virement=date_virement;
this.primeCoass=primCoass;
this.piece_jointe=piece_jointe;
this.libelle=libelle;
this.date_encaissement=date_encaissement;
}
public Encaissement_Virement(){
}
}
I created from eclipse an instance of Encaissement_virement, the generated id is 71 then when i create another it gives it 75, after that it jumps to 91 !!! then it's adding 3 after each insertion (i mean id=103 then 106 then 109) !!!!!
PS : When i excute
Encaissement_virement ev=new Encaissement_virement();
//ev.getters and setters
ev.getId_Encaissement(); doesn't return the real Id instead it returns 0 whether it is called before or after the commit.
This problem is driving me crazy and i can't figure out the problem. (i think that the inheritance id or the id type (which is long) are not working).
I would appreciate your help. Thanks.
Edit :
After using sql developer i'm convinced that the problem is in the inheritance.
This is what i get when i try to insert an Encaissement_virement (which is logical because it extends another entity) :
Can anyone help me fix the inheritance problem in jpa eclipselikn. Thanks again.
Edit2
I create a new instance of Encaissement_virement using this code :
JPAContainer<Encaissement_Espece> ee=JPAContainerFactory.make(Encaissement_Espece.class, PERSISTANCE_UNIT);
Encaissement_Espece encaissEspece;
JPAContainer<Encaissement_Cheque> ec=JPAContainerFactory.make(Encaissement_Cheque.class, PERSISTANCE_UNIT);
Encaissement_Cheque encaissCheque;
JPAContainer<Encaissement_Virement> ev=JPAContainerFactory.make(Encaissement_Virement.class, PERSISTANCE_UNIT);
Encaissement_Virement encaissVirement;
//Some code here.
switch (typeEncaissement) {
case 0:
encaissEspece=new Encaissement_Espece();
encaissEspece.setCaisse(caisseEnc);
encaissEspece.setDate_encaissement(dateEnc);
encaissEspece.setLibelle(libelleEnc);
encaissEspece.setMontant(montantEncEspece);
encaissEspece.setPiece_jointe(pieceJointesEnc);
encaissEspece.setClient(clientEnc);
//UUID uuid = (UUID)ee.addEntity(encaissEspece);
//EntityItem<Encaissement_Espece> eeEntityItem = ee.getItem(uuid);
IdEnc=(Long)ee.addEntity(encaissEspece);
ee.commit();
break;
case 1:
encaissCheque=new Encaissement_Cheque();
encaissCheque.setBanque(banqueEnc);
encaissCheque.setCheque(chequeEnc);
encaissCheque.setClient(clientEnc);
encaissCheque.setDate_encaissement(dateEnc);
encaissCheque.setLibelle(libelleEnc);
encaissCheque.setPiece_jointe(pieceJointesEnc);
encaissCheque.setPrimeCoass(primeCoassEnc);
IdEnc=(Long)ec.addEntity(encaissCheque);
ec.commit();
break;
case 2:
encaissVirement=new Encaissement_Virement();
encaissVirement.setBanque(banqueEnc);
encaissVirement.setClient(clientEnc);
encaissVirement.setDate_encaissement(dateEnc);
encaissVirement.setLibelle(libelleEnc);
encaissVirement.setPiece_jointe(pieceJointesEnc);
encaissVirement.setPrimeCoass(primeCoassEnc);
encaissVirement.setDate_virement(dateVir);
IdEnc=(Long)ev.addEntity(encaissVirement);
ev.commit();
break;
default:
break;
this is the result (a new anstance with 66 as id) :
[EL Fine]: sql: 2015-04-01 17:25:45.301--ServerSession(5981709)--Connection(27335918)--Thread(Thread[http-bio-8080-exec-5,5,main])--SELECT ENCAISSEMENT_SEQ.NEXTVAL FROM DUAL
[EL Fine]: sql: 2015-04-01 17:25:45.316--ClientSession(26722029)--Connection(27335918)--Thread(Thread[http-bio-8080-exec-5,5,main])--INSERT INTO ENCAISSEMENT (ID_ENCAISSEMENT, DATE_ENCAISSEMENT, LIBELLE, PIECE_JOINTE, AGENCE, DATE_AVIS_RECETTE, ENDROIT, PROVENANCE, UNITE, ID_CLIENT, ENCAISS_TYPE) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
bind => [66, 2015-04-01, titre, jointes, null, null, null, null, null, 2, V]
[EL Fine]: sql: 2015-04-01 17:25:45.795--ClientSession(26722029)--Connection(27335918)--Thread(Thread[http-bio-8080-exec-5,5,main])--INSERT INTO ENCAISSEMENT_TECHNIQUE (PRIMECOASS, ID_BANQUE, ID_ENCAISSEMENT) VALUES (?, ?, ?)
bind => [123.0, 1, 66]
[EL Fine]: sql: 2015-04-01 17:25:45.936--ClientSession(26722029)--Connection(27335918)--Thread(Thread[http-bio-8080-exec-5,5,main])--INSERT INTO ENCAISSEMENT_VIREMENT (DATE_VIREMENT, ID_ENCAISSEMENT) VALUES (?, ?)
bind => [2015-04-01, 66]
Then i drop this row and create another instance with the same code, and i get :
[EL Fine]: sql: 2015-04-01 17:30:42.119--ServerSession(27444543)--Connection(6011948)--Thread(Thread[http-bio-8080-exec-15,5,main])--SELECT ENCAISSEMENT_SEQ.NEXTVAL FROM DUAL
[EL Fine]: sql: 2015-04-01 17:30:42.13--ClientSession(1011455)--Connection(6011948)--Thread(Thread[http-bio-8080-exec-15,5,main])--INSERT INTO ENCAISSEMENT (ID_ENCAISSEMENT, DATE_ENCAISSEMENT, LIBELLE, PIECE_JOINTE, AGENCE, DATE_AVIS_RECETTE, ENDROIT, PROVENANCE, UNITE, ID_CLIENT, ENCAISS_TYPE) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
bind => [69, 2015-04-01, titre, j, null, null, null, null, null, 4, V]
[EL Fine]: sql: 2015-04-01 17:30:42.195--ClientSession(1011455)--Connection(6011948)--Thread(Thread[http-bio-8080-exec-15,5,main])--INSERT INTO ENCAISSEMENT_TECHNIQUE (PRIMECOASS, ID_BANQUE, ID_ENCAISSEMENT) VALUES (?, ?, ?)
bind => [123.0, 1, 69]
[EL Fine]: sql: 2015-04-01 17:30:42.211--ClientSession(1011455)--Connection(6011948)--Thread(Thread[http-bio-8080-exec-15,5,main])--INSERT INTO ENCAISSEMENT_VIREMENT (DATE_VIREMENT, ID_ENCAISSEMENT) VALUES (?, ?)
bind => [2015-04-01, 69]
You can notice that instead of getting 67 as Id i get 69 ??
I'm having a hard time figuring out how to make effective use of query caching criteria queries on the following entity:
#Entity #Table(name = "category_configuration_values")
#Immutable
#Cacheable
#org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_ONLY)
public class CategoryConfigurationValue implements Serializable {
private static final long serialVersionUID = 3L;
private static final Logger LOGGER = LoggerFactory.getLogger(CategoryConfigurationValue.class);
#EmbeddedId
private CategoryConfigurationValuePk primaryKey;
#Column(name = "value")
private String value;
#Override
public boolean equals(Object o) { ... }
#Override
public int hashCode() { ... }
}
#Embeddable
#Cacheable
#org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_ONLY)
class CategoryConfigurationValuePk implements Serializable {
private static final long serialVersionUID = 5068893389269876464L;
#Column(name = "configuration_type_id")
private int configurationTypeId;
#Column(name = "category_id", columnDefinition = "smallint")
private int categoryId;
#Override
public int hashCode() { ... }
#Override
public boolean equals(Object obj) { ... }
}
The one of the criteria which is resulting in cache misses is:
Criteria criteria = getCurrentSession().createCriteria(CategoryConfigurationValue.class);
criteria.setCacheable(true);
criteria.setCacheRegion("query.AllConfigurationValuesForCategoriesAndAncestors");
criteria.add(Restrictions.in("primaryKey.categoryId", categoryIds));
List<CategoryConfigurationValue> allCategoryConfigurationValues = criteria.list();
The first time is is executed I get the 'in' query:
Hibernate: select this_.category_id as category1_4_0_, this_.configuration_type_id as configur2_4_0_, this_.value as value4_0_ from category_configuration_values this_ where this_.category_id in (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
If I execute it another time I get a lot of the following, which to me looks like cache misses:
Hibernate: select categoryco0_.category_id as category1_4_0_, categoryco0_.configuration_type_id as configur2_4_0_, categoryco0_.value as value4_0_ from category_configuration_values categoryco0_ where categoryco0_.category_id=? and categoryco0_.configuration_type_id=?
Hibernate: select categoryco0_.category_id as category1_4_0_, categoryco0_.configuration_type_id as configur2_4_0_, categoryco0_.value as value4_0_ from category_configuration_values categoryco0_ where categoryco0_.category_id=? and categoryco0_.configuration_type_id=?
Hibernate: select categoryco0_.category_id as category1_4_0_, categoryco0_.configuration_type_id as configur2_4_0_, categoryco0_.value as value4_0_ from category_configuration_values categoryco0_ where categoryco0_.category_id=? and categoryco0_.configuration_type_id=?
Hibernate: select categoryco0_.category_id as category1_4_0_, categoryco0_.configuration_type_id as configur2_4_0_, categoryco0_.value as value4_0_ from category_configuration_values categoryco0_ where categoryco0_.category_id=? and categoryco0_.configuration_type_id=?
Hibernate: select categoryco0_.category_id as category1_4_0_, categoryco0_.configuration_type_id as configur2_4_0_, categoryco0_.value as value4_0_ from category_configuration_values categoryco0_ where categoryco0_.category_id=? and categoryco0_.configuration_type_id=?
...
What could I be missing here?
eventhough you've enabled query caching, you need to explicitly add the class CategoryConfigurationValue as cachable, then all instances of the class is marked as cachable, this would solve your problem..
Anantha Sharma