org.hibernate.AssertionFailure Issue when getting sequence value - java

I am trying to insert multiple records in a table using loop and getting sequence number for that using below method. It is getting sequence number for very first time alone and during next iteration below exception is coming.Please help in resolving this
14:03:51.928 [http-nio-8080-exec-5] ERROR org.hibernate.AssertionFailure - HHH000099: an assertion failure occured (this may indicate a bug in Hibernate, but is more likely due to unsafe use of the session): org.hibernate.AssertionFailure: possible non-threadsafe access to session
14:03:51.938 [http-nio-8080-exec-5] ERROR u.s.m.e.p.o.b.c.ORBudgetController - 2020/08/26_14:03:51.938|1|pa23690|bearer 6d7417d8-6835-485e-956d-c362cb7bce2b|createRecord|possible non-threadsafe access to session
#Override
public int getNextSequenceNumber(String seqName) {
int nextValue = 0;
String strQuery = "SELECT " + seqName + ".NEXTVAL FROM DUAL";
Query q = entityManager.createNativeQuery(strQuery);
BigDecimal bd = (BigDecimal) q.getSingleResult();
nextValue = bd.intValue();
return nextValue;
}

You need to generate the sequence automatically, do it manually is a bad practice and can bring you problems in the future. There are several JPA strategies to automatically generate the sequence, this, for example, is The Sequence Strategy
#Entity
// Define a sequence - might also be in another class:
#SequenceGenerator(name="seq", initialValue=1, allocationSize=100)
public class EntityWithSequenceId {
// Use the sequence that is defined above:
#GeneratedValue(strategy=GenerationType.SEQUENCE, generator="seq")
#Id long id;
}
You can also use The Auto Strategy
#Entity
public class EntityWithAutoId1 {
#Id #GeneratedValue(strategy=GenerationType.AUTO) long id;
}

Related

Hibernate+ postgres batch update does not work

Is there any way to do batch updates ?
i create a simple entity
#Entity
#Getter
#Setter
public class A {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "A_ID_GENERATOR")
#SequenceGenerator(name = "A_ID_GENERATOR", sequenceName = "a_id_seq")
private Long id;
private String name;
}
next step i generated 10000 objects of class A and put them to db
next step i get list of A from db ,set new name and save them again
#PutMapping
#Transactional
public String updateAllTest(){
var list=aRepository.findAll();
for (int i = 0; i <list.size() ; i++) {
list.get(i).setName("AA"+i);
}
return "OK";
}
what did i expect- i expect that hibernate will do batch update
and hibernate did it -hibernate statistics says - it execute 200 batches ( batch size=500)
next i go to db log files and what i see there- there are no batches- only single updates -10 000 rows
it looks like same with batch insert without adding reWriteBatchedInserts=true to JDBC driver
so is there any way to do batch updates in postgres with hibernate or no?
The key thing to understand is that reusing the same server side statement handle for multiple executions is batching. The log is just telling you about every execution, but that doesn't mean it is slow. It's doing exactly what it should do.

Hibernate save returns wrong generated id

