I am writing java code to do database operations using JPA. i.e. getTransaction, getResultList, setFirstResult, setMaxResults, begin, commit, flush, clear, ...
My question is, even though I can wrap my codes in try catch blocks, I still need ways to generate exception to test if my code works.
How would you generate database errors to test your exception handling? Some SQL commands to run on the DB outside java at the same time when the program runs? My target DB is SQL server 2008 R2.
Examples on common errors like locking and "StaleObjectStateException:Row was updated or deleted by another..." would be appreciated.
Thank you!
For the StaleObjectStateSession you can write a JUnit test case like
e1 = session1.load(key);
e2 = session2.load(key);
e2.modifyAnything();
e2.update();
e2.commit();
e1.modifyAnything();
e1.update();
Then you get your exception. By the way, the StaleObjectStateSession is a Hibernate exception, NOT a database exception.
For testing a real database exception you can violate a database constraint, for example write a JUnit case where you insert a row with a primary key which already exists or which has a null value in a column which is declared as NOT NULL on the database.
If you want to test only once and you want to avoid the effort for writing a JUnit test case, then you can do it with the eclipse debugging and SQL manipulations:
You set a breakpoint between the load and the commit of the record in your code. When the breakpoint is reached then in SQL you manually remove this record with DELETE FROM table WHERE primary_key =... and commit this modification before you continue execution. (Alternatively you can UPDATE the row, but then do not forget to update the version column too.) Then in Eclipse you continue the execution of the program.
Another idea is to temporarily make a nullable column to not null with ALTER TABLE table MODIFY(column ... NOT NULL). After your test you have to undo this modification. Sure, such a test only should be done on a dedicated test database and not on the productive system.
I'd mock the interface-based DAO to create whatever exceptions I wanted.
You are writing interface-based DAOs, aren't you?
I'm not sure that it's practical to try and unit test for each and every exceptional situation that might come up.
Related
I'm just looking for high-level advice when dealing with an issue with a multi-threaded application.
Here's how it works:
The application takes in Alerts, which are then processed in different threads to make Reports. On occasion, two Alerts include the same Report, however that is not desired.
It is a Spring application, written in Java, using a MySQL DB.
I altered my code to run a SELECT SQL query before saving a Report which checks to see if a similar report is already there. If it exists, the Report is not generated. However, if two Alerts come in at the same time, the SELECT command is run for Report #2, before Report #1 is saved.
I thought about putting in a sleep() with a random wait time of 1-10 seconds, but it still would cause an issue when the two threads had the same random sleep time assigned.
I'm pretty new to multi-threading, so does anyone have any ideas? Or resources to point me in the right direction.
Thanks a lot!!
Assuming you have code that looks something like this:
Report report = getReport(...); // calls the DB to get a record to see if it already exists
if (report == null) {
insertReport(...); // add a record to DB which might have already been added by another thread
}
then to avoid collisions across threads (or JVMs) combine the SELECT and INSERT. For example:
insertReportIfNotAlreadyExists(...);
which uses a query structured as:
INSERT INTO REPORTS (...) VALUES (...)
WHERE NOT EXISTS (...)
with the NOT EXISTS clause SELECTing for the record to make sure it doesn't already exist.
In my code I am saving data to a Microsoft SQL database version 10.50.4042.0
I am using hibernate-validator version 4.2.0.CR1 and hibernate-commons-annotations version 3.2.0.Final
I am working over several projects connected by Maven built on Spring framework.In my test project(using junit 4.8.2) I am trying to save the data into the database by selecting several xml files and converting them into database rows(one row at a time). Inside my project that is dealing with SQL transactions I am sending the data to the database using this annotation
#Transactional(readOnly = false, propagation = Propagation.REQUIRED, isolation = Isolation.READ_COMMITTED)
I think the problem occurs inside the Transactional process of hibernate.But there are no asynchronized calls and XML structure is totally valid. I tried different approaches but the problem seems to occur very randomly without any specific pattern and it fails to save only 1 random data row.
Error message I get is:
2016-06-09 12:41:01,578: ERROR [http-8080-Processor3] Could not synchronize database state with session
org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1
at org.hibernate.jdbc.Expectations$BasicExpectation.checkBatched(Expectations.java:85)
at org.hibernate.jdbc.Expectations$BasicExpectation.verifyOutcome(Expectations.java:70)
at org.hibernate.jdbc.NonBatchingBatcher.addToBatch(NonBatchingBatcher.java:47)
at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:2574)
at org.hibernate.persister.entity.AbstractEntityPersister.updateOrInsert(AbstractEntityPersister.java:2478)
at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:2805)
at org.hibernate.action.EntityUpdateAction.execute(EntityUpdateAction.java:114)
at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:268)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:260)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:180)
at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:51)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1206)
at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:375)
at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:137)
at org.springframework.orm.hibernate3.HibernateTransactionManager.doCommit(HibernateTransactionManager.java:656)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:754)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:723)
at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:393)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:120)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)
at com.sun.proxy.$Proxy48.save(Unknown Source)
There are no other SQL calls that are updating the row at the same time.
Can you help if you came across the same problem in hibernate.Or any other suggestions might help.
Thank you
Actually this problem means that
It was unable to found record with your given id.
To avoid this I always read record with same id if I found record back then I call update otherwise throw "exception record not found".
You have deleted a object and then tried to update it. On that case, you need to clear the session session.clear();
Actual Answer:
In the Hibernate mapping file for the id property, if you use any generator class, for that property you should not set the value explicitly by using a setter method.
If you set the value of the Id property explicitly, it will lead the error above. Check this to avoid this error.
Investigation Procedure:
However, to get a better handle as to what causes the problem, try the following:
In your hibernate configuration, set hibernate.show_sql to true.
This should show you the SQL that is executed and causes the
problem.
Set the log levels for Spring and Hibernate to DEBUG, again this
will give you a better idea as to which line causes the problem.
Create a unit test which replicates the problem without configuring
a transaction manager in Spring. This should give you a better idea
of the offending line of code.
Solution:
This Exception will arise in different scenario of save and saveOrupdate method of hibernate.
if Object is transient , need to save may occur this exception
Conditions.
Flushing the data before committing the object may lead to clear all object pending for persist.
If object has primary key which is auto generated and you are forcing has assigned key may cause the exception.
if you are cleaning the object before committing the object to database may lead this exception.
Zero or Incorrect ID: Hibernate excepts an primary or id of null (not initialize while saving) has per point 2 to mean the object was not saved. If you set the ID to zero or something else, Hibernate will try to update instead of insert, or it lead may to throw this exception.
Object Doesn’t Exist: This is the most easy to determine : has the object get deleted somehow? If so, trying to delete once again it will throw this exception.
Object is Stale: Hibernate caches objects from the session. If the object was modified, and Hibernate doesn’t know about it, it will throw this exception — note the StaleStateException part of the exception.
so after committing the object to database need to flush or clear or clean it ,not before.
As far as I know, there can be one of the below mentioned three reasons:
The primary key of the table in database is not correctly mapped in your code.
The update is being triggered for a non-backing object in database. You can easily find this out by looking at the id of the object in debug mode or print the id in logs and check if a record with that id actually exist in database at that time.
The isolation level. I see you are using READ_COMMITTED as the isolation level here. If above two did not make the exception go away, try setting DEFAULT as isolation level. Default will make the isolation level to be determined by the database tier which in your case is Microsoft SQL.
Share your code if none of the three mentioned above solve your issue.
Reading your explanation it seems also to me that is a problem related to the isolation level of your trasaction.
The READ_COMMITTED isolation level specify that it is possible to have access only to records not comprehended in an open transaction, so I think that in your case, it randomly happens that one other transaction accesses to one or plus of your records that are batch updated, and so it raises an exception.
I think that one solution is, giving a committ each row by time, verify each time the row's db state, or instead, you may manage this exception in a way to avoid halting of your process or transaction.
I am working on a java plugin interfacing with an H2 database. What I really want is an "Insert Ignore" statement; however, I'm aware that H2 doesn't support this. I am also aware of Merge, but this is really not what I want, if the record exists I don't want to change it.
What I am considering is to just run the insert and let the duplicate key exception happen. However, I don't want this to fill my log file. The DB call happens in an imported class that I can't change. So my questions are:
Is this a reasonable thing to do? I'm not one for letting errors happen, but this seems like the best way in this case (it should not happen all that much).
How can I keep this exception from hitting my log file? If there isn't a way to block exceptions down the stack, can I redirect the output of the stack trace that is output?
Thanks.
One solution is to use:
insert into test
select 1, 'Hello' from dual
where not exists(select * from test where id = 1)
This should work for all databases (except for the dual part; you may need to create your own dummy table with one row).
To disable logging exceptions, append ;trace_level_file=0 to the database URL:
jdbc:h2:~/test;trace_level_file=0
or run the SQL statement:
set trace_level_file 0
I'm running a Java application with Spring and I am getting an error on one of my insert statements. My error is:
nested exception is java.sql.SQLIntegrityConstraintViolationException:
ORA-01400: cannot insert NULL into ("MY_SCHEMA"."VALIDATION_RESULT"."RESULT_SEQ")
For all the database guys, is there ever a scenario that Oracle would return null from a nextval call? What about if multiple threads are calling it simultaneously?
For any Spring developers, we're using
org.springframework.jdbc.support.incrementer.OracleSequenceMaxValueIncrementer
to handle the sequence. We use the nextLongValue method.
My gut here is telling me that Oracle isn't giving me a null nextval. From everything I've already searched for, that seems impossible. Can anyone confirm?
Confirmed. They do not return NULL. You get an error message.
Oracle sequences actually generate a block of "nextval" objects so threads can quickly access them. You can alter the sequences to create larger readahead numbers of values if it is performance obstacle. The only possibility is if Oracle is seriously broken. Get your DBA to look in the alert log. Errors like ORA-06nn errors are a DBA's nightmare and are the only thing I am aware of that actually breaks objects like sequences.
In this case the DB and probably the DBA, too, are close to DOA. This kind of thing happens once in a career.
I would suspect your code first. Or someone tinking with the sequences - like doing something stupid with ALTER SEQUENCE. i.e., restarting the sequence from one and breaking table constraints. It is also easy to get things screwed up sequence-wise when you export only table from database DEV -> import to database TEST, because the other metadata needs to be brought over as well.
I am working on a java plugin interfacing with an H2 database. What I really want is an "Insert Ignore" statement; however, I'm aware that H2 doesn't support this. I am also aware of Merge, but this is really not what I want, if the record exists I don't want to change it.
What I am considering is to just run the insert and let the duplicate key exception happen. However, I don't want this to fill my log file. The DB call happens in an imported class that I can't change. So my questions are:
Is this a reasonable thing to do? I'm not one for letting errors happen, but this seems like the best way in this case (it should not happen all that much).
How can I keep this exception from hitting my log file? If there isn't a way to block exceptions down the stack, can I redirect the output of the stack trace that is output?
Thanks.
One solution is to use:
insert into test
select 1, 'Hello' from dual
where not exists(select * from test where id = 1)
This should work for all databases (except for the dual part; you may need to create your own dummy table with one row).
To disable logging exceptions, append ;trace_level_file=0 to the database URL:
jdbc:h2:~/test;trace_level_file=0
or run the SQL statement:
set trace_level_file 0