The version is increased although saveOrUpdate failed - java

I have a table in database create by SQL:
CREATE TABLE `s_supplier` ( <br/>
`id` int(11) NOT NULL auto_increment,<br/>
`code` varchar(32) collate utf8_bin NOT NULL,<br/>
`name` varchar(128) collate utf8_bin NOT NULL,<br/>
`version` int(11) NOT NULL default '0'<br/>
PRIMARY KEY (`id`),<br/>
UNIQUE KEY `ui_uom_category_code` (`code`)<br/>
)
The database existing 2 row:
(1, code1, name1, 1)
(2, code2, name2, 1)
Using spring-hibernate:
step 1:
I load row 1 to the entity and then change the code to code2 (the same as row 2).
and then call org.springframework.orm.hibernate3.support.HibernateDaoSupport.getHibernateTemplate().saveOrUpdate(entity);
--> It raises the exception 'duplicate code' --> OK
step 2:
I change the code to code3 and then save again by above method --> It raises the exception 'optimistic exception the row was update or delete by other user' (I just test on single user) --> KO
After tracing I found that after step 1 the version automatically increasing 1 on the entity. I think it should not because happened exception.
My question:
Is that the bug of spring framework or hibernate?

Does not sound like a bug. I don't know is it clearly documented in Hibernate documentation, but behavior is consistent with JPA specification:
Transaction rollback typically causes the persistence context to be in an
inconsistent state at the point of rollback. In particular, the state of
version attributes and generated state (e.g., generated primary keys) may
be inconsistent.

Related

(ObjectOptimisticLockingFailureException) StaleStateException in a single transaction