I am having trouble using Hibernate with MSSQL Server 2012. No matter what I do when I try to insert a value in a certain table using Hibernate I get generated id=0.
Here is the model.
#Entity
#Table(name = "tbl_ClientInfo")
public class ClientInfo {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column (name = "auto_Client_ID", unique=true, nullable=false)
private int auto_Client_ID;
...
Here is the write.
public boolean addNewClient(Client client) {
// there is a class that wraps SessionFactory as singleton
Session session = getSessionFactory().openSession();
Transaction tx = null;
Integer clientFamId; //client family info id
Integer clientId; // actual client id
try {
// create fam info first with some data - need id for ClientInfo
tx = session.beginTransaction();
ClientFam clientFam = new ClientFam();
clientFamId = (Integer) session.save(clientFam);
clientFamId = (Integer) session.getIdentifier(clientFam); // this returns the right id
session.flush();
ClientInfo clientInfo = new ClientInfo();
clientInfo.setABunchOfFields(withStuff); //multiple methods
session.save(clientInfo);
clientInfoId = (Integer) session.getIdentifier(clientInfo); // this is always 0
session.flush();
tx.commit();
} catch (HibernateException e) {
if (tx!=null) tx.rollback();
e.printStackTrace();
return false;
} finally {
session.close();
}
return true;
}
In the database the PK auto_Client_ID is clustered, set to IDENTITY(1,1). Both ClientInfo and ClientFam records are created in the db, but hibernate returns 0. I also tried catching the value from save, but it's also 0.
I don't want to commit in-between separate insert: the transaction is when all inserts are fine (there are more after this, but I can't get to them because of this id issue yet).
The model for ClientFam is almost the same: the id field is #GeneratedValue(strategy=GenerationType.IDENTITY) as well.
I also tried specifying this for ClientInfo
#GeneratedValue(generator="increment", strategy=GenerationType.IDENTITY)
#GenericGenerator(name = "increment", strategy = "increment")
The first time I ran it it returned the correct value. However, the second time I ran it I got an error:
Cannot insert explicit value for identity column in table 'Report' when IDENTITY_INSERT is set to OFF
And that was the end of trying that. Everywhere I looked the recommendation is to use GenerationType.IDENTITY for auto incremented field in the db. That's supposed to return the right values. What might I be doing wrong?
I also tried getting the id from the ClientInfo object itself (I thought it should get written into it) after the right, but it's was also 0. Makes me think something is wrong with my ClientInfo model and/or annotations in it.
I found the problem with my situation - has nothing to do with Hibernate. There is a instead of insert trigger that wasn't returning id and hence messing up what save() returns.
This is just an educated guess, but you might want to remove the "unique=true" clause from the #Column definition. Hibernate may be handling the column as a unique constraint as opposed to a primary key.

Generate non-conflicting non-primary-key unique "composite ids" in Hibernate

