I have a running Spring Boot application with Mysql and Hibernate.
While launching it, i'm getting this error
Unsuccessful: alter table SMARTPARK.illuminazione add constraint FK_4kmtr3q9e2hnaoutsxgahhm63 foreign key (id_interruttore) references SMARTPARK.interruttori (id_interruttore)
2016-05-05 08:46:35 ERROR SchemaUpdate:262 - Cannot add foreign key constraint
I have two table/entities
Illuminazione.java is (just the interesting parts...)
#Entity
#Table(name = "illuminazione", catalog = "SMARTPARK")
public class Illuminazione {
private int idilluminazione;
private Interruttore interruttore;
private Date dateTime;
private Date lastDateTime;
private boolean isLit;
#ManyToOne
#JoinColumn(name = "id_interruttore")
public Interruttore getInterruttore() {
return this.interruttore;
}
public void setInterruttore(Interruttore interruttore) {
this.interruttore = interruttore;
}
In Interruttore.java I have the #OneToMany relation with Illuminazione
#Entity
#Table(name = "interruttori", catalog = "SMARTPARK", uniqueConstraints = #UniqueConstraint(columnNames = "id_interruttore"))
public class Interruttore implements java.io.Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
private int idInterruttore;
private int numeroInterruttore;
private String nomeInterruttore;
private String descrizione;
private List<Luce> luci;
private GpioController gpio;
private GpioPinDigitalOutput relePin;
private Pin pin;
private boolean remoto;
private boolean stato;
private Date dateTime;
private Set<Illuminazione> illuminazione;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "interruttore")
public Set<Illuminazione> getIlluminazione() {
return illuminazione;
}
public void setIlluminazione(Set<Illuminazione> illuminazione) {
this.illuminazione = illuminazione;
}
Every time I start the application, during the boot i'm getting this error (even if the application seems working good...)
I had the same error message, which I found out was caused by incorrect annotations. Hibernate was trying to run
alter table cidades
add constraint FKdt0b3ronwpi1upsrhaeq6r69n
foreign key (estado_id)
references estados (id)
And when I looked at my Cidade.java, I found this mapping
#ManyToOne
#JoinColumn(name = "cidade_id")
private Estado estado;
The error was in "cidade_id", which should have been "estado_id". It would be great if #besmart could provide the DB table info, since the error could be caused by a typo (e.g. id_interruttore could actually be id_interruttori).
I hope this helps someone in the future.
I hit similar problem .
To me apparently hibernate/Spring was NOT using mysql Engine -INNODB , you need engine INNODB for mysql to generate foreign key constraint.
Using the following properties in application.properties, makes spring boot/hibernate to use mysql engine INNODB. So foreign key constraint works and hence also delete cascade
spring.jpa.hibernate.use-new-id-generator-mappings=true
spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect
Related
I am new to Spring Boot. I am trying to use the save() functionality via the JPA library using Postman for the first time. My database is a legacy Mysql database. Generically speaking, this table contains data of baseball players who have been drafted into a fantasy baseball league. The primary key of my table is 'play_id', and I also track the player's 'mlb_id' (Major League Baseball's unique identifier) in the same table.
Here is my code:
Table setup in Mysql:
CREATE TABLE `mlb_rosters` (
`play_id` int(10) NOT NULL,
`mlb_id` int(10) NOT NULL,
`name_first` varbinary(255) NOT NULL,
`name_last` varbinary(255) NOT NULL,
`bats` varchar(1) NOT NULL,
`throws` varchar(1) NOT NULL,
`birthday` date NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
ALTER TABLE `mlb_rosters`
ADD PRIMARY KEY (`play_id`),
ADD UNIQUE KEY `mlb_id` (`mlb_id`),
ADD UNIQUE KEY `mlb_id_2` (`mlb_id`);
ALTER TABLE `mlb_rosters`
MODIFY `play_id` int(10) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=6730;
I also ran insert statements for approximately ~1500 players, so this is not a blank table.
My object in Springboot:
package com.example.demo.entities;
import javax.persistence.*;
#Entity
#Table(name="mlb_rosters")
public class IbcMlbPlayer {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name="play_id", columnDefinition = "int(10)")
private Integer playId;
#Column(name="mlb_id")
private Integer mlbId;
#Column(name="name_first", columnDefinition = "varbinary(255)")
private String nameFirst;
#Column(name="name_last", columnDefinition = "varbinary(255)")
private String nameLast;
#Column(name="bats")
private String bats;
#Column(name="throws")
private String thrws;
#Column(name="birthday")
private String birthday;
public IbcMlbPlayer(){
}
public Integer getPlayId() {
return playId;
}
public void setPlayId(Integer playId) {
this.playId = playId;
}
public Integer getMlbId() {
return mlbId;
}
public void setMlbId(Integer mlbId) {
this.mlbId = mlbId;
}
public String getNameFirst() {
return nameFirst;
}
public void setNameFirst(String nameFirst) {
this.nameFirst = nameFirst;
}
public String getNameLast() {
return nameLast;
}
public void setNameLast(String nameLast) {
this.nameLast = nameLast;
}
public String getBats() {
return bats;
}
public void setBats(String bats) {
this.bats = bats;
}
public String getThrws() {
return thrws;
}
public void setThrws(String thrws) {
this.thrws = thrws;
}
public String getBirthday() {
return birthday;
}
public void setBirthday(String birthday) {
this.birthday = birthday;
}
}
The relevant path of my controller:
#PostMapping(value = "/saveIbcMlbPlayer")
public IbcMlbPlayer saveIbcMlbPlayer(#RequestBody IbcMlbPlayer ibcMlbPlayer){
return ibcMlbPlayerDao.save(ibcMlbPlayer);
}
My Dao:
package com.example.demo.dao;
import com.example.demo.entities.IbcMlbPlayer;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
#Repository
public interface IbcMlbPlayerDao extends JpaRepository<IbcMlbPlayer, Integer> {
}
When I attempt to do a Post request to the save path and pass in the JSON object of the player who I'm attempting to create, I get the following error:
Duplicate entry '25' for key 'PRIMARY'
In this case, I've tried this 25 times, so Postman/Spring Boot keep incrementing the 'play_id' field by 1 (this number goes up in the error message by one each time I test).
I understand the error, for whatever reason, Spring Boot isn't getting the max value of the 'play_id' field, incrementing it by one, and then attempting to do the insert. I would have expected 'play_id' to be 6730, which I believe is the table's max play_id plus one. Does anyone know how to fix this? Any help would be really appreciated!
AUTO shouldn't be used as GenerationType you must use IDENTITY
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name="play_id", columnDefinition = "int(10)")
private Integer playId;
I wrote an application (Springboot + Data JPA + Data Rest) that keeps throwing OutOfMemoryException at me when the application loads. I can skip that code that runs on application start but then the exception may happen later down the road. It's probably best to show you what happens on application start because it's actually super simple and should not cause any problems imho:
#SpringBootApplication
#EnableAsync
#EnableJpaAuditing
public class ScraperApplication {
public static void main(String[] args) {
SpringApplication.run(ScraperApplication.class, args);
}
}
#Component
#RequiredArgsConstructor(onConstructor = #__(#Autowired))
public class DefaultDataLoader {
private final #NonNull LuceneService luceneService;
#Transactional
#EventListener(ApplicationReadyEvent.class)
public void load() {
luceneService.reindexData();
}
}
#Service
#RequiredArgsConstructor(onConstructor = #__(#Autowired))
public class LuceneService {
private static final Log LOG = LogFactory.getLog(LuceneService.class);
private final #NonNull TrainingRepo trainingRepo;
private final #NonNull EntityManager entityManager;
public void reindexData() {
LOG.info("Reindexing triggered");
FullTextEntityManager fullTextEntityManager = Search.getFullTextEntityManager(entityManager);
fullTextEntityManager.purgeAll(Training.class);
LOG.info("Index purged");
int page = 0;
int size = 100;
boolean morePages = true;
Page<Training> pageData;
while (morePages) {
pageData = trainingRepo.findAll(PageRequest.of(page, size));
LOG.info("Loading page " + (page + 1) + "/" + pageData.getTotalPages());
pageData.getContent().stream().forEach(t -> fullTextEntityManager.index(t));
fullTextEntityManager.flushToIndexes(); // flush regularly to keep memory footprint low
morePages = pageData.getTotalPages() > ++page;
}
fullTextEntityManager.flushToIndexes();
LOG.info("Index flushed");
}
}
You can see what I am doing is clear out the index, read all Trainings from the TrainingRepo in a paged way (100 at a time) and write them into the index. Not much going on actually. A few minutes after the "Index purged" message I get this - and only this:
java.lang.OutOfMemoryError: Java heap space
In the logs I get to see "Index purged" but never see any "Loading page ..." message, so it must be stuck on the findAll() call.
I had the JVM write a heap dump and loaded it into Eclipse Memory Analyzer and got a full stack trace: https://gist.github.com/mathias-ewald/2fddb9762427374bb04d332bd0b6b499
I also looked around the report a bit, but I need help interpreting this information which is why I attached some screenshots from Eclipse Memory Analyzer.
EDIT:
I just enabled "show-sql" and saw this before everything hung:
Hibernate: select training0_.id as id1_9_, training0_.created_date as created_2_9_, training0_.description as descript3_9_, training0_.duration_days as duration4_9_, training0_.execution_id as executi14_9_, training0_.level as level5_9_, training0_.modified_date as modified6_9_, training0_.name as name7_9_, training0_.price as price8_9_, training0_.product as product9_9_, training0_.quality as quality10_9_, training0_.raw as raw11_9_, training0_.url as url12_9_, training0_.vendor as vendor13_9_ from training training0_ where not (exists (select 1 from training training1_ where training0_.url=training1_.url and training0_.created_date<training1_.created_date)) limit ?
Hibernate: select execution0_.id as id1_1_0_, execution0_.created_date as created_2_1_0_, execution0_.duration_millis as duration3_1_0_, execution0_.message as message4_1_0_, execution0_.modified_date as modified5_1_0_, execution0_.scraper as scraper6_1_0_, execution0_.stats_id as stats_id8_1_0_, execution0_.status as status7_1_0_, properties1_.execution_id as executio1_2_1_, properties1_.properties as properti2_2_1_, properties1_.properties_key as properti3_1_, stats2_.id as id1_5_2_, stats2_.avg_quality as avg_qual2_5_2_, stats2_.max_quality as max_qual3_5_2_, stats2_.min_quality as min_qual4_5_2_, stats2_.null_products as null_pro5_5_2_, stats2_.null_vendors as null_ven6_5_2_, stats2_.products as products7_5_2_, stats2_.tags as tags8_5_2_, stats2_.trainings as training9_5_2_, stats2_.vendors as vendors10_5_2_, producthis3_.stats_id as stats_id1_6_3_, producthis3_.product_histogram as product_2_6_3_, producthis3_.product_histogram_key as product_3_3_, taghistogr4_.stats_id as stats_id1_7_4_, taghistogr4_.tag_histogram as tag_hist2_7_4_, taghistogr4_.tag_histogram_key as tag_hist3_4_, vendorhist5_.stats_id as stats_id1_8_5_, vendorhist5_.vendor_histogram as vendor_h2_8_5_, vendorhist5_.vendor_histogram_key as vendor_h3_5_ from execution execution0_ left outer join execution_properties properties1_ on execution0_.id=properties1_.execution_id left outer join stats stats2_ on execution0_.stats_id=stats2_.id left outer join stats_product_histogram producthis3_ on stats2_.id=producthis3_.stats_id left outer join stats_tag_histogram taghistogr4_ on stats2_.id=taghistogr4_.stats_id left outer join stats_vendor_histogram vendorhist5_ on stats2_.id=vendorhist5_.stats_id where execution0_.id=?
Apparently, it creates the statement to fetch all the Training entities but the Execution statement is the last it manages to execute.
I changed the relation from Training to Execution from #ManyToOne to #ManyToOne(fetch = FetchType.LAZY) and suddenly I the code was able to load data into the index again. So I am thinking something might be wrong with my Execution entity mapping. Let me share the code with you:
#Entity
#Data
#EntityListeners(AuditingEntityListener.class)
public class Execution {
public enum Status { SCHEDULED, RUNNING, SUCCESS, FAILURE };
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#ToString.Include
private Long id;
#Column(updatable = false)
private String scraper;
#CreatedDate
private LocalDateTime createdDate;
#LastModifiedDate
private LocalDateTime modifiedDate;
#Min(0)
#JsonProperty(access = Access.READ_ONLY)
private Long durationMillis;
#ElementCollection(fetch = FetchType.EAGER)
private Map<String, String> properties;
#NotNull
#Enumerated(EnumType.STRING)
private Status status;
#Column(length = 9999999)
private String message;
#EqualsAndHashCode.Exclude
#OneToOne(cascade = CascadeType.ALL)
private Stats stats;
}
And since it is a relation of Execution, here's the Stats entity, too:
#Entity
#Data
public class Stats {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#ToString.Include
private Long id;
private Long trainings;
private Long vendors;
private Long products;
private Long tags;
private Long nullVendors;
private Long nullProducts;
private Double minQuality;
private Double avgQuality;
private Double maxQuality;
#ElementCollection(fetch = FetchType.EAGER)
private Map<String, Long> vendorHistogram;
#ElementCollection(fetch = FetchType.EAGER)
private Map<String, Long> productHistogram;
#ElementCollection(fetch = FetchType.EAGER)
private Map<String, Long> tagHistogram;
}
All this is running in a single transaction and I can't see a clear here, so the EntityManager loading all this data still references it.
To fix this inject the EntityManager and invoke clear. Or alternatively make the scope of the transaction the processing of one page.
I recommend the TransactionTemplate for this.
I'm not familiar with the FullTextEntityManager but it might have similar problems.
For more background you might want to read up on the JPA entity lifecycle.
I believe it has to do with your FullTextEntityManager not finding enough memory. You have to configure your queryPlanCache.Go through this thread on how to Stackoverflow and this one too.
I am using Spring Data JPA (1.7.2-RELEASE) in combination with Hibernate (4.3.8.Final) and MySQL (5.5). I want to manage two entities in a bidirectional assosciation. The save and update of the enties works fine, but the deletion doesn't work.
#Entity
public class Beacon extends AbstractEntity {
#OneToMany(fetch = FetchType.EAGER, mappedBy = "beacon", cascade = ALL)
private Set<Comment> comments;
/**
* #return the comments
*/
public Set<Comment> getComments() {
return comments;
}
/**
* #param comments the comments to set
*/
public void setComments(Set<Comment> comments) {
this.comments = comments;
}
}
and
#Entity
public class Comment extends AbstractEntity {
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "beacon_id")
private Beacon beacon;
public Beacon getBeacon() {
return beacon;
}
public void setBeacon(Beacon beacon) {
this.beacon = beacon;
}
}
Having a beacon with comments stored in the database, I want to delete the comment but it doesn't work. I don't get an exception but the entity is still present in the database.
This is my unit test:
#Test
public void deleteWithStrategyCheck() {
Beacon beacon = this.beaconRepository.save(createBeacon());
Comment comment = this.commentRepository.save(createEntity());
comment.setBeacon(beacon);
comment = this.commentRepository.save(comment);
this.commentRepository.delete(comment.getId());
assertThat(this.commentRepository.exists(comment.getId())).isFalse();
assertThat(this.beaconRepository.exists(beacon.getId())).isTrue();
assertThat(this.beaconRepository.findOne(beacon.getId()).getComments()).doesNotContain(comment);
}
If I delete the comment via a sql statement it works.
You need to add orphanRemoval = true to your #OneToMany mappings, and remove the Comment from the parrent beacon.
If you delete the Comment without removing it from the parrent collection you should actually get the exception (unless you are not using InnoDB storage engine, (and ou should)).
beacon.getComments().remove(comment),
will do the work then. (with orphanRemoval you don't need to call EM.remove(comment). Without it, you need to remove the comment from the collection and call EM.remove(comment).
I have two Classes mapping each one to an Entity in MySQL database. Whenever I try to map into to DB I got an MySQL Error
Class Owner:
#Entity
public class Owner {
#Id #GeneratedValue
private int idOwner;
public int getIdOwner() {
return idOwner;
}
public void setIdOwner(int idOwner) {
this.idOwner = idOwner;
}
}
Class Car with FK:
#Entity
public class Car {
#Id #GeneratedValue
private int idCar;
#ManyToOne
#JoinColumn( name = "idOwner")
private Owner owner;
public int getIdCar() {
return idCar;
}
public void setIdCar(int idCar) {
this.idCar = idCar;
}
public Owner getOwner() {
return owner;
}
public void setOwner(Owner owner) {
this.owner = owner;
}
}
Code running:
EntityManagerFactory f = Persistence.createEntityManagerFactory("glorious");
EntityManager em = f.createEntityManager();
EntityTransaction t = em.getTransaction();
t.begin();
Car c = new Car();
Owner o = new Owner();
c.setOwner(o);
em.persist(c);
em.persist(o);
t.commit();
f.close();
em.close();
Error:
GRAVE: Unsuccessful: alter table .Car add index FK107B43F620606 (idOwner), add constraint FK107B43F620606 foreign key (idOwner) references .Owner (idOwner)
27/05/2014 20:35:01 org.hibernate.tool.hbm2ddl.SchemaExport create
GRAVE: Can't create table 'glorious.#sql-2aa_1f8' (errno: 150)
MySQL Version : 5.5.34
Engine : InnoDB
Hibernate Dialect : MySQL5InnoDBDialect
I took the script generated by Hibernate and tested it directly in phpMyAdmin, it didn't work.
SQL script :
alter table .Car add index FK107B43F620606 (idOwner), add constraint FK107B43F620606 foreign key (idOwner) references .Owner (idOwner)
If I fix the script by replacing the tables name with , e.g. Car or glorious.Car than it works. Anyone has an idea?
Solved it. My persistence.xml had the property default_schema set to empty. That's why no DB name was appearing before the table's name.
I have issues persisting a simple 2 classes on DataNucleus 3.1.3 on MySQL, where DataNucleus seems to create invalid foreign-keys, ending up in a "foreign key constraint fails" -exception from database.
Here my classes:
// datastore since i dont care about identity here
#PersistenceCapable(identityType = IdentityType.DATASTORE)
class A {
#Persistent
int x;
#Persistent
int y;
}
// identity type:application here to enable id lookups
#PersistenceCapable
class B {
#PrimaryKey
#Persistent(valueStrategy = IdGeneratorStrategy.NATIVE)
long id;
#Persistent
double longitude;
#Persistent
double latitude;
// simple 1:1 unidirectional
#Persistent
A a;
}
The schemaTool created the tables (InnoDB) which looks good, but an insert fails, here the logs:
12:54:11,369 DEBUG [DataNucleus.Datastore.Native] - INSERT INTO `A` (`X`,`Y`) VALUES (<1>,<1>)
12:54:11,387 DEBUG [DataNucleus.Datastore.Persist] - Execution Time = 18 ms (number of rows = 1)
12:54:11,398 DEBUG [DataNucleus.Datastore.Persist] - Object "foo.A#624af1e" was inserted in the datastore and was given strategy value of "3"
12:54:11,403 DEBUG [DataNucleus.Datastore] - Closing PreparedStatement "org.datanucleus.store.rdbms.ParamLoggingPreparedStatement#6f5ba238"
12:54:11,404 DEBUG [DataNucleus.Datastore.Native] - INSERT INTO `B` (`LONGITUDE`,`LATITUDE`,`A_A_ID_OID`) VALUES (<0.5099776394799052>,<0.6191090630996077>,<51>)
12:54:11,419 WARN [DataNucleus.Datastore.Persist] ... Cannot add or update a child row: a foreign key constraint fails (`xperimental`.`B`, CONSTRAINT `B_FK1` FOREIGN KEY (`A_A_ID_OID`) REFERENCES `A` (`A_ID`))
Looking at the logs on lines (3) and (5) its very suspicious that an insert into table A returned a PK of "3" but DataNucleus instead uses a value of "51" as FK on A when inserting data into table B which causes the violation.
Where is the issue? Thanks
UPDATE: the resources
Class A
package jdotest.a;
import javax.jdo.annotations.IdentityType;
import javax.jdo.annotations.PersistenceCapable;
import javax.jdo.annotations.Persistent;
#PersistenceCapable(identityType = IdentityType.DATASTORE)
public class A {
#Persistent
private int x;
#Persistent
private int y;
public int getX() {
return x;
}
public int getY() {
return y;
}
}
Class B
package jdotest.b;
import javax.jdo.annotations.IdGeneratorStrategy;
import javax.jdo.annotations.PersistenceCapable;
import javax.jdo.annotations.Persistent;
import javax.jdo.annotations.PrimaryKey;
import jdotest.a.A;
#PersistenceCapable
public class B {
#PrimaryKey
#Persistent(valueStrategy = IdGeneratorStrategy.NATIVE)
long id;
#Persistent
double longitude;
#Persistent
double latitude;
// simple 1:1 unidirectional
#Persistent
A a;
public long getId() {
return id;
}
public double getLongitude() {
return longitude;
}
public double getLatitude() {
return latitude;
}
public void setA(A a) {
this.a = a;
}
public A getA() {
return a;
}
}
Dao
package dao;
import javax.jdo.JDOHelper;
import javax.jdo.PersistenceManager;
import javax.jdo.PersistenceManagerFactory;
import javax.jdo.Transaction;
import jdotest.b.B;
public class BDao {
public void write(B b) {
PersistenceManagerFactory pmf = JDOHelper.getPersistenceManagerFactory("cloud-sql");
PersistenceManager pm = pmf.getPersistenceManager();
Transaction tx = pm.currentTransaction();
try {
tx.begin();
pm.makePersistent(b);
tx.commit();
} finally {
if (tx.isActive())
tx.rollback();
pm.close();
}
}
}
execution
package exec;
import jdotest.a.A;
import jdotest.b.B;
import dao.BDao;
public class Ex{
public void persist(){
A a = new A();
B b = new B();
b.setA(a);
new BDao().write(b); //<-- exception
}
}
the exception *
java.sql.SQLException: Cannot add or update a child row: a foreign key constraint fails (xperimental.b, CONSTRAINT B_FK1 FOREIGN KEY (A_A_ID_OID) REFERENCES a (A_ID))