Hibernate自增列保存失败的问题
author: hiu
更正说明:今天(2014-07-07)才发现的问题,我把@Id设置在了实体类中的id中,@Id是主键,应该设置在实体类的keyjobno中,之前发的文章可能误导了大家,如今更正一下,请看以下红色的更正内容。
近期由ibatis转用Hibernate,期间遇到了一系列的问题,今天又遇到了个问题,是由于自增列的问题导致保存时报错,如今记录下来,以便日后忘记时查看
这个问题事实上是使用myEclipse生成表的实体类时,自增列的注解错误导致的。
问题原因:利用myEclipse的Hibernate Reverse Engineening生成的实体类自增列注解设置了在主键keyjobno上,而不是相应的 id 列上
解决的方法 :将自增列注解设置在相应的 自增列id上
数据库employee表:
这里主要列出了部分字段,关键在于id和keyjobno,id设置了是自增列,keyjobno设置为主键
利用myEclipse的Hibernate Reverse Engineening生成实体类
生成后的实体类Employee,仅仅贴出了keyjobno,id的,其他的没贴出来
@Entity @Table(name = "employee", catalog = "union_ssh", uniqueConstraints = @UniqueConstraint(columnNames = "id")) public class Employee implements java.io.Serializable { // Fields private String keyjobno; private Integer id; @Id @GeneratedValue(strategy = IDENTITY) @Column(name = "keyjobno", unique = true, nullable = false, length = 20) public String getKeyjobno() { return this.keyjobno; } public void setKeyjobno(String keyjobno) { this.keyjobno = keyjobno; } @Column(name = "id", unique = true, nullable = false) public Integer getId() { return this.id; } public void setId(Integer id) { this.id = id; } }
service层
public Employee save(Employee employee) throws SQLException { employee.setKeyjobno("K8888"); employeeDao.save(employee); return employee; }
dao层
@Override public Serializable save(T o) { return this.getCurrentSession().save(o); }
控制台打印出的sql语句:
2014-07-04 14:10:50 [org.hibernate.SQL]-[DEBUG] insert into union_ssh.employee (born_boon, borndate, company, createdate, dept, getborn_date, getmarry_date, id, identitycard, ifout, interest, jobno, lodging, marry, marry_boon, name, nativename, operator, phone, politicsface, sex) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) Hibernate: insert into union_ssh.employee (born_boon, borndate, company, createdate, dept, getborn_date, getmarry_date, id, identitycard, ifout, interest, jobno, lodging, marry, marry_boon, name, nativename, operator, phone, politicsface, sex) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) 2014-07-04 14:10:50 [org.hibernate.engine.jdbc.spi.SqlExceptionHelper]-[DEBUG] Field 'keyjobno' doesn't have a default value [n/a] <span style="color:#ff0000;"><strong>java.sql.SQLException: Field 'keyjobno' doesn't have a default value</strong></span>
注意红色部分了,报错说我keyjobno没有默认值,最奇怪的就是这里了,我明明在service层里设置了
employee.setKeyjobno("K8888");
明明已经为keyjobno设置值了,竟然还说我没有默认值。再看一下打出来的sql语句,里面有id,可是没有keyjobno,按理说id在数据库表中设置了自增,这里不应该也插入的,但keyjobno明明是已经设置了值的,却没有显示在插入的sql中,这是由于注解时将keyjobno设置为了自增列了。
如今再来看看实体类中的注解:
@Id @GeneratedValue(strategy = IDENTITY) @Column(name = "keyjobno", unique = true, nullable = false, length = 20) public String getKeyjobno() { return this.keyjobno; }
注解意思:
@Id —— 注解声明了该实体bean的标识属性(相应表中的主键)。
@GeneratedValue —— 注解声明了主键的生成策略。该注解有例如以下属性
strategy
指定生成的策略(JPA定义的),这是一个GenerationType。默认是GenerationType. AUTO
GenerationType.AUTO 主键由程序控制
GenerationType.IDENTITY
主键由数据库自己主动生成(主要是自己主动增长类型)
看到注讲解明,大家应该就明确了,我在数据库表中设置的是id自增列,可是生成的实体类的自增列却是keyjobno,这就是导致保存失败的原因了,将实体类改为下面形式,主要是将keyjobno的自增注解剪切到id列中
@Entity @Table(name = "employee", catalog = "union_ssh", uniqueConstraints = @UniqueConstraint(columnNames = "id")) public class Employee implements java.io.Serializable { private String keyjobno; private Integer id; @Column(name = "keyjobno", unique = true, nullable = false, length = 20) public String getKeyjobno() { return this.keyjobno; } public void setKeyjobno(String keyjobno) { this.keyjobno = keyjobno; } @Id @GeneratedValue(strategy = IDENTITY) @Column(name = "id", unique = true, nullable = false) public Integer getId() { return this.id; } public void setId(Integer id) { this.id = id; } }
@Id设置了在id属性的get方法中,去掉这里的@Id,由于@Id是代表主键,能够看到上面数据库employee表中的图,keyjobno才是主键,所以应该把@Id设置在keyjobno的get方法上才对
@Id @Column(name = "keyjobno", unique = true, nullable = false, length = 20) public String getKeyjobno() { return this.keyjobno; }
假设你不更正这里,在做employee表的单独插入操作时是没问题的,假设你有其他表关联了employee表的keyjobno主键,但你没有将@Id设置在keyjobno上,那么这里问题就来了,假设你往关联的表中插入数据时,就无法插入了,由于关联的表相应不了employee的主键,导致无法插入。我今天用in_union_his表关联了employee表,在做in_union_his表插入操作时,不断提示外键约束失败,无法往子表in_union_his中插入数据
,以下是我今天操作时失败的错误信息:Cannot add or update a child row: a foreign key constraint fails
2014-07-07 10:03:18 [org.hibernate.SQL]-[DEBUG] insert into union_ssh.employee (bornboon, borndate, company, createdate, dept, getborndate, getmarrydate, identitycard, ifout, interest, jobno, keyjobno, lodging, marry, marryboon, name, nativename, operator, phone, politicsface, sex) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) Hibernate: insert into union_ssh.employee (bornboon, borndate, company, createdate, dept, getborndate, getmarrydate, identitycard, ifout, interest, jobno, keyjobno, lodging, marry, marryboon, name, nativename, operator, phone, politicsface, sex) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) 2014-07-07 10:03:18 [org.hibernate.id.IdentifierGeneratorHelper]-[DEBUG] Natively generated identity: 660 2014-07-07 10:03:18 [org.hibernate.engine.spi.ActionQueue]-[DEBUG] Executing identity-insert immediately 2014-07-07 10:03:18 [org.hibernate.SQL]-[DEBUG] insert into union_ssh.in_union_his (createdate, keyjobno, inuniondate, operator) values (?, ?, ?, ?) Hibernate: insert into union_ssh.in_union_his (createdate, keyjobno, inuniondate, operator) values (?, ?, ?, ?) 2014-07-07 10:03:18 [org.hibernate.engine.jdbc.spi.SqlExceptionHelper]-[DEBUG]Cannot add or update a child row: a foreign key constraint fails (`union_ssh`.`in_union_his`, CONSTRAINT `FK_in_union_his` FOREIGN KEY (`keyjobno`) REFERENCES `employee` (`keyjobno`) ON DELETE CASCADE ON UPDATE CASCADE) [n/a] com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Cannot add or update a child row: a foreign key constraint fails (`union_ssh`.`in_union_his`, CONSTRAINT `FK_in_union_his` FOREIGN KEY (`keyjobno`) REFERENCES `employee` (`keyjobno`) ON DELETE CASCADE ON UPDATE CASCADE) at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)仅仅要将@Id设在数据库表主键相应的实体类的属性keyjobno上,就攻克了,关键是我之前把@Id设置在了id属性上。
又一次部署,再运行保存,控制台打印出来的sql语句:
2014-07-04 14:30:21 [org.hibernate.SQL]-[DEBUG] insert into union_ssh.employee (born_boon, borndate, company, createdate, dept, getborn_date, getmarry_date, identitycard, ifout, interest, jobno, keyjobno, lodging, marry, marry_boon, name, nativename, operator, phone, politicsface, sex) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) Hibernate: insert into union_ssh.employee (born_boon, borndate, company, createdate, dept, getborn_date, getmarry_date, identitycard, ifout, interest, jobno, keyjobno, lodging, marry, marry_boon, name, nativename, operator, phone, politicsface, sex) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) 2014-07-04 14:30:21 [org.hibernate.id.IdentifierGeneratorHelper]-[DEBUG] Natively generated identity: 557最后 一行Natively generated identity: 557这句是什么意思呢,事实上557就是插入的这条记录的id了,由于我数据库中已经有556记录了,这就说明保存成功了,大家能够看到,这条sql语句已经没有id存了,也即是说sql语句插入时没有把id插入,而是在数据库中自己主动添加�了。今天(2014-07-07)再经过測试,发现,这里显示不显示id出来都能够插入成功,不显示的原因是由于我之前把注解@Id,@GeneratedValue(strategy = IDENTITY)设在了id列中才没显示出来,我预计是仅仅要你注解设置在自增列而且自增列是主键时,就在插入时sql语句不显示这个列了
总结:注解地方的错误是由于使用myEclipse生成实体类时引致的注解设置地方错误,所以有时也不要太过依赖自己主动生成实体类。个人推測原因,是由于我将id设为是自增的,但keyjobno列设置为主键,也即是说,这两列都是唯一的,myEclipse在生成实体类是可能不能区分,就将自增列的注解设置了在主键的列上了,没细致研究,大家有兴趣的话,能够去研究下。