I'm not sure if my question title is correct, if not, please correct it.
Anyway, long story short, I have sellers, each seller belongs to a company, each seller has an ID as a primary key which is auto-incrementing and a seller-number which is unique per company.
id seller-number company-id
0 0 1
1 1 1
2 2 1
3 0 2
4 1 2
4 2 2
Here's my Seller entity:
#Entity
#Configurable
#Table(name="Seller", uniqueConstraints = {#UniqueConstraint(columnNames= {"company", "sellerNumber"})})
public class Seller implements Serializable {
#PersistenceContext
transient EntityManager entityManager;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private Long id;
#Version
#Column(name = "version")
private Integer version;
#ManyToOne
private Company company;
private Long sellerNumber;
...
Now when creating a seller, I do the following:
#Transactional
private void createSeller(SellerRequest request, SellerResponse response, Session session) {
Seller seller = new Seller();
// generate seller number
TypedQuery<Long> query = Seller.entityManager().createQuery("SELECT max(o.sellerNumber) + 1 FROM Seller AS o WHERE o.company=:company", Long.class);
query.setParameter("company", session.getCompany());
Long sellerNumber = query.getSingleResult();
seller.setSellerNumber(sellerNumber == null ? 1 : sellerNumber);
...
seller.setCompany(session.getCompany());
// persist
seller.persist();
...
The seller numbers I'm getting back is fine, until I start doing a lot of concurrent creates. If two creates happen at the exact same moment, I get a org.hibernate.exception.ConstraintViolationException
The requirements are that I only use an ID as a primary key, no composite primary keys. So taking these constraints into account, how should I be creating these entities so that they have unique seller numbers inside their companies and avoid ConstraintViolationExceptions ?
Is using max(o.sellerNumber) + 1 the right way to go or is there a better way to do this?
The hackish way to accomplish this was to simply catch the ConstraintViolationException and recursively retry the create, increment a retry counter in the request so that it's possible to bail if the number of recursive retries becomes too much.
try {
createSeller(...);
} catch(org.springframework.orm.jpa.JpaSystemException e){
if (e.contains(org.hibernate.exception.ConstraintViolationException.class)){
return thisMethodThatCallsCreateSeller(...);
} else {
throw e;
}
}
On small loads, there's almost no contention, when throwing heavy load at it, there's a little bit of a slowdown as contention causes multiple calls to try and create the seller with multiple ConstraintViolations being caught. Gets the job done though.

Performance OpenJPA query (3000+ records) is slow

I'm using Websphere Application Server 7 with buildin OpenJPA 1.2.3 and an Oracle database. I have the following entity:
#NamedNativeQuery(name=Contract.GIVE_ALL_CONTRACTS,
query="SELECT number, name \n" +
"FROM contracts \n" +
"WHERE startdate <= ?1 \n" +
"AND enddate > ?1",
resultSetMapping = Contract.GIVE_ALL_CONTRACTS_MAPPING)
#SqlResultSetMapping(name = Contract.GIVE_ALL_CONTRACTS_MAPPING,
entities = { #EntityResult(entityClass = Contract.class, fields = {
#FieldResult(name = "number", column = "number"),
#FieldResult(name = "name", column = "name")
})
})
#Entity
public class Contract {
public static final String GIVE_ALL_CONTRACTS = "Contract.giveAllContracts";
public static final String GIVE_ALL_CONTRACTS_MAPPING = "Contract.giveAllContractsMapping";
#Id
private Integer number;
private String name;
public Integer getNumber() {
return number;
}
public String getName() {
return name;
}
}
And the following code to retrieve the contracts:
Query query = entityManager.createNamedQuery(Contract.GIVE_ALL_CONTRACTS);
query.setParameter(1, referenceDate);
List contracts = query.getResultList();
entityManager.clear();
return contracts;
The retrieved contracts are passed to a webservice.
Executing this query in Oracle developer takes around 0,35 seconds for 3608 records.
The call to query.getResultList() takes around 4 seconds.
With a logger in the constuctor of the entity, it logs that there are about 10-20 entities created with the same timestamp. Then 0,015 seconds it does something else. I guess OpenJPA stuff.
Is there a way to speed up OpenJPA? Or is the only solution caching?
Object creation may have its fair share in the performance hit. While running your code in the server, you're not only querying the database but also you allocate memory and create a new Contract object for each row. An expanding heap or garbage collection cycle may count for idle periods that you observed.
I'd suggest you skim through OpenJPA documentation on how to process large results sets.
I suggest you downloading VisualVM and set up a profiling for the packages involved. VisualVM can show the time spent in different methods that will sum up to 0.35sec in your case theoretically. You will be able to analyze the distribution of the total time between your code, OpenJPA and the network IO. This will help you to identify the bottleneck.

How to validate negative values with hibernate annotations?

I have a table that contains the stock. It's legacy database and the stock is kept in columns. The database has a constraint on the columns stating that they can't be negative values. But I only get the constrain violation after the Transaction is committed.
15:21:31,154 WARN JDBCExceptionReporter:77 - SQL Error: 2290, SQLState: 23000
15:21:31,154 ERROR JDBCExceptionReporter:78 - ORA-02290: check constraint (ERPDSS13.STKMAST_CON_QTY13) violated
ORA-06512: at "ERPDSS13.INLTRAN_UPD_STKMAST", line 25
ORA-04088: error during execution of trigger 'ERPDSS13.INLTRAN_UPD_STKMAST'
Is there a way with annotations you can specify that a column can't be negative. Below is the column mapping?
#Column(name = "STKSOHQTY01", precision = 12)
public BigDecimal getStksohqty01() {
return this.stksohqty01;
}
#Check(constraints = "STKSOHQTY01 >= 0")
public class Coupon implements Serializable {
}
It should work
As of version 3.5 Hibernate supports standard bean validation (JSR303). You can and should use those to validate your entities as the API is fast, well-integrated, and more importantly, standardized:
#Min(value = 0)
#Column(name = "STKSOHQTY01", precision = 12)
public BigDecimal getStksohqty01() {
return this.stksohqty01;
}
Try with #Check
#Check(constraints = "STKSOHQTY01t >= 0")
public class YourEntity implements Serializable {...}

Categories

Resources