Hibernate can't create table - mysql

I just started to user hibernate and i allways get this Error:
ERROR: HHH000388: Unsuccessful: create table User (id bigint not null auto_increment, mail varchar(255), passwort varchar(255), primary key (id))
ERROR: Got error -1 from storage engine
This is my mapped class:
package Entities;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
#Entity
public class User
{
private long id;
private String mail;
private String passwort;
#Id
#GeneratedValue
#Column(name="id")
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
#Column(name="mail")
public String getMail() {
return mail;
}
public void setMail(String mail) {
this.mail = mail;
}
#Column(name="passwort")
public String getPasswort() {
return passwort;
}
public void setPasswort(String passwort) {
this.passwort = passwort;
}
}

It is because "User" is a reserved keyword. You should change your table name.
The annotation below is the solution for this issue.
#Table(name = "users")

Here is the hibernate config:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/mysql?zeroDateTimeBehavior=convertToNull</property>
<property name="hibernate.connection.username">root</property>
<property name="connection.pool_size">1</property>
<property name="show_sql">true</property>
<property name="hbm2ddl.auto">update</property>
</session-factory>
</hibernate-configuration>

I don't know why but I had same issue. Then I just change the name for table with #Table(name="Users") annotation and it started to work.
So try changing this
#Entity
public class User
{
}
to This:
#Entity
#Table(name="Users")
public class User
{
}

Wrong
#Entity /* It will map POJO class with DB Table i,e. Hibernate mapping */
#Table() /* Create Table in DB */
public class User {
}
Right
#Entity /* It will map POJO class with DB Table i,e. Hibernate mapping */
#Table(name="F2CUSER") /* Create Table in DB */
public class User {
}
Here I have use #Table(name="F2CUSER") and it works for me

Related

Hibernate #OneToOne gets a NullPointer Exception

