This question has been asked here before but none of the solutions are working for me.
I am getting following error due to composite key in my SQL Server 2008 table.
java.lang.ExceptionInInitializerError
at HB.Main.<clinit>(Main.java:30)
Caused by: java.lang.IllegalArgumentException: expecting IdClass mapping
at org.hibernate.metamodel.internal.AttributeFactory$3.resolveMember(AttributeFactory.java:977)
at org.hibernate.metamodel.internal.AttributeFactory$5.resolveMember(AttributeFactory.java:1035)
at org.hibernate.metamodel.internal.AttributeFactory.determineAttributeMetadata(AttributeFactory.java:450)
at org.hibernate.metamodel.internal.AttributeFactory.buildIdAttribute(AttributeFactory.java:139)
at org.hibernate.metamodel.internal.MetadataContext.buildIdClassAttributes(MetadataContext.java:388)
at org.hibernate.metamodel.internal.MetadataContext.applyIdMetadata(MetadataContext.java:318)
at org.hibernate.metamodel.internal.MetadataContext.wrapUp(MetadataContext.java:221)
at org.hibernate.metamodel.internal.MetamodelImpl.initialize(MetamodelImpl.java:274)
at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:305)
at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:462)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:708)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:724)
at HB.Main.<clinit>(Main.java:26)
Exception in thread "main"
my table looks like this
The classes and mapping is as follows:
Entity Class
package HB;
import java.util.Objects;
public class EmMonthlyPollTablesEntity
{
private int monthlyPollId;
private int tableId;
public int getMonthlyPollId()
{
return monthlyPollId;
}
public void setMonthlyPollId(int monthlyPollId)
{
this.monthlyPollId = monthlyPollId;
}
public int getTableId()
{
return tableId;
}
public void setTableId(int tableId)
{
this.tableId = tableId;
}
#Override
public boolean equals(Object o)
{
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
EmMonthlyPollTablesEntity that = (EmMonthlyPollTablesEntity) o;
return monthlyPollId == that.monthlyPollId && tableId == that.tableId;
}
#Override
public int hashCode()
{
return Objects.hash(monthlyPollId, tableId);
}
}
ID Class
package HB;
import java.io.Serializable;
import java.util.Objects;
public class EmMonthlyPollTablesEntityPK implements Serializable
{
private int monthlyPollId;
private int tableId;
public EmMonthlyPollTablesEntityPK()
{
}
public EmMonthlyPollTablesEntityPK(int monthlyPollId, int tableId)
{
this.monthlyPollId = monthlyPollId;
this.tableId = tableId;
}
public int getMonthlyPollId()
{
return monthlyPollId;
}
public void setMonthlyPollId(int monthlyPollId)
{
this.monthlyPollId = monthlyPollId;
}
public int getTableId()
{
return tableId;
}
public void setTableId(int tableId)
{
this.tableId = tableId;
}
#Override
public boolean equals(Object o)
{
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
EmMonthlyPollTablesEntityPK that = (EmMonthlyPollTablesEntityPK) o;
return monthlyPollId == that.monthlyPollId && tableId == that.tableId;
}
#Override
public int hashCode()
{
return Objects.hash(monthlyPollId, tableId);
}
}
Main Class
package HB;
import org.hibernate.HibernateException;
import org.hibernate.Metamodel;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.query.Query;
import javax.persistence.metamodel.EntityType;
public class Main
{
private static final SessionFactory ourSessionFactory;
static
{
try
{
Configuration configuration = new Configuration();
configuration.setProperty("hibernate.connection.username", "sa");
configuration.setProperty("hibernate.connection.password", "");
configuration.configure();
ourSessionFactory = configuration.buildSessionFactory();
}
catch (Throwable ex)
{
throw new ExceptionInInitializerError(ex);
}
}
public static Session getSession() throws HibernateException
{
return ourSessionFactory.openSession();
}
public static void main(final String[] args) throws Exception
{
final Session session = getSession();
try
{
System.out.println("querying all the managed entities...");
final Metamodel metamodel = session.getSessionFactory().getMetamodel();
for (EntityType<?> entityType : metamodel.getEntities())
{
try
{
final String entityName = entityType.getName();
final Query query = session.createQuery("from " + entityName);
System.out.println("executing: " + query.getQueryString());
for (Object o : query.list())
{
try
{
System.out.println(" " + o);
}
catch (Exception ex)
{
ex.printStackTrace();
;
}
}
}
catch (Exception ex)
{
ex.printStackTrace();
;
}
}
}
finally
{
session.close();
}
}
}
Mapping
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="HB.EmMonthlyPollTablesEntity" table="EM_MONTHLY_POLL_TABLES" schema="dbo" catalog="HB2">
<composite-id mapped="true" class="HB.EmMonthlyPollTablesEntityPK">
<key-property name="monthlyPollId">
<column name="MONTHLY_POLL_ID" sql-type="int"/>
</key-property>
<key-property name="tableId">
<column name="TABLE_ID" sql-type="int"/>
</key-property>
</composite-id>
</class>
</hibernate-mapping>
Entire Intellij Idea Project and table script can be downloaded from here
There is a bug in Hibernate composite id's defined via hbm.xml cause java.lang.IllegalArgumentException in JPA deployment
Root cause
In JPA the composite id must be embeddable. Because the EmMonthlyPollTablesEntityPK class is not embeddable and that is not a component the JPA environment will never support that.
Solution 1: Workaround
Disable metamodel population in hibernate.cfg.xml
<hibernate-configuration>
<session-factory>
<property name="hibernate.ejb.metamodel.population">disabled</property>
<mapping class="..."/>
<!-- ... -->
</session-factory>
</hibernate-configuration>
Solution 2: Drop HBM Mappings and use annotations
As I know HBM mappings are deprecated and will be removed in a future version of Hibernate.
In this case you can choose between using Composite Id, IdClass and EmbeddedId approaches. The following example uses EmbeddedId
Entity class
#Entity
#Table(name = "EM_MONTHLY_POLL_TABLES")
public class EmMonthlyPollTablesEntity implements Serializable {
#EmbeddedId
private EmMonthlyPollTablesEntityPK id;
#Column(name = "NAME")
private String name;
public EmMonthlyPollTablesEntityPK getId() {
return id;
}
public void setId(EmMonthlyPollTablesEntityPK id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof EmMonthlyPollTablesEntity)) return false;
EmMonthlyPollTablesEntity that = (EmMonthlyPollTablesEntity) o;
return id.equals(that.id) &&
Objects.equals(name, that.name);
}
#Override
public int hashCode() {
return Objects.hash(id, name);
}
}
PK class
#Embeddable
public class EmMonthlyPollTablesEntityPK implements Serializable {
#Column(name = "MONTHLY_POLL_ID", nullable = false)
private int monthlyPollId;
#Column(name = "TABLE_ID", nullable = false)
private int tableId;
public EmMonthlyPollTablesEntityPK() {
}
public EmMonthlyPollTablesEntityPK(int monthlyPollId, int tableId) {
this.monthlyPollId = monthlyPollId;
this.tableId = tableId;
}
public int getMonthlyPollId() {
return monthlyPollId;
}
public void setMonthlyPollId(int monthlyPollId) {
this.monthlyPollId = monthlyPollId;
}
public int getTableId() {
return tableId;
}
public void setTableId(int tableId) {
this.tableId = tableId;
}
#Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
EmMonthlyPollTablesEntityPK that = (EmMonthlyPollTablesEntityPK) o;
return monthlyPollId == that.monthlyPollId && tableId == that.tableId;
}
#Override
public int hashCode() {
return Objects.hash(monthlyPollId, tableId);
}
}
Delegating PK's getters and setters are available of course.
In this case you don't have to disable metamodel population and you can drop HBM mapping resource from hibernate.cfg.xml
Although I know migrating a huge legacy codebase to JPA annotations and XML mappings is very exhausting I'm sure that is the way to go.
Related
Hibernate 5.6 with Spring 5.3 here.
When creating predicates to fetch data from a table with this code:
CriteriaBuilder cb = this.getSession().getCriteriaBuilder();
CriteriaQuery cq = cb.createQuery(aliasToBeanClass);
Root root = cq.from(aliasToBeanClass); // aliasToBeanClass is set to UmsUserRoleVOImpl
predicates.add(cb.equal(root.get(key), value)); // key is set to "userName" - this line is causing the exception
I get this error:
java.lang.IllegalArgumentException: Unable to locate Attribute with
the the given name [userName] on this ManagedType
[com.myapp.ums.business.impl.UmsUserRoleVOImpl]
But the attribute userName is included in my VO, as well as a public setter and it's mapped in my .hbm.xml file:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.myapp.ums.business.impl.UmsUserRoleVOImpl" table="ums_t_user_role"
proxy="com.myapp.ums.common.business.UmsUserRoleVO">
<composite-id>
<key-property name="userName" type="java.lang.String" column="fk_user_id"/>
<key-property name="roleName" type="java.lang.String" column="fk_role_id"/>
</composite-id>
</class>
</hibernate-mapping>
This is my VO:
public class UmsUserRoleVOImpl extends AbstractBasePropertiesImpl implements UmsUserRoleVO {
private static final long serialVersionUID = 2393634151578825216L;
private String roleName;
private String userName;
private List<PmPropertyVO> properties;
public UmsUserRoleVOImpl() {
}
#Get(AbstractBaseProperties.ROWGUID)
#Override
public Long getRowguid() {
return super.getRowguid();
}
#Set(AbstractBaseProperties.ROWGUID)
#Override
public void setRowguid(final Long rowguid) {
super.setRowguid(rowguid);
}
#Get(UmsUserRoleVO.ROLE_NAME)
public String getRoleName() {
return roleName;
}
#Set(UmsUserRoleVO.ROLE_NAME)
public void setRoleName(String roleName) {
this.roleName = roleName;
}
#GetCollection(value = UmsUserRoleVO.PROPERTIES, defaultObject = "com.myapp.pm.business.impl.PmPropertyVOImpl")
public List<PmPropertyVO> getProperties() {
return properties;
}
#SetCollection(value = UmsUserRoleVO.PROPERTIES, defaultObject = "com.myapp.pm.business.impl.PmPropertyVOImpl")
public void setProperties(List<PmPropertyVO> properties) {
this.properties = properties;
}
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof UmsUserRoleVOImpl)) {
return false;
}
UmsUserRoleVOImpl user = (UmsUserRoleVOImpl) o;
if (!(roleName.equals(user.getRoleName()))) {
return false;
}
return userName.equals(user.getUserName());
}
public int hashCode() {
int result = 17;
result = 29 * result + (roleName != null ? roleName.hashCode() : 0);
result = 29 * result + (userName != null ? userName.hashCode() : 0);
return result;
}
public String toString() {
return roleName + " " + userName;
}
#Get(UmsUserRoleVO.USER_NAME)
public String getUserName() {
return this.userName;
}
#Set(UmsUserRoleVO.USER_NAME)
public void setUserName(String userName) {
this.userName = userName;
}
There seems to be something wrong with the mapping, because Hibernate does not find any attribute of the UmsUserRoleVOImpl:
Any idea what could be causing this error?
So,
I am trying to do a many to many implementation through Spring JPA.
I tried to do an embedded key implementation.
But I am getting this error
{
"message": "Internal server error",
"details": "Could not set field value [26] value by reflection : [class com.domain.configuredview.model.RelationshipViewPersonPK.personId] setter of com.domain.configuredview.model.RelationshipViewPersonPK.personId; nested exception is org.hibernate.PropertyAccessException: Could not set field value [26] value by reflection : [class com.domain.configuredview.model.RelationshipViewPersonPK.personId] setter of com.domain.configuredview.model.RelationshipViewPersonPK.personId"
}
I tried searching through all the answers but couldn't fix this.
My classes are
import com.domain.person.model.Person;
import java.io.Serializable;
import javax.persistence.*;
import lombok.Data;
import lombok.NoArgsConstructor;
#Data
#NoArgsConstructor
#Entity
#Table(name = "relationship_view_person")
public class RelationshipViewPerson implements Serializable {
#EmbeddedId
private RelationshipViewPersonPK entryId;
#ManyToOne(fetch = FetchType.LAZY)
#MapsId("viewId")
#JoinColumn(name = "view_id", nullable = false)
private ConfiguredView view;
#ManyToOne(fetch = FetchType.LAZY)
#MapsId("personId")
#JoinColumn(name = "person_id", nullable = false)
private Person person;
public RelationshipViewPerson(ConfiguredView view, Person person) {
this.view = view;
this.person = person;
this.entryId = new RelationshipViewPersonPK(view.getId(), person.getWsGlobalId());
}
public void setEntryId(Long viewId, String personId) {
this.entryId.setViewId(viewId);
this.entryId.setPersonId(personId);
}
public void setView(ConfiguredView view) {
this.view = view;
}
public void setPerson(Person person) {
this.person = person;
}
public Person getPerson() {
return this.person;
}
public ConfiguredView getView() {
return this.view;
}
}
The relationship key is
import java.io.Serializable;
import javax.persistence.*;
import lombok.NoArgsConstructor;
#Embeddable
#NoArgsConstructor
public class RelationshipViewPersonPK implements Serializable {
#Column(name = "view_id")
private Long viewId;
#Column(name = "person_id")
private String personId;
public RelationshipViewPersonPK(Long viewId, String personId) {
this.viewId = viewId;
this.personId = personId;
}
// setters & getters
public void setViewId(Long viewId) {
this.viewId = viewId;
}
public void setPersonId(String personId) {
this.personId = personId;
}
public String getPersonId() {
return this.personId;
}
public Long getViewId() {
return this.viewId;
}
// Override equals and hashCode
#Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
RelationshipViewPersonPK that = (RelationshipViewPersonPK) o;
return this.viewId.equals(that.viewId) && this.personId.equals(that.personId);
}
#Override
public int hashCode() {
return this.viewId.hashCode() + this.personId.hashCode();
}
}
The ConfiguredView model has PK as id and Person model has field as wsGlobalId . The key on the Person table is not a PK.
I have the setters, getters, constructors, and pretty much everyting in place. Not sure whats happening with Hibernate here, it cannot find the getter or something? Not sure whats happening with this.
You should have a setter like below:
public void setEntryId(RelationshipViewPersonPK entryId) {
this.entryId.setViewId(entryId.getViewId());
this.entryId.setPersonId(entryId.getPersonId());
}
instead of (or in addition to) this:
public void setEntryId(Long viewId, String personId) {
this.entryId.setViewId(viewId);
this.entryId.setPersonId(personId);
}
I have multi module project (*.war).
It's an entry point in app.
#SpringBootConfiguration
#SpringBootApplication
#EnableJpaRepositories(basePackages = {"....dao.repository"})
#EntityScan(basePackages = {"....dao.model"})
#ComponentScan(basePackages = {"..."})
public class ApsTtsApplication
extends SpringBootServletInitializer
implements WebApplicationInitializer {
private static final Logger LOGGER = LoggerFactory.getLogger( ApsTtsApplication.class );
public static void main(String[] args) {
LOGGER.info("Start an application...");
SpringApplication.run(ApsTtsApplication.class, args);
}
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
LOGGER.info("There is building the web application!");
return builder.sources(ApsTtsApplication.class);
}
}
model
IdMainForEntities
#MappedSuperclass
public abstract class IdMainForEntities {
#Id
#GenericGenerator(name="system-uuid", strategy = "uuid")
#GeneratedValue(generator="system-uuid")
#Column(name = "id", nullable = false)
private String ID;
public IdMainForEntities() {
}
public String getID() {
return ID;
}
public void setID(String ID) {
this.ID = ID;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
IdMainForEntities that = (IdMainForEntities) o;
return Objects.equals(ID, that.ID);
}
#Override
public int hashCode() {
return Objects.hash(ID);
}
#Override
public String toString() {
return "IdMainEntity{" +
"ID='" + ID + '\'' +
'}';
}
}
MessageLog
#Entity
#Table(name = "MESSAGESLOG")
public class MessageLog extends IdMainForEntities {
...
#Column(name = "MSG_OWNER_ID")
#Size(message = "MSG_OWNER_ID{MessagesLog.size}", max = 32)
private String msgOwnerId;
public MessageLog() {
}
public String getMsgOwnerId() {
return msgOwnerId;
}
public void setMsgOwnerId(String msgOwnerId) {
this.msgOwnerId = msgOwnerId;
}
....
}
MessagesLogReadRepository
public interface MessagesLogReadRepository extends CrudRepository <MessageLog, String> {
Optional <MessageLog> findByMsgOwnerId(String msgOwnerId);
MessageLog findMessageLogByMsgOwnerId(String msgOwnerId);
Optional <MessageLog> findByDocument(String documentId);
}
Only standard methods can be called from this repository : findById (), etc.
But named queries is not found.
18-03-2020 08:49:39.531 DEBUG 8660 o.s.d.j.r.query.JpaQueryFactory
: Looking up query for method findByMsgOwnerId 18-03-2020
08:49:39.547 DEBUG 8660 o.s.d.jpa.repository.query.NamedQuery :
Looking up named query MessageLog.findByMsgOwnerId 18-03-2020
08:49:39.547 DEBUG 8660 o.h.e.t.internal.TransactionImpl :
On TransactionImpl creation,
JpaCompliance#isJpaTransactionComplianceEnabled == false 18-03-2020
08:49:39.547 DEBUG 8660 o.s.d.jpa.repository.query.NamedQuery :
Did not find named query MessageLog.findByMsgOwnerId
#Override
public MessageLogDto getByMsgOwnerId(String msgOwnerId) {
if(msgOwnerId == null) throw new MessagesLogException(paramNotNull);
/*It's null*/
Optional<MessageLog> byMsgOwnerId = this.messagesLogReadRepository.findByMsgOwnerId("8a00844170d829040170d82c670b00");
MessageLog messageLog = byMsgOwnerId.orElse(new MessageLog());
/*It's OK*/
Optional<MessageLog> byId = this.messagesLogReadRepository.findById("8a00844170d829040170d82c670b0003");
return transformEntityToDto(messageLog);
}
Update
public interface MessagesLogReadRepository extends JpaRepository<MessageLog, String> {
#Query(value = "SELECT * from messageslog where MSG_OWNER_ID = ?1", nativeQuery = true )
Optional <MessageLog> findRowByMsgOwnerId(String msgOwnerId);
...
...extends JpaRepository
But, It doesn't solve the problem.
I don't have any mistakes. I only get null, but the requested row is in the table, that 's for sure.
does anyone have any ideas about this?
Why ?
Solution
The field we were working with had a data type CHAR(32 byte). We changed this type to VARCHAR(32 byte) into a table database of Oracle.
Now, Spring can build named query fine.
The project on older versions of Spring worked like this ...(CHAR(32 byte))
I don't understand why so.
I am trying to find the correct way to convert the below (Hibernate) XML to JPA annotations:
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<class name="TesTEntry" table="RAW_SCORE">
<composite-id mapped="false" unsaved-value="undefined">
<key-property column="SSN" name="ssn" type="string"/>
<key-property column="SUB_TEST_CD" name="subTestCd" type="string"/>
</composite-id>
<property column="TEST_QY" generated="never" lazy="false"
name="testQy" type="java.lang.Short"/>
<property column="SYS_REC" generated="never" lazy="false"
name="sysRec" type="java.util.Date"/>
<property column="SYS_ID" generated="never" lazy="false"
name="sysId" type="java.lang.String"/>
</class>
Since I have two <key-property> I am not sure if I use #Id, or #EmbeddedId
Since I have two I am not sure if I use #Id, or #EmbeddedId
You mean probably IdClass. And it doesn't matter which one you use.
Let us say, you want to use #IdClass:
Define a class for your ID.
Implement equals and hashCode methods
Implement public default constructor
Implement the Serializable interface
Here is an example implementation (equals & hashCode are generated from IDE):
public class TestEntityPK implements Serializable {
private static final long serialVersionUID = -3424067518791080014L;
private String ssn;
private String subTestCd;
public TestEntityPK() { // }
public TestEntityPK(String ssn, String subTestCd) {
this.ssn = ssn;
this.subTestCd;
}
public String getSsn() {
return ssn;
}
public String getSubTestCd() {
return subTestCd;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((ssn == null) ? 0 : ssn.hashCode());
result = prime * result
+ ((subTestCd == null) ? 0 : subTestCd.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
TestEntityPK other = (TestEntityPK) obj;
if (ssn == null) {
if (other.ssn != null)
return false;
} else if (!ssn.equals(other.ssn))
return false;
if (subTestCd == null) {
if (other.subTestCd != null)
return false;
} else if (!subTestCd.equals(other.subTestCd))
return false;
return true;
}
}
And use it in the entity as follows:
#Entity
#Table(name="RAW_SCORE")
#IdClass(TestEntityPK.class)
public class TestEntity {
#Id private String ssn;
#Id
#Column(name="SUB_TEST_CD")
private String subTestCd;
#Column(name="TEST_QY")
private short testQy;
#Column(name="SYS_REC")
#Temporal(TemporalType.DATE)
private Date sysRec;
#Column(name="SYS_ID")
private String sysId;
// getters and setters
}
I have the following Entity
#Entity
#Table(name = "APP_ITEM")
public class AppItem implements Serializable {
private static final long serialVersionUID = 1L;
#EmbeddedId
private AppItemPK AppItemPK;
public AppItemPK getAppItemPK() {
return appItemPK;
}
public void setAppItemPK(
AppItemPK appItemPK) {
this.appItemPK = appItemPK;
}
}
#Embeddable
public class AppItemPK implements Serializable {
private static final long serialVersionUID = 1L;
#Column(name = "app_id")
private Long appId;
#Column(name = "item_id")
private Long itemId;
public Long getAppId() {
return appId;
}
public void setAppId(Long appId) {
this.appId = appId;
}
public Long getItemId() {
return itemId;
}
public void setItemId(Long itemId) {
this.itemId = itemId;
}
public boolean equals(Object obj) {
if (obj instanceof AppItemPK) {
AppItemPK appItemPK = (AppItemPK) obj;
if (appItemPK.getItemId().equals(this.itemId)
&& appItemPK.getAppId().equals(
this.appId)) {
return true;
}
}
return false;
}
public int hashCode() {
return this.itemId.hashCode() + this.applicationId.hashCode();
}
}
Using below code to insert record into app_item table
#Transactional(readOnly = false)
public boolean saveItemSelection(PageHeaderViewData pageHeaderViewData, Map<Long, Boolean> selectedItems,String savedItems){
long millisSaveStart = Calendar.getInstance().getTimeInMillis();
log.debug("Inside saveItemSelection appId:"+pageHeaderData.getAppId());
boolean saveStatus = false;
List<AppItem> appItemInsList = new ArrayList<SavedApplicationItem>();
if (pageHeaderData.getAppId() != null) {
for (Entry<Long, Boolean> idEntry : selectedItems.entrySet() ) {
if (idEntry!= null){
if (idEntry.getValue() && !savedItems.contains(idEntry.getKey().toString())){
//log.debug("Inside saveItemSelection SAVED itemId:"+idEntry.getKey()+" , Value:"+idEntry.getValue());
AppItem appItem = new AppItem();
AppItemPK appItemPK = new AppItemPK();
appItemPK.setAppId(pageHeaderData.getAppId());
appItemPK.setItemId(idEntry.getKey());
appItem.setAppItemPK(appItemPK);
appItem.setUpdateInd(ToggleEnum.Y);
appItemInsList.add(appItem);
//appItemRepository.saveAndFlush(appItem);
}
}
}
}
if (appItemInsList.size() != 0){
long millisJPASaveStart = Calendar.getInstance().getTimeInMillis();
appItemRepository.save(appItemInsList);
long millisJPASaveEnd = Calendar.getInstance().getTimeInMillis();
log.debug("JPA save time:"+(millisJPASaveEnd-millisJPASaveStart));
}
saveStatus = true;
long millisSaveEnd = Calendar.getInstance().getTimeInMillis();
log.debug("Total save time:"+(millisSaveEnd-millisSaveStart));
}
return saveStatus;
}//end of saveItemSelection
For inserting 5000 records it is taking 13826 milliseconds.
Can someone please let me know, how to improve the performance in above JPA code. We are using hibernate for jpa implementation.
To improve the performance your inserts, you should implement batch insert using custom code. The method below will make sure that batches are flushed to the database. Tweak the batch size based on your performance tests. Generally 50 is a good number to start.
#Transactional
public void bulkPersist(List<Entity> entities) {
int i = 0;
for (Entity entity : entities) {
em.persist(entity);
i++;
if (i % batchSize == 0) {
flush();
clear();
}
}
}
Above change will create multiple insert statements. You can further optimize the insert query by setting up the hibernate configuration.
<prop key="hibernate.order_inserts">true</prop>
<prop key="hibernate.order_updates">true</prop>
Tip: Enable Debug log to see 1 insert query is being generated per batch.