I generated application using Jhipster. In start everything was working fine but as application grow tournament entity become issue regarding performances.
This is my entity :
/**
* A Tournament.
*/
#Entity
#Table(name = "tournament")
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
#Document(indexName = "tournament")
public class Tournament implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
#SequenceGenerator(name = "sequenceGenerator")
private Long id;
#Column(name = "name")
private String name;
#Column(name = "location")
private String location;
#Column(name = "url")
private String url;
#Column(name = "start_date")
private ZonedDateTime startDate;
#Column(name = "end_date")
private ZonedDateTime endDate;
#Column(name = "entry_fee")
private Double entryFee;
#Column(name = "prize")
private Double prize;
#Column(name = "goods")
private String goods;
#Column(name = "favorite_rating")
private Long favoriteRating;
#Column(name = "participants_number")
private Integer participantsNumber;
#Column(name = "finished")
private Boolean finished;
#Column(name = "view_only")
private Boolean viewOnly;
#Column(name = "image")
private String image;
#Column(name = "description")
private String description;
#Column(name = "teams_applied")
private String teamsApplied;
#Lob
#Column(name = "schedule")
private String schedule;
#Lob
#Column(name = "prize_distribution")
private String prizeDistribution;
#Lob
#Column(name = "contacts")
private String contacts;
#Lob
#Column(name = "rules")
private String rules;
#OneToMany(mappedBy = "tournament", fetch = FetchType.LAZY)
#JsonIgnore
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
private Set<Stream> streams = new HashSet<>();
#ManyToMany
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
#JoinTable(name = "tournament_platforms", joinColumns = #JoinColumn(name = "tournaments_id", referencedColumnName = "id"), inverseJoinColumns = #JoinColumn(name = "platforms_id", referencedColumnName = "id"))
private Set<Platform> platforms = new HashSet<>();
#ManyToMany(mappedBy = "favoriteTournaments", fetch = FetchType.LAZY)
#JsonIgnore
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
private Set<User> favoriteUsers = new HashSet<>();
#ManyToOne
private Game game;
#ManyToOne
private TournamentStatus status;
#ManyToOne
private EntryType entryType;
#ManyToOne
private TournamentFormat format;
#ManyToOne
private Region region;
#ManyToOne
private GameMode gameMode;
#ManyToOne
private PrizeType prizeType;
#ManyToOne
private Organizer organizer;
#ManyToOne
private TournamentStage stage;
#ManyToOne
private HostPlatform hostPlatforms;
#ManyToOne
private TournamentType type;
#ManyToOne
private PlayType playType;
#ManyToOne
private Currency currency;
#ManyToOne
private Country country;
I am using spring JPA. Getting 20 tournaments from database takes 39 seconds. That is not acceptable. Is there any way i can reduce it to normal speed. What is reason for such a long response time ? Every many to one relation i made unidire
In hibernate's implementation of JPA, #ManyToOne has a fetchType = EAGER by default and you have 14 of them.
#ManyToOne
private Country country;
That means 14 joins for each request. I highly recommend to use fetchType = LAZY for all relationships and deactivate them one by one when needed.
As a rule of thumb, you should not use more than 3 joins per request.
Also take a look at the generated request and use EXPLAIN PLAN in order to understand what the database really does and where it is costly. It will probably reveal some missing indexes on columns used as foreign keys...
Related
I have the following entities in a Hibernate - Spring proyect.
Member:
#Entity
#Table(name = "member")
public class Member implements Serializable {
private static final long serialVersionUID = 1871629487715861212L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#Column(name = "first_name")
private String firstName;
#Column(name = "last_name")
private String lastName;
#Column(name = "ident_doc")
private String identDoc;
#Column(name = "join_date")
private String joinDate;
private String nickname;
#OneToOne(mappedBy = "member")
private MemberContact memberContact;
#OneToMany(mappedBy = "member", cascade = CascadeType.ALL)
private List<MemberChapterLog> memberChapterLogs;
#OneToMany(mappedBy = "member")
private List<ChapterOfficers> chapterOfficers;
#OneToOne(mappedBy = "contactMember", cascade = CascadeType.ALL)
private Chapter asChapterContact;
Chapter:
#Entity
#Table(name = "chapter")
#NamedQuery(
name = "Chapter_Get_Detailed_Members_List",
query = "from MemberChapterLog where chapter.id = :paramChapter and active = true "+
"order by member.lastName asc")
public class Chapter implements Serializable {
private static final long serialVersionUID = -8387387246818721664L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String initials;
#Column(name ="chap_name")
private String chapName;
#ManyToOne
#JoinColumn(name = "category")
private ChapCategory category;
#OneToOne
#JoinColumn(name = "contact_member")
private Member contactMember;
#OneToOne(mappedBy = "chapter", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private ChapterContact chapterContact;
#OneToMany(mappedBy = "chapter")
private List<MemberChapterLog> memberChapterlogs;
#OneToMany(mappedBy = "chapter")
private List<ChapterOfficers> chapterOfficers;
MemberChapterLog:
#Entity
#Table(name = "member_chapter_log")
public class MemberChapterLog implements Serializable {
private static final long serialVersionUID = -643503606583240644L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "member_id")
private Member member;
#ManyToOne
#JoinColumn(name = "chapter_id")
private Chapter chapter;
#Column(name = "log_date")
private String logDate;
private String comment;
private boolean active;
I want to get a list of the active members of certain chapter (passed as ':paramChapter'), order by their last name. When I run the named query at chapter ("from MemberChapterLog where chapter.id = :paramChapter and active = true order by member.lastName asc") it generates the following error:
org.hibernate.HibernateException: Errors in named queries:
Chapter_Get_Detailed_Members_List failed because of: org.hibernate.hql.internal.ast.QuerySyntaxException: unexpected token: member near line 1, column 105 [from dev.xarlsr.cdt.entity.MemberChapterLog where chapter.id = :paramChapter and active = true order by member.lastName asc]
If I delete the order by member.lastName it works properly (without any order, byt the way).
I tried to change the mapping by changing the tables foreign keys and the ownership, but doesn't work. I tried to change the fetch type without results. What am I doing wrong?
The problem is the mapping:
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "member_id")
private Member member;
member is a keyword in JPQL/HQL and soft-keyword handling was only introduced in Hibernate 6, so you will need to change the name of the field to e.g. memberAssociation and the query condition to ... order by memberAssociation.lastName asc
Trying to run a delete query on a many-one relationship. But sometime it's stuck for a while when the count of row delete is more then ~50.
Repository:
#Repository
public interface TransitItemRepository extends JpaRepository<TransitItemsMapping, UUID> {
#Modifying
#Transactional
#Query(value="delete from TransitItemsMapping t where t.grouping_form_id=:groupingFormId",nativeQuery = true)
void deleteByGroupingFormId(#Param("groupingFormId") UUID groupingFormId);
}
Domain:TransitItemsMapping.java
#Data
#Entity
#Table(name = "TransitItemsMapping")
public class TransitItemsMapping implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GenericGenerator(name = "uuid", strategy = "uuid2")
#GeneratedValue(generator = "uuid")
#Column(name = "transit_Item_id",unique = true, nullable = false)
private UUID transitItemId;
#ToString.Exclude
#JsonManagedReference
#JsonIgnore
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "grouping_form_id")
//#OnDelete(action = OnDeleteAction.CASCADE)
private GroupingForm groupingForm;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(referencedColumnName = "dim_Item_ID",name = "item_id")
private Item item;
#Column(name ="item_relationship_id", insertable = false,updatable = false)
private String itemRelationshipId;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "item_relationship_id",referencedColumnName = "dim_item_relationship_id")
private VendorFactoryItem vendorFactoryItem;
#Column(name = "edam_id")
private String edamId;
#Column(name = "model_number")
private String modelNumber;
#Column(name = "description")
private String description;
#Column(name = "packaging_details")
private String packagingDetails;
#Column(name = "packaging_method")
private String packagingMethod;
#Column(name = "is_side_stack")
private String isSideStack;
#Column(name = "quantity")
private Integer quantity;
#Column(name = "dimensions")
private String dimensions;
#Column(name = "product_net_weight")
private String productNetWeight;
#Column(name = "plastic_bag_ind")
private String plasticBagInd;
#Column(name = "insertion_order")
private Integer insertionOrder;
#Column(name = "comments")
private String comments;
#Column(name = "item_unique_id")
private String itemUniqueId;
#Column(name = "itm_pak_qty")
private Integer itemPackQuantity;
}
GroupingForm.java
#Setter
#Getter
#NoArgsConstructor
#AllArgsConstructor
#EqualsAndHashCode
#Entity
#Table(name = "GroupingForm")
public class GroupingForm implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
#Id
#GenericGenerator(name = "uuid", strategy = "uuid2")
#GeneratedValue(generator = "uuid")
#Column(name = "grouping_form_id",unique = true, nullable = false)
private UUID groupingFormId;
#Column(name = "grouping_form_name")
private String groupingFormName;
#Column(name = "vid")
private String vid;
#Column(name = "vendor_name")
private String vendorName;
#Column(name = "hovbu")
private String hovbu;
#Column(name = "fid")
private String fid;
#Column(name = "factory_name")
private String factoryName;
#Column(name = "item_count")
private Integer itemCount;
#CreationTimestamp
#Column(name = "creation_date")
private Timestamp creationDate;
#Column(name = "created_by")
private String createdBy;
#UpdateTimestamp
#Column(name = "modified_date")
private Timestamp modifiedDate;
#Column(name = "modified_by")
private String modifiedBy;
#Column(name = "product_engineer")
private String productEngineer;
#Column(name = "status")
private String status;
#Column(name = "sourcing_type")
private String sourcingType;
#Column(name = "total_comments")
private Integer totalComments;
#Column(name = "factory_name_chinese")
private String factoryNameChinese;
#Column(name = "grouping_form_type")
private String groupingFormType;//to save as Product/transit/Product_transit
#Column(name = "ref_id")
private String refId;
#JsonBackReference
#OneToMany(mappedBy = "groupingForm", cascade = CascadeType.ALL)
private List<ProductItemsMapping> productItems = new ArrayList<>();
#JsonBackReference
#OneToMany(mappedBy = "groupingForm", cascade = CascadeType.ALL)
private List<TransitItemsMapping> transitItems = new ArrayList<>();
#Column(name = "pdf_status")
private String pdfStatus;
public GroupingForm(UUID groupingFormId,String groupingFormName, String vid, String vendorName, String hovbu,
String fid, String factoryName, String status, String sourcingType, Integer totalComments,
Date creationDate, String createdBy, Date modifiedDate, String modifiedBy, String productEngineer,
Integer itemCount, String groupingFormType, String refId, String factoryNameChinese) {
this.groupingFormId = groupingFormId;
this.groupingFormName = groupingFormName;
this.vid = vid;
this.vendorName = vendorName;
this.hovbu = hovbu;
this.fid = fid;
this.factoryName = factoryName;
this.status = status;
this.sourcingType = sourcingType;
this.totalComments = totalComments;
this.creationDate = creationDate!=null?new Timestamp(creationDate.getTime()):null;
this.createdBy = createdBy;
this.modifiedDate = modifiedDate!=null?new Timestamp(modifiedDate.getTime()):null;
this.modifiedBy = modifiedBy;
this.productEngineer = productEngineer;
this.itemCount = itemCount;
this.groupingFormType = groupingFormType;
this.refId = refId;
this.factoryNameChinese = factoryNameChinese;
}
}
Service: methods which already annotated with #Transactional
private void updateTransitItem(GroupingCardsDto groupingCardsDto, GroupingForm groupingForm) {
transitItemRepository.deleteByGroupingFormId(groupingCardsDto.getGroupingFormDto().getGroupingFormId());
groupingFormService.saveTransitItems(groupingCardsDto.getGroupingFormDto(), groupingForm);
}
when I am running eclipse in debug mode then my breakpoint is stuck in delete method. I am using
PostgreSQL 9.6.24 on x86_64-pc-linux-gnu, compiled by Debian clang version 12.0.1, 64-bit
version, and for pool connection Hikari-CP-3.2.0.
And If I let my debug running after long time (~45min) I am getting below error.
marked as broken because of SQLSTATE(08006), ErrorCode(0)\norg.postgresql.util.PSQLException: An I/O error occurred while sending to the backend.
Thanks in advance.
There are two possible reasons for this.
Either your delete statement actually takes a really long time, or it is stuck on a lock.
45 min, is certainly a lot for simple delete and could only be expected when you are working on huge amounts of data, like many millions of rows. Use the explain plan to validate that the expected indexes are used.
I consider locks the more likely reason for the problem. You'll need to check what locks are present and where they are coming from. This wiki page about lock monitoring in PostgreSQL seems to be a good starting point.
I have 4 models:
Blueprint, that describes a single type of Item:
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name="name")
private String name;
#ElementCollection
#CollectionTable(name = "BLUEPRINT_TAG", joinColumns = #JoinColumn(name = "blueprint"))
private List<String> tags;
#OneToMany(mappedBy = "blueprint", cascade = CascadeType.ALL, orphanRemoval = true)
private List<BlueprintProperty> properties;
#OneToMany(mappedBy = "blueprint", cascade = CascadeType.ALL, orphanRemoval = true)
#JsonIgnore
private List<Item> items;
#Column(name = "width")
private Float width;
#Column(name = "height")
private Float height;
#Column(name = "imagePath")
private String imagePath;
#Column(name = "zPosition")
private long zPosition;
BlueprintProperty, that describes what information can be entered for each type of Item.
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#ManyToOne
#JoinColumn(name = "blueprint")
#JsonIgnore
private Blueprint blueprint;
#Column(name = "name")
private String name;
#Enumerated(EnumType.STRING)
private PropertyType type;
#Column(name = "data")
#Convert(converter = JpaJsonConverter.class)
private ObjectNode data;
#OneToMany(mappedBy = "property", cascade = CascadeType.ALL, orphanRemoval = true)
#JsonIgnore
private List<ItemProperty> itemProperties;
Then there's Item:
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#ManyToOne
#JoinColumn(name = "parent")
//#Nullable
private Item parent;
#Column(name = "pos_x")
private Float posX;
#Column(name = "pos_y")
private Float posY;
#Column(name = "transformation")
private String transformation;
#ManyToOne
#JoinColumn(name = "blueprint")
private Blueprint blueprint;
#OneToMany(mappedBy = "parent", cascade = CascadeType.ALL)
#JsonIgnore
private List<Item> children;
#OneToMany(mappedBy = "item", cascade = CascadeType.ALL, orphanRemoval = true)
private List<ItemProperty> properties;
And finally, ItemProperty, that holds foreign keys referencing Item the specific property belongs to, and BlueprintProperty it's describing:
#Id
#ManyToOne
#JoinColumn(name = "item")
#JsonIgnore
private Item item;
#Id
#ManyToOne
#JoinColumn(name = "property")
#JsonIgnore
private BlueprintProperty property;
#Column(name = "value")
private String value;
Now, I'm not exactly happy with this setup, but that's what I have to work with and unless completely necessary I shouldn't change anything. What I'm trying to do is create a Query that takes a number of Item properties and returns all Items which properties match the query.
Using Query by example sounded promising, but I found out that only SingularAttribute properties can currently be used for property matching.. So that killed that approach, and I don't think I can use native query, because a certain Item can have N properties, and you should be able to enter a query that searches by a single property, up to N properties.
Can someone suggest a way to perform the search I need and get a List of Items matching whose properties matched those entered as a result?
This is the first entity:
#Entity
#Table(name = "photographers")
public class Photographer {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#NotNull
#Column(name = "first_name")
private String firstName;
#NotNull
#Size(min = 2, max = 50)
#Column(name = "last_name")
private String lastName;
#Pattern(regexp = "^\\+[0-9]{1,3}/[0-9]{8,10}$")
private String phone;
#NotNull
#OneToOne(optional = false)
#JoinColumn(name = "primary_camera_id", referencedColumnName = "id")
private BasicCamera primaryCamera;
#NotNull
#OneToOne(optional = false)
#JoinColumn(name = "secondary_camera_id", referencedColumnName = "id")
private BasicCamera secondaryCamera;
#OneToMany(mappedBy = "owner")
private Set<Lens> lenses;
#OneToMany(mappedBy = "owner")
private Set<Accessory> accessories;
and this is the other(lenses) :
#Entity
#Table(name = "lenses")
public class Lens {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String make;
#Column(name = "focal_length")
private Integer focalLength;
#Column(name = "max_aperture", precision = 1)
private Double maxAperture;
#Column(name = "compatible_with")
private String compatibleWith;
#ManyToOne
#JoinColumn(name = "owner_id", referencedColumnName = "id")
private Photographer owner;
Firstly i have lenses without owners. Then i want to create a photographer with everything and set its lenses to exiting ones i do this with this code:
for (Lens lens : lensSet) {
lens.setOwner(photographer);
}
photographer.setPrimaryCamera(primaryCamera);
photographer.setSecondaryCamera(secondaryCamera);
photographer.setLenses(lensSet);
and when i save the photographer i want the lenses owner to be set to the created one. I tried cascad.MERGE on the OneToMany realation in the photographer entity but did't work and in the database all lenses owners are still nulls
I figured it out : i need to save the lenses AFTER i save the photographer:
for (Lens lens : lensSet) {
lens.setOwner(photographer);
}
photographer.setPrimaryCamera(primaryCamera);
photographer.setSecondaryCamera(secondaryCamera);
photographer.setLenses(lensSet);
this.photographerRepository.save(photographer);
this.lensRepository.save(lensSet);
I have some big problems with making a proper mapping for delivered diagram. It looks like this:
Now, so far I did this, hopefully its ok (ommited getters/setters). You'll notice that USERS has DOMAIN_ID, ignore it as it is not full diagram.
FunctionalityGroup
#Entity
#Table(name = "FUNCTIONALITY_GROUP")
public class FunctionalityGroup implements Serializable
{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "FUNCTIONALITY_GROUP_ID")
private Long functionalityGroupId;
#Column(name = "FUNCTIONALITY_GROUP_NM")
private String functionalityGroupName;
#Column(name = "FUNCTIONALITY_GROUP_DESC")
private String functionalityGroupDesc;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "funcionalityGroupId")
private List<Functionality> functionalityList;
}
Functionality
#Entity
#Table(name = "FUNCTIONALITY")
public class Functionality implements Serializable
{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "FUNCTIONALITY_ID")
private Long functionalityId;
#Column(name = "FUNCTIONALITY_NM")
private String functionalityGroupName;
#Column(name = "FUNCTIONALITY_DESC")
private String functionalityGroupDesc;
#Column(name = "FUNCTIONALITY_GROUP_ID")
private Long funcionalityGroupId;
#ManyToMany(fetch = FetchType.LAZY)
#JoinTable(name = "ROLE_FUNCTIONALITY",
joinColumns = {#JoinColumn(name = "FUNCTIONALITY_ID")},
inverseJoinColumns = {#JoinColumn(name = "ROLE_ID")})
private List<Role> roleList;
}
Role
#Entity
#Table(name = "ROLE")
public class Role implements Serializable
{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "ROLE_ID")
private Integer roleId;
#Column(name = "ROLE_NM")
private String roleName;
#Column(name = "ROLE_DESC")
private String roleDesc;
#Column(name = "OBJECT_TYPE")
private String objectType;
#ManyToMany(fetch = FetchType.LAZY, mappedBy = "roleList")
private List<Functionality> functionalityListy;
}
Users
#Entity
#Table(name = "USERS")
public class Users implements Serializable
{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "USER_ID")
private Long userId;
#Column(name = "USER_DESC")
private String userDesc;
#Column(name = "FIRST_NM")
private String firstNM;
#Column(name = "LAST_NM")
private String lastNM;
#Column(name = "IS_ENABLED")
private String isEnabled;
}
I have no idea how Role_Member and Role_Member_Entry should be mapped and handled withing object world, could somebody give me some hits? Thanks!
Normally I'd connect Users with Role as Many to Many, but the entity Role_Member_Entry ruins everything.