I am reviewing my Java skills and your support to the community is amazing, your tips have helped me a lot.
I am stuck in a Hibernate #OneToOne configuration, it is a very simple design and code but I can´t find the error. I´d really appreciate your help.
This is the user.java code, the user_id is generated by an autoincrement column at MySQL. I have omitted hash() and equals() code for simplicity. Hibernate understands the User class but something is missing to get to the Address class that is at the other side of the relationship.
Any help would be very appreciated.
Thank you
1) This is the user.java:
package myPackage;
import java.io.Serializable;
import java.util.Arrays;
import javax.persistence.*;
#Entity
#Table(name="user1")
public class User implements Serializable {
private static final long serialVersionUID = 3271213543123246487L;
#Id
#GeneratedValue
#Column(name="user_id")
private Integer user_id;
#Column(name="user_name", length=100, nullable=false)
private String user_name;
#OneToOne (cascade= CascadeType.ALL)
#PrimaryKeyJoinColumn(name="user_id")
private Address myAddress;
public Integer getUser_id() {
return user_id;
}
public void setUser_id(Integer user_id) {
this.user_id = user_id;
}
public String getUser_name() {
return user_name;
}
public void setUser_name(String user_name) {
this.user_name = user_name;
}
public Address getMyAddress() {
return myAddress;
}
public void setMyAddress(Address myAddress) {
this.myAddress = myAddress;
}
}
2) This is the Address.java code:
package myPackage;
import java.io.Serializable;
import javax.persistence.*;
import org.hibernate.annotations.Parameter;
#Entity
#Table(name="address1")
public class Address implements Serializable {
private static final long serialVersionUID = 3605176021936036836L;
#Id
#GeneratedValue(generator="address_ibfk_2")
#org.hibernate.annotations.GenericGenerator(name="address_ibfk_2",
strategy="foreign",parameters =#Parameter(name="property",value="user1"))
#Column(name="user_id")
private Integer user_id;
#Column(name="address_line1", length=100, nullable=false)
private String address_line1;
public String getAddress_line1() {
return address_line1;
}
public void setAddress_line1(String address_line1) {
this.address_line1 = address_line1;
}
}
3) This is the very simple TestUser class
public class TestUser {
public static void main(String[] args) {
Session mySession = HibernateUtil.getSessionFactory().openSession();
System.out.println("Connection status"+mySession.isConnected());
System.out.println("Session status"+mySession.isOpen());
Transaction myTransaction = mySession.beginTransaction();
try {
User myUser = new User();
Address myAddress = new Address();
myUser.setUser_name("TesteO2O");
myAddress.setAddress_line1("Rua A");
myUser.setMyAddress(myAddress);
mySession.save(myUser);
myTransaction.commit();
System.out.println("myUser saved sucessfully");
} catch (Exception e) {
e.printStackTrace();
myTransaction.rollback();
} finally {
mySession.close();
}
}
}
4) This is the hibernate.cfg.xml config file
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!--MySQL Config-->
<property name="dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property>
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="connection.url">jdbc:mysql://localhost/p2pl_dev?serverTimezone=UTC</property>
<property name="connection.username">xyz</property>
<property name="connection.password">blabla</property>
<property name="current_session_context_class">thread</property>
<!--Connection Pool Config: max_statements cached, idle time in seconds-->
<property name="c3po.min_size">2</property>
<property name="c3po.max_size">3</property>
<property name="c3po.timeout">300</property>
<property name="c3po.max_stamentes">50</property>
<property name="c3po.idle_test_period">3000</property>
<!--Debug Config, show_sql=console, format_sql=legible -->
<property name="show_sql">true</property>
<property name="format_sql">true</property>
<property name="generate_statistics">true</property>
<property name="use_sql_comments">true</property>
<!-- Classes -->
<mapping class="myPackage.User"/>
<mapping class="myPackage.Address"/>
</session-factory>
</hibernate-configuration>
5) Finally the error trace
Hibernate:
/* insert myPackage.User
*/ insert
into
user1
(user_name)
values
(?)
java.lang.NullPointerException
at org.hibernate.tuple.entity.AbstractEntityTuplizer.getPropertyValue(AbstractEntityTuplizer.java:650)
at org.hibernate.persister.entity.AbstractEntityPersister.getPropertyValue(AbstractEntityPersister.java:4736)
at org.hibernate.id.ForeignGenerator.generate(ForeignGenerator.java:96)
at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:117)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:209)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:194)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:114)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:90)
at org.hibernate.internal.SessionImpl.fireSaveOrUpdate(SessionImpl.java:684)
at org.hibernate.internal.SessionImpl.saveOrUpdate(SessionImpl.java:676)
at org.hibernate.engine.spi.CascadingActions$5.cascade(CascadingActions.java:235)
at org.hibernate.engine.internal.Cascade.cascadeToOne(Cascade.java:350)
at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:293)
at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:161)
at org.hibernate.engine.internal.Cascade.cascade(Cascade.java:118)
at org.hibernate.event.internal.AbstractSaveEventListener.cascadeAfterSave(AbstractSaveEventListener.java:460)
at org.hibernate.event.internal.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:294)
at org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:194)
at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:125)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:209)
at org.hibernate.event.internal.DefaultSaveEventListener.saveWithGeneratedOrRequestedId(DefaultSaveEventListener.java:55)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:194)
at org.hibernate.event.internal.DefaultSaveEventListener.performSaveOrUpdate(DefaultSaveEventListener.java:49)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:90)
at org.hibernate.internal.SessionImpl.fireSave(SessionImpl.java:715)
at org.hibernate.internal.SessionImpl.save(SessionImpl.java:707)
at org.hibernate.internal.SessionImpl.save(SessionImpl.java:702)
at myPackage.TestUser.main(TestUser.java:26)

HTTP Status 500 - Servlet.init() for servlet management threw exception

Emp.java
package com.management;
public class Emp {
private int id;
private String name;
private float salary;
private String designation;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public float getSalary() {
return salary;
}
public void setSalary(float salary) {
this.salary = salary;
}
public String getDesignation() {
return designation;
}
public void setDesignation(String designation) {
this.designation = designation;
}
}
EmpController.java
package com.management;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
import com.management.Emp;
import com.management.EmpDao;
#Controller
public class EmpController {
#Autowired
EmpDao dao;//will inject dao from xml file
/*It displays a form to input data, here "command" is a reserved request attribute
*which is used to display object data into form
*/
#RequestMapping("/empform")
public ModelAndView showform(){
return new ModelAndView("empform","command",new Emp());
}
/*It saves object into database. The #ModelAttribute puts request data
* into model object. You need to mention RequestMethod.POST method
* because default request is GET*/
#RequestMapping(value="/save",method = RequestMethod.POST)
public ModelAndView save(#ModelAttribute("emp") Emp emp){
dao.save(emp);
return new ModelAndView("redirect:/viewemp");//will redirect to viewemp request mapping
}
/* It provides list of employees in model object */
#RequestMapping("/viewemp")
public ModelAndView viewemp(){
List<Emp> list=dao.getEmployees();
return new ModelAndView("viewemp","list",list);
}
/* It displays object data into form for the given id.
* The #PathVariable puts URL data into variable.*/
#RequestMapping(value="/editemp/{id}")
public ModelAndView edit(#PathVariable int id){
Emp emp=dao.getEmpById(id);
return new ModelAndView("empeditform","command",emp);
}
/* It updates model object. */
#RequestMapping(value="/editsave",method = RequestMethod.POST)
public ModelAndView editsave(#ModelAttribute("emp") Emp emp){
dao.update(emp);
return new ModelAndView("redirect:/viewemp");
}
/* It deletes record for the given id in URL and redirects to /viewemp */
#RequestMapping(value="/deleteemp/{id}",method = RequestMethod.GET)
public ModelAndView delete(#PathVariable int id){
dao.delete(id);
return new ModelAndView("redirect:/viewemp");
}
}
EmpDao.java
package com.management;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import com.management.Emp;
public class EmpDao {
JdbcTemplate template;
public void setTemplate(JdbcTemplate template) {
this.template = template;
}
public int save(Emp p){
String sql="insert into Emp99(name,salary,designation) values('"+p.getName()+"',"+p.getSalary()+",'"+p.getDesignation()+"')";
return template.update(sql);
}
public int update(Emp p){
String sql="update Emp99 set name='"+p.getName()+"', salary="+p.getSalary()+", designation='"+p.getDesignation()+"' where id="+p.getId()+"";
return template.update(sql);
}
public int delete(int id){
String sql="delete from Emp99 where id="+id+"";
return template.update(sql);
}
public Emp getEmpById(int id){
String sql="select * from Emp99 where id=?";
return template.queryForObject(sql, new Object[]{id},new BeanPropertyRowMapper<Emp>(Emp.class));
}
public List<Emp> getEmployees(){
return template.query("select * from Emp99",new RowMapper<Emp>(){
public Emp mapRow(ResultSet rs, int row) throws SQLException {
Emp e=new Emp();
e.setId(rs.getInt(1));
e.setName(rs.getString(2));
e.setSalary(rs.getFloat(3));
e.setDesignation(rs.getString(4));
return e;
}
});
}
}
servlet-management.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns = "http://www.springframework.org/schema/beans"
xmlns:context = "http://www.springframework.org/schema/context"
xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation = "http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:component-scan base-package = "com.spring" />
<bean class = "org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name = "prefix" value = "/WEB-INF/jsp/" />
<property name = "suffix" value = ".jsp" />
</bean>
<bean id="ds" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://loclahost:3306/test1" />
<property name="username" value="root" />
<property name="password" value="" />
</bean>
<bean id="jt" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="ds"></property>
</bean>
<bean id="dao" class="com.spring.EmpDao">
<property name="template" ref="jt"></property>
</bean>
</beans>
web.xml
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
<servlet>
<servlet-name>management</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>management</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
hi
my trying to insert the value to the database by using the spring-mvc.
and using the mysql database.
while execution process it shows the error like that-org.springframework.beans.factory.CannotLoadBeanClassException: Cannot find class [com.spring.EmpDao] for bean with name 'dao' defined in ServletContext resource [/WEB-INF/management-servlet.xml]; nested exception is java.lang.ClassNotFoundException: com.spring.EmpDao .
please provide the soluation.
thank you.

Why list size shows zero?

I have used spring boot, try to retrieve all the product from the database ( MySQL ) . But list size is zero. There is no error is shown to console.
This is my controller:
#RequestMapping(value = "/showListOfProduct", method=RequestMethod.GET)
public String showList(Model model) {
List<Products> allProduct = productService.listAllProducts();
System.out.println("sizeEEEEEEEEEEEEEE"+ allProduct.size());
model.addAttribute("allProduct", allProduct);
return "showlist";
}
This is repository:
#Repository
public interface ProductRepository extends JpaRepository<Products, Long> {
}
This is service:
#Transactional(propagation = Propagation.REQUIRED, readOnly = true)
public List<Products> listAllProducts() {
return productRepository.findAll();
}
This is my Entity:
#Entity
#Table(name="products")
public class Products {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private long id;
#Column(name="productname")
private String productName;
#Column(name="numberofavailableinstock")
private long numberofavailableInStock;
#Column(name="productprice")
private String productPrice;
#Column(name="percentageofsell")
private double percentageOfSell;
// setter getter
This is my application.properties:
> spring.mvc.view.prefix: webapp/WEB-INF/jsp/ spring.mvc.view.suffix:
> .jsp server.port=7000 spring.datasource.url=
> jdbc:mysql://localhost:3306/myproduct spring.datasource.username=root
> spring.datasource.password=root
> spring.jpa.hibernate.ddl-auto=create-drop spring.jpa.show-sql=true
My database is:
> Table: products Columns: id int(11) AI PK productname varchar(45)
> productprice varchar(45) numberofavailableinstock varchar(45)
> percentageofsell varchar
Usually when I run into this type of issue, its because my #Entity and the schema don't match up properly.
You should consider adding these two properties to your application.properties:
spring.jpa.generate-ddl=true
spring.jpa.hibernate.ddl-auto=update
That will help you keep schema and entity matching.

com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 'user0_.userId' in 'field list'

I am getting Error:
com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 'user0_.userId' in 'field list'
Please check the code and reply to me .
Step 1: creating database table
CREATE TABLE `userlogin` (
`email` varchar(20) DEFAULT NULL,
`password` varchar(20) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
example:
email = mahesh#gmail.com
pwd = 1234
step 2: entity class
package com.ims.entity;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
#Entity
#Table(name="userlogin")
public class User {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Long userId;
#Column(name="email")
private String email;
#Column(name="password")
private String password;
//setter and getter methods
step 3: bean class
package com.ims.bean;
import org.hibernate.validator.constraints.NotEmpty;
public class LoginBean {
#NotEmpty
private String emailid;
#NotEmpty
private String password;
public String getEmail() {
return emailid;
}
public void setEmail(String email) {
this.emailid = email;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
step 4: controller class
package com.ims.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import com.ims.bean.LoginBean;
import com.ims.entity.User;
import com.ims.service.UserService;
#Controller
public class LoginController extends BaseController{
#Autowired
private UserService userService;
#RequestMapping({"/","/home"})
public String viewHomePage(Model model){
model.addAttribute(new LoginBean());
return "home";
}
step 5: service class
package com.ims.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import com.ims.bean.LoginBean;
import com.ims.dao.UserDao;
import com.ims.entity.User;
#Service
#Transactional(propagation=Propagation.REQUIRED)
public class UserService {
#Autowired
private UserDao userDao;
public boolean isUserExists(LoginBean loginBean){
User user = userDao.findUser(loginBean);
return user != null ? true: false;
}
public User findUser(LoginBean loginBean){
User user = userDao.findUser(loginBean);
return user;
}
step 6 dao class
package com.ims.dao;
import java.util.List;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import com.ims.bean.LoginBean;
import com.ims.entity.User;
#Repository
public class UserDaoImpl implements UserDao {
#Autowired
private SessionFactory sessionFactory;
#SuppressWarnings("unchecked")
public User findUser(LoginBean loginBean){
User user = null;
Session session = sessionFactory.openSession();
List<User> users = session.createQuery("from User where email = '"+loginBean.getEmail()+"' and password='"+loginBean.getPassword()+"'").list();
if(users != null){
user = users.get(0);
}
session.close();
return user;
}
step 7 hibermate configuration file
<hibernate-configuration>
<session-factory>
<!-- We're using MySQL database so the dialect needs to MySQL as well-->
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
</session-factory>
</hibernate-configuration>
step 8: applicationcontext file
<tx:annotation-driven />
<bean id="messageSource"
class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basename" value="classpath:messages" />
<property name="defaultEncoding" value="UTF-8" />
</bean>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"
p:driverClassName="com.mysql.jdbc.Driver"
p:url="jdbc:mysql://localhost:3306/agiledb" p:username="root"
p:password="admin"
p:initialSize="5"
p:maxActive="10"
p:maxWait="-1"
p:testOnBorrow="true"
p:validationQuery="select 1 as dbcp_connection_test"
p:minIdle="1" />
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"
p:dataSource-ref="dataSource" p:configLocation="/WEB-INF/hibernate.cfg.xml"
p:packagesToScan="com.ims.entity" />
<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
</beans>
step 9: project name - servlet.xml
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- Example: a logical view name of 'showMessage' is mapped to '/WEB-INF/jsp/showMessage.jsp' -->
<property name="prefix" value="/WEB-INF/view/"/>
<property name="suffix" value=".jsp"/>
</bean>
java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
Exception is occurring because your query criteria list() is returning empty users list, and you are trying to access the 0 index.

Hibernate Optimistic Lock with/without a Version not working

I have a legacy app that uses:
hibernate-3.5.5.jar
hibernate-jpa-2.0-api-1.0.0.jar
Spring 3.0.2
Tapestry 5.3.8
MySQL
Tomcat 7.0.64
It has a serious issue with multiple users updating the same table row at the same time and loosing the first update. Basically user A says "I want to own the record" (place my id in the record) and user B says "I want to own the record" the code being processed takes a bit of time. So user A gets it and then user B doesn't notice that user A had it and so user B gets it when he shouldn't have because user A already had it.
I've tried using:
#org.hibernate.annotations.Entity(dynamicUpdate = true, optimisticLock = OptimisticLockType.ALL)
on the Entity class for the table and watching the SQL that hibernate produces it never adds the table columns to the SQL update statement. It simply has update ... where id=?.
I've also tried adding a version column to the table in question and the Entity class and annotated the field with
#Version.
This has exactly the same effect as above, nothing in the generated SQL is using the version column. It never gets incremented either.
I'm guessing that I'm missing something with setting this up or there is something about the way the app uses hibernate that is keeping this from working as everything I have read says it should "Just Work".
appContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
<!-- Configurer that replaces ${...} placeholders with values from a properties
file -->
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:app_jdbc.properties"/>
</bean>
<!-- Message source for this context, loaded from localized files -->
<bean id="messageSource"
class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basenames">
<list>
<value>app_app</value>
<value>app_env</value>
<value>pdf</value>
</list>
</property>
</bean>
<!-- Define data source -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName">
<value>${jdbc.driverClassName}</value>
</property>
<property name="url">
<value>${jdbc.url}</value>
</property>
<property name="username">
<value>${jdbc.username}</value>
</property>
<property name="password">
<value>${jdbc.password}</value>
</property>
<property name="defaultAutoCommit">
<value>${jdbc.autoCommit}</value>
</property>
<property name="maxActive">
<value>${dbcp.maxActive}</value>
</property>
<property name="maxWait">
<value>${dbcp.maxWait}</value>
</property>
</bean>
<!-- Hibernate SessionFactory -->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="annotatedClasses">
<list>
...
<value>company.app.domain.Overtime</value>
...
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
<prop key="hibernate.query.substitutions">${hibernate.query.substitutions}</prop>
</props>
</property>
</bean>
<!-- Transaction manager for a single Hibernate SessionFactory (alternative
to JTA) -->
<bean id="txManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory">
<ref local="sessionFactory" />
</property>
</bean>
<!-- regular beans -->
<bean id="baseDao" class="vive.db.BaseHbDao">
<property name="sessionFactory">
<ref local="sessionFactory" />
</property>
</bean>
...
<bean id="overtimeDao" class="company.app.dataaccess.OvertimeDao">
<property name="sessionFactory">
<ref local="sessionFactory" />
</property>
</bean>
...
<!-- service beans -->
<bean id="appService" class="company.app.services.AppService">
<property name="baseDao"><ref local="baseDao"/></property>
...
</bean>
<!-- transaction advice -->
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="get*" read-only="true" />
<tx:method name="*" />
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="serviceOperation"
expression="execution(* company.app.services.*Service.*(..))" />
<aop:advisor pointcut-ref="serviceOperation" advice-ref="txAdvice" />
</aop:config>
</beans>
Overtime Entity class:
package company.app.domain;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import javax.persistence.Transient;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Parameter;
import org.hibernate.annotations.OptimisticLockType;
#Entity
#Table(name = "over_time")
#org.hibernate.annotations.Entity(dynamicUpdate = true, optimisticLock = OptimisticLockType.ALL)
public class Overtime implements java.io.Serializable {
private static final long serialVersionUID = 7263309927526074109L;
#Id
#GeneratedValue(generator = "ot_gen")
#GenericGenerator(name = "ot_gen", strategy = "hilo", parameters = {
#Parameter(name = "table", value = "unique_key"), #Parameter(name = "column", value = "next_hi"),
#Parameter(name = "max_lo", value = "99") })
private Integer id;
#Deprecated
#Column(name = "from_time")
private Date fromTime;
#Deprecated
#Column(name = "to_time")
private Date toTime;
#Column(name = "fm_dttm")
private Long fromDttm;
#Column(name = "to_dttm")
private Long toDttm;
#Column(name = "post_dttm")
private Long postDttm;
private String dow;
private String shift;
#Column(name = "sub_groups")
private String subGroups;
#Column(name = "created_by")
private String createdBy;
#Column(name = "signed_up_by")
private String signedUpBy;
#Column(name = "signed_up_via")
private String signedUpVia;
#Column(name = "date_signed_up")
private Date dateSignedUp;
#Column(name = "signed_up_by_partner_username")
private String signedUpByPartnerUsername;
#Column(name = "signed_up_by_partner_ot_refno")
private String signedUpByPartnerOtRefNo;
private String comment;
private Integer status;
#Column(name = "title_abbrev")
private String titleAbbrev;
#Column(name = "record_status")
private String recordStatus;
#Column(name = "ref_no")
private String refNo;
#Column(name = "ref_id")
private String refId;
#Column(name = "misc_notes")
private String miscNotes;
#Column(name = "sends_notif_upon_posting")
private Boolean sendsNotificationUponPosting;
#Column(name = "notify_post_person_when_filled")
private Boolean notifyPostPersonWhenFilled;
#Column(name = "notify_others_when_filled")
private Boolean notifyOthersWhenFilled;
#Column(name = "vehicle_needed")
private Boolean vehicleNeeded;
#Column(name = "agency_id")
private Integer agencyId;
#Column(name = "schedule_id")
private Integer scheduleId;
#Column(name = "post_date")
private Date postDate;
#Column(name = "enrollment_opens_at")
private Date enrollmentOpensAt;
#Column(name = "enrollment_closes_at")
private Date enrollmentClosesAt;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "class_id")
private OvertimeClass overtimeClass;
public Overtime() {
}
//getters and setters
}
The Tapestry page class where the user tries to sign up for the overtime:
package company.app.pages;
import java.io.*;
import java.text.MessageFormat;
import java.util.*;
import org.apache.tapestry5.StreamResponse;
import org.apache.tapestry5.annotations.Component;
import org.apache.tapestry5.annotations.InjectComponent;
import org.apache.tapestry5.annotations.InjectPage;
import org.apache.tapestry5.annotations.Property;
import org.apache.tapestry5.annotations.SessionState;
import org.apache.tapestry5.annotations.Persist;
import org.apache.tapestry5.corelib.components.Form;
import org.apache.tapestry5.corelib.components.Zone;
import org.apache.tapestry5.ioc.Messages;
import org.apache.tapestry5.ioc.annotations.Inject;
import org.apache.tapestry5.services.PageRenderLinkSource;
import org.apache.tapestry5.services.Request;
import org.apache.tapestry5.services.RequestGlobals;
import org.hibernate.StaleObjectStateException;
import org.slf4j.Logger;
import org.springframework.transaction.annotation.Transactional;
import vive.util.*;
import company.t5ext.LabelValueSelectModel;
import company.t5ext.components.DateTimeField;
import company.app.*;
import company.app.domain.*;
import company.app.services.CacheService;
import company.app.services.AppService;
import company.app.comparator.OtComparator;
#RequiresLogin
public class ListPostedOvertime {
#SessionState
#Property
private AppSessionState visit;
#Inject
private RequestGlobals requestGlobals;
#Inject
#Property
private AppService appService;
#Inject
private Request request;
void setupRender() {
...
}
// this method handle the case when a user tries to sign up for an overtime slot
void onSignUp(Integer overtimeId) {
// check to see if the OT has been deleted or modified or signed-up
Overtime ot = (Overtime)appService.getById(Overtime.class, overtimeId);
if (ot == null) {
visit.setOneTimeMessage("The overtime has already been deleted.");
return;
}
if (ot.getStatus() != null && ot.getStatus() != AppConst.OT_NEW) {
visit.setOneTimeMessage("The overtime has already been signed up. Please choose a different one to sign up.");
return;
}
...
try {
appService.validateOvertimeForUser(agency, user, ot);
appService.handleSignUpOvertime(agency, user, ot);
// log activity
String what = "Signed up for overtime " + ot.getRefNo() + ".";
appService.logActivity(user, AppConst.LOG_OVERTIME, what);
} catch(StaleObjectStateException e) {
visit.setOneTimeMessage("The overtime record has been changed by another user, please try again.");
return;
} catch(Exception e) {
visit.setOneTimeMessage(e.getMessage());
return;
}
...
}
}
The AppService class that is used by the Tapestry page to update the overtime record:
package company.app.services;
import java.io.Serializable;
import java.util.*;
import java.text.DecimalFormat;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.LockMode;
import org.springframework.context.support.ResourceBundleMessageSource;
import vive.db.BaseHbDao;
import vive.util.*;
import company.app.*;
import company.app.comparator.LeaveRequestComparator;
import company.app.comparator.UserOtInterestComparator;
import company.app.dataaccess.*;
import company.app.domain.*;
public class AppService
{
private Log log = LogFactory.getLog(this.getClass().getName());
private BaseHbDao baseDao;
private OvertimeDao otDao;
private MiscDao miscDao;
private ResourceBundleMessageSource msgSource;
/**
* Default constructor.
*/
public AppService() {
}
public void save(Object item) {
if (item != null) {
baseDao.save(item);
}
}
public void update(Object item) {
if (item != null) {
baseDao.update(item);
}
}
public void saveOrUpdate(Object item) {
if (item != null) {
baseDao.saveOrUpdate(item);
}
}
public void saveOrUpdateAll(Collection col) {
if (col != null) {
baseDao.saveOrUpdateAll(col);
}
}
public void delete(Object item) {
if (item != null) {
baseDao.delete(item);
}
}
public void deleteAll(Collection col) {
if (col != null) {
baseDao.deleteAll(col);
}
}
public Object getById(Class clazz, Serializable id) {
return baseDao.get(clazz, id);
}
public Object getById(Class clazz, Serializable id, LockMode lockMode) {
return baseDao.get(clazz, id, lockMode);
}
public void validateOvertimeForUser(Agency agency, User user, Overtime ot) throws Exception {
validateOvertimeForUser(agency.getId(), agency, user, ot);
}
public void validateOvertimeForUser(AgencyLite agency, User user, Overtime ot) throws Exception {
validateOvertimeForUser(agency.getId(), agency, user, ot);
}
public void handleSignUpOvertime(AgencyBase agency, User user, Integer otId) {
Overtime ot = (Overtime)getById(Overtime.class, otId);
handleSignUpOvertime(agency, user, ot);
}
public void handleSignUpOvertime(AgencyBase agency, User user, Overtime ot) {
handleSignUpOvertime(agency, user, ot, 1.0d);
}
public void handleSignUpOvertime(AgencyBase agency, User user, Integer otId, Double ptsPerOt) {
Overtime ot = (Overtime)getById(Overtime.class, otId);
handleSignUpOvertime(agency, user, ot, ptsPerOt);
}
public void handleSignUpOvertime(AgencyBase agency, User user, Overtime ot, Double ptsPerOt) {
handleSignUpOvertime(agency, user, ot, ptsPerOt, null, null);
}
public void handleSignUpOvertime(AgencyBase agency, User user, Overtime ot, Double ptsPerOt, String viaUsername, String viaName) {
Date today = new Date();
boolean isOtConfirmRequired = AppUtil.isTrue(agency.getOtConfirmRequired());
Integer otConfirmThreshold = 0;
if (agency.getOtConfirmThreshold() != null) {
otConfirmThreshold = agency.getOtConfirmThreshold();
}
long otInDays = (ot.getFromDttm() - today.getTime()) / AppConst.MILLIS_IN_DAY;
ot.setSignedUpBy(user.getUsername());
ot.setDateSignedUp(today);
ot.setSignedUpVia(viaUsername);
if (isOtConfirmRequired && otInDays >= otConfirmThreshold) {
ot.setStatus(AppConst.OT_PDG);
} else {
ot.setStatus(AppConst.OT_FIN);
}
saveOrUpdate(ot);
user.setLastOtSignupDate(today);
user.setPoints(AppUtil.addPoints(ptsPerOt, user.getPoints()));
saveOrUpdate(user);
...
// email notification sent from caller
}
...
}
The base class for all of the DAO classes:
package vive.db;
import java.io.Serializable;
import java.util.*;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.LockMode;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.HibernateException;
import org.hibernate.type.Type;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import vive.XException;
import vive.util.XUtil;
/**
* The superclass for hibernate data access object.
*/
public class BaseHbDao extends HibernateDaoSupport implements BaseHbDaoInterface
{
private Log log;
public BaseHbDao() {
super();
log = LogFactory.getLog(getClass());
}
...
/**
* Save or update an object.
*/
public void saveOrUpdate(Object obj) {
getHibernateTemplate().saveOrUpdate(obj);
}
public void save(Object obj) {
getHibernateTemplate().save(obj);
}
public void update(Object obj) {
getHibernateTemplate().update(obj);
}
/**
* Delete an object.
*/
public void delete(Object obj) {
getHibernateTemplate().delete(obj);
}
/**
* Retrieve an object of the given id, null if it does not exist.
* Similar to "load" except that an exception will be thrown for "load" if
* the given record does not exist.
*/
public Object get(Class clz, Serializable id) {
return getHibernateTemplate().get(clz, id);
}
public Object get(Class clz, Serializable id, LockMode lockMode) {
return getHibernateTemplate().get(clz, id, lockMode);
}
...
public void flush() {
getHibernateTemplate().flush();
}
/**
* Retrieve a HB session.
* Make sure to release it after you are done with the session by calling
* releaseHbSession.
*/
public Session getHbSession() {
try {
return getSession();
} catch (Exception e) {
return null;
}
}
/**
* Release a HB Session
*/
public void releaseHbSession(Session sess) {
releaseSession(sess);
}
}
Okay I got it working!
First, I'm using the #Version annotation so I added a version column to the table with the problem.
alter table over_time add version INT(11) DEFAULT 0;
Second, add the Version annotation and member to the Entity class:
public class Overtime implements java.io.Serializable {
private static final long serialVersionUID = 7263309927526074109L;
#Id
#GeneratedValue(generator = "ot_gen")
#GenericGenerator(name = "ot_gen", strategy = "hilo", parameters = {
#Parameter(name = "table", value = "unique_key"), #Parameter(name = "column", value = "next_hi"),
#Parameter(name = "max_lo", value = "99") })
private Integer id;
#Version
#Column(name = "version")
private int version;
...
When I tried this the first couple of times I was using an Integer object not an int primitive for the version member of the class. I THINK this was the issue.
Also make sure that the other hibernate specific annotation is NOT on the entity class:
#org.hibernate.annotations.Entity(dynamicUpdate = true, optimisticLock = OptimisticLockType.ALL)
Third, the exception that gets thrown is not what any of the web sites I've read say it should be, so let's catch the one that really is thrown in the Tapestry page class that handles the user signing up for the overtime record.
void onSignUp(Integer overtimeId) {
// check to see if the OT has been deleted or modified or signed-up
Overtime ot = (Overtime)appService.getById(Overtime.class, overtimeId);
if (ot == null) {
visit.setOneTimeMessage("The overtime has already been deleted.");
return;
}
if (ot.getStatus() != null && ot.getStatus() != AppConst.OT_NEW) {
visit.setOneTimeMessage("The overtime has already been signed up. Please choose a different one to sign up.");
return;
}
...
try {
appService.validateOvertimeForUser(agency, user, ot);
appService.handleSignUpOvertime(agency, user, ot);
// log activity
String what = "Signed up for overtime " + ot.getRefNo() + ".";
appService.logActivity(user, AppConst.LOG_OVERTIME, what);
} catch(HibernateOptimisticLockingFailureException x) {
visit.setOneTimeMessage("The overtime record has been changed by another user, please try again.");
return;
} catch(Exception e) {
visit.setOneTimeMessage(e.getMessage());
return;
}
...