The code below is deliberately simplified and abridged to avoid unnecessary distraction.
I've mysql database with table:
CREATE TABLE `payment` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`status` varchar(45) DEFAULT NULL,
`last_update_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `id_UNIQUE` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=latin1
I have Spring Transactional method which is called from the controller.
#GetMapping("/reproduce_error")
#Transactional
public ResponseEntity reproduceErrorOnUpdate(Long id) {
try {
Payment payment = paymentDao.getPayment(id); //1st query
payment.setStatus(payment.getStatus().equals("A") ? "B" : "A");
paymentDao.findAllByStatus("NOT EXISTING STATUS"); // 2nd query
payment.setStatus("C");
} catch (Exception e) {
return new ResponseEntity<>(e, HttpStatus.INTERNAL_SERVER_ERROR);
}
return new ResponseEntity(HttpStatus.OK);
}
When I call this method I always have an exception:
org.springframework.orm.ObjectOptimisticLockingFailureException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1; nested exception is org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1
BUT AT THE SAME TIME (and it is the most curious thing):
if we omit the 2nd query (which anyway returns null!), the method works correctly!
Both methods are executed at the SINGLE transaction!
(here is how I call them both, so you can see that there are no other transactions somewhere)
There are no different threads or HTTP calls working with the same DB row (as per I reproduce it on my local machine). The only difference is that in the 1st case (error) we make the second search at the DB and have an error (even if this second search returns nothing) and at the 2nd case (success) we don't do so.
I understand that (in error case) Hibernate flushes changes before the 2nd call to DB is executed to support consistency. But why then we have StaleStateException as we DO process everything it ONE transaction and every changes made in it should be visible for itself.
Could someone help me with this weird hibernate behavior and explain why this happens.
I've prepared the minimal reproduceable app and placed it on bitbucket:
https://bitbucket.org/gegunov/hibernate_issue
I've also raised a ticket at Hibernate project's Jira: https://hibernate.atlassian.net/browse/HHH-13867
The Hibernate team has helped me with it. It turned out that this issue was a result of both, Hibernate and MySql bugs connected with precision losses during the flush.
One of the workarounds is to change DB column format from TIMESTAMP to (e.g) TIMESTAMP(6) or DATETIME(6).

SQLException when specifying length along with default value for varchar

I'm trying to initialise an inmemory H2 database with Spring using something like the following statement:
===Throws SQLException===
CREATE TABLE config (
id INTEGER NOT NULL,
module_id VARCHAR(10) NOT NULL DEFAULT 'global',
...
);
Every time I try to run the project an SQLException is thrown saying the syntax is wrong. After quite a bit of experimenting I have noted that when I remove the DEFAULT keyword, there is no exception thrown.
===This works===
CREATE TABLE config (
id INTEGER NOT NULL,
module_id VARCHAR(10) NOT NULL,
...
);
What is even more interesting is that when I removed the length on the VARCHAR and kept the DEFAULT keyword as it is also it worked.
===This also works===
CREATE TABLE config (
id INTEGER NOT NULL,
module_id VARCHAR NOT NULL DEFAULT 'global',
...
);
So the question is, is there something preventing both of these being specified together?
According to a strict reading of the syntax diagram in documentation for the SQL grammar...
the default clause has to come before the NOT NULL.

#1467 - Failed to read auto-increment value from storage engine

I was trying to create a new object and this error appeared:
java.sql.sqlexception failed to read auto-increment value from storage engine
So I went to the phpMyAdmin to create the object there and the same showed up:
MySQL said: Documentation
1467 - Failed to read auto-increment value from storage engine
then I clicked on edit, and it was there:
INSERT INTO `reservation`.`room` (`idroom`, `number`, `floor`, `description`, `characteristics`, `cost`, `status`, `type`) VALUES (NULL, '114', '3', 'ss', 'ss', '550.00', 'Available', 'ss')
(idroom is supposed to be auto-incremented.)
I already read other posts where they say I have to put this:
ALTER TABLE `table_name` AUTO_INCREMENT = 1
but I have no idea where to put that. Is there a better solution?
Your INSERT statement is wrong. Since idroom is AUTO_INCREMENT; you must not include it in the column list on your insert command. Your insert statement should look like below. Notice that I have removed idroom column from insert column list and not passing NULL as well in value list.
INSERT INTO `reservation`.`room` (`number`, `floor`, `description`,
`characteristics`, `cost`, `status`, `type`)
VALUES ('114', '3', 'ss', 'ss', '550.00', 'Available', 'ss')
I also struggled with this problem and searched, and didn't find anything. Then the following worked for me; I guess it might work for your problem. Thx.
1st:
-delete (before backup)->all data from your database.
-try to run your Java program again, or any program you want.
If it fails then go to 2nd.
2nd:
- backup all data from your table
- delete table completely
- create table again; example shown below:
CREATE TABLE `users` (
`id` int(6) NOT NULL,
`f_name` varchar(30) NOT NULL,
`l_name` varchar(30) NOT NULL,
`address` varchar(50) DEFAULT NULL,
`phone_num` varchar(12) DEFAULT NULL,
`email` varchar(30) DEFAULT NULL
);
ALTER TABLE `users`
ADD PRIMARY KEY (`id`);
AUTO_INCREMENT for table `users`
ALTER TABLE `users`
MODIFY `id` int(6) NOT NULL AUTO_INCREMENT;

com.mysql.jdbc.MysqlDataTruncation: Data truncation: Incorrect date value: '' for column 'Date_Of_Birth' at row 1

I'm trying to update the personal detail of a user through a java panel.Panel has fields like user_id(autogenerated),name,date of birth.
problem is when i enter nothing to the date of birth field in java panel and then save it. It gives me the above mentioned error.
i tried to verify it by inserting null to the date of birth(Date datatype) field directly using the mysql database.There it gives no error.
Why is it not taking null string when i insert through java panel but is taking when insert directly using mysql.
CREATE TABLE `userpersonaldetail` (
`User_Id` int(10) unsigned NOT NULL auto_increment,
`Name` varchar(45) default NULL,
`Date_Of_Birth` date default NULL,
`Address` varchar(300) default NULL,
`Phone` varchar(20) default NULL,
`Mobile` varchar(20) default NULL,
`Email` varchar(50) default NULL,
PRIMARY KEY (`User_Id`),
CONSTRAINT `FK_userpersonaldetail_1` FOREIGN KEY (`User_Id`) REFERENCES `usermaster` (`User_Id`)
)
And the portion of the code where exception occurs is:
try
{
con=(Connection) DBConnection.getConnection();
pstmt=(PreparedStatement) con.prepareStatement("Update userpersonaldetail set "+
"name=?,date_of_birth=?,address=?,phone=?,mobile=?,email=? where user_id=?");
pstmt.setInt(7,perBean.getUserId());
pstmt.setString(1,perBean.getName());
pstmt.setString(2,perBean.getDateOfBirth());
pstmt.setString(3,perBean.getAddress());
pstmt.setString(4,perBean.getPhone());
pstmt.setString(5,perBean.getMobile());
pstmt.setString(6,perBean.getEmail());
int i=pstmt.executeUpdate();
}
here perBean is the javaBean which retrieves values from the gui.In one of the test case i kept the date_of_birth text box null which is giving error while storing in DB.
My initial guess would be the field has been defined as 'NOT NULL' which means it will force you to enter a value...
If you were to do a mysql dump of the table (or view it in some tool) you'll probably find it defined such as:
`someDT` datetime NOT NULL
I replaced older version of my-sql-connector jar (to be found in lib folder of the server) with the latest. That solved my problem.
Ahh, i see now, you can't insert '' as a date. you will need to pass a date.
If an attribute does not have a value but you have it mentioned in the column list, forcing you to give something there, you need to use
statement.setNull(index, datatype)
to it. Setting to "" is not the same thing as setting to null.

CMP 2.0 bean auto-generated primary key WAS 6.1

is it possible to map bean's key field with identity primary key column in DB2?
Sample table:
CREATE TABLE ADDRESS (
ID INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (
START WITH 1
INCREMENT BY 1
MINVALUE 1
MAXVALUE 2147483647
NO CYCLE
CACHE 20
NO ORDER ),
Line1 VARCHAR(255) NOT NULL,
Line2 VARCHAR(255),
City VARCHAR(255) NOT NULL,
Postcode VARCHAR(6) NOT NULL,
Country VARCHAR(50) NOT NULL,
Latitude DOUBLE,
Longitude DOUBLE
)
AUDIT NONE
DATA CAPTURE NONE
CCSID UNICODE;
ejbCreate methods have been tailored NOT TO set ID field, but it gets initialized with default for integer type - 0 so i'm getting DuplicateKeyException on second and following calls to ejbCreate.
What is the best way to implement IDENTITY behavior? I found many examples for JBoss but nothing for WAS.
It was easy with JPA, but CMP 2.0 is a must at this time
Override method ejbPostCreate. You will be able to retrieve the generated ID from there, and update your model and your code in order to avoid duplicate IDs.
For instance, take a look at http://forums.sun.com/thread.jspa?threadID=699131

Categories

Resources