本文首发于 http://www.YoungZY.com/
从 Hibernate 3 升级到 Hibernate 4 ,出现了这样的错误:
1 2 3 4 5 6 |
org.hibernate.id.IdentifierGenerationException: Unknown integral data type for ids : java.lang.String at org.hibernate.id.IdentifierGeneratorHelper.getIntegralDataTypeHolder(IdentifierGeneratorHelper.java:215) at org.hibernate.id.SequenceGenerator.buildHolder(SequenceGenerator.java:150) at org.hibernate.id.SequenceGenerator.generateHolder(SequenceGenerator.java:126) at org.hibernate.id.SequenceGenerator.generate(SequenceGenerator.java:116) at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:118) |
原来,在 Hibernate 4 中如果主键的生成策略是 Sequence ,则要求数据库中对应的字段必须为数字(Number,Long 等)类型。
而当前系统中使用的是字符串类型,所以报错了。
网上参考了几篇文章,就一篇(见文末)还不错。在此基础上,覆写了部分方法,解决了问题。
首先是 HISequenceGenerator 类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
package org.young.hibernate.common; import java.io.Serializable; import org.hibernate.engine.spi.SessionImplementor; import org.hibernate.id.IntegralDataTypeHolder; import org.hibernate.id.SequenceGenerator; /** * 继承 hibernate 里的 SequenceGenerator 类, * 覆写2个方法: * 1. buildHolder() * 2. generate(SessionImplementor session, Object obj) * * @author by youngz * on 2016年7月24日 * * Package&FileName: org.young.hibernate.common.HISequenceGenerator */ public class HISequenceGenerator extends SequenceGenerator { @Override public Serializable generate(SessionImplementor session, Object obj) { /* * 源码 * * return generateHolder(session).makeValue(); */ // Serializable id = generateHolder(session).makeValue(); Number id = generateHolder(session).makeValue(); /* * 笔者曾自作聪明地以为可以省掉这一步, * 继而这个方法就不用覆写,毕竟都是 Serializable , * 不管是数字(Number)还是字符串(String) * * 但返回值却需要确定到String,因为Java类(hbm对象)的属性是String类型的 * 而 makeValue() 返回的 Number (这里的实际类型是 Long) * * 所以 id 的类型直接定义成 Number (更直观), * 而不是 Serializable */ if (getIdentifierType().getReturnedClass() == String.class){ //增加对String的判断 return id.toString(); } return id; } @Override protected IntegralDataTypeHolder buildHolder() { /* * 源码 * * return IdentifierGeneratorHelper.getIntegralDataTypeHolder(this.identifierType.getReturnedClass()); */ return HIIdentifierGeneratorHelper .getIntegralDataTypeHolder(getIdentifierType() .getReturnedClass()); } } |
还有一个辅助类 HIIdentifierGeneratorHelper
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 |
package org.young.hibernate.common; import java.math.BigDecimal; import java.math.BigInteger; import org.hibernate.id.IdentifierGenerationException; import org.hibernate.id.IdentifierGeneratorHelper; import org.hibernate.id.IntegralDataTypeHolder; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; /** * IdentifierGeneratorHelper ,final 类,不可继承 * * @author by youngz * on 2016年7月24日 * * Package&FileName: org.young.hibernate.common.HIIdentifierGeneratorHelper */ public class HIIdentifierGeneratorHelper { public static IntegralDataTypeHolder getIntegralDataTypeHolder( Class integralType) { if ((integralType == Long.class) || (integralType == Integer.class) || (integralType == Short.class) // 增加对String的判断 || (integralType == String.class)) { return new HIBasicHolder(integralType); } if (integralType == BigInteger.class) return new IdentifierGeneratorHelper.BigIntegerHolder(); if (integralType == BigDecimal.class) { return new IdentifierGeneratorHelper.BigDecimalHolder(); } throw new IdentifierGenerationException( "Unknown integral data type for ids : " + integralType.getName()); } public static class HIBasicHolder implements IntegralDataTypeHolder { private final Class exactType; private long value = 0L; public HIBasicHolder(Class exactType) { this.exactType = exactType; if ((exactType != Long.class) && (exactType != Integer.class) && (exactType != Short.class) // 增加对String的判断 && (exactType != String.class) ) throw new IdentifierGenerationException( "Invalid type for basic integral holder : " + exactType); } public long getActualLongValue() { return this.value; } public IntegralDataTypeHolder initialize(long value) { this.value = value; return this; } public IntegralDataTypeHolder initialize(ResultSet resultSet, long defaultValue) throws SQLException { long value = resultSet.getLong(1); if (resultSet.wasNull()) value = defaultValue; return initialize(value); } public void bind(PreparedStatement preparedStatement, int position) throws SQLException { preparedStatement.setLong(position, this.value); } public IntegralDataTypeHolder increment() { checkInitialized(); this.value += 1L; return this; } private void checkInitialized() { if (this.value == 0L) throw new IdentifierGenerationException( "integral holder was not initialized"); } public IntegralDataTypeHolder add(long addend) { checkInitialized(); this.value += addend; return this; } public IntegralDataTypeHolder decrement() { checkInitialized(); this.value -= 1L; return this; } public IntegralDataTypeHolder subtract(long subtrahend) { checkInitialized(); this.value -= subtrahend; return this; } public IntegralDataTypeHolder multiplyBy(IntegralDataTypeHolder factor) { return multiplyBy(IdentifierGeneratorHelper.extractLong(factor)); } public IntegralDataTypeHolder multiplyBy(long factor) { checkInitialized(); this.value *= factor; return this; } public boolean eq(IntegralDataTypeHolder other) { return eq(IdentifierGeneratorHelper.extractLong(other)); } public boolean eq(long value) { checkInitialized(); return (this.value == value); } public boolean lt(IntegralDataTypeHolder other) { return lt(IdentifierGeneratorHelper.extractLong(other)); } public boolean lt(long value) { checkInitialized(); return (this.value < value); } public boolean gt(IntegralDataTypeHolder other) { return gt(IdentifierGeneratorHelper.extractLong(other)); } public boolean gt(long value) { checkInitialized(); return (this.value > value); } public IntegralDataTypeHolder copy() { HIBasicHolder copy = new HIBasicHolder(this.exactType); copy.value = this.value; return copy; } public Number makeValue() { checkInitialized(); if (this.exactType == Long.class) return Long.valueOf(this.value); // 增加对String的判断 if (this.exactType == String.class) { return Long.valueOf(this.value); } if (this.exactType == Integer.class) { return Integer.valueOf((int) this.value); } return Short.valueOf((short) (int) this.value); } public Number makeValueThenIncrement() { Number result = makeValue(); this.value += 1L; return result; } public Number makeValueThenAdd(long addend) { Number result = makeValue(); this.value += addend; return result; } public String toString() { return "BasicHolder[" + this.exactType.getName() + "[" + this.value + "]]"; } public boolean equals(Object o) { if (this == o) return true; if ((o == null) || (super.getClass() != o.getClass())) { return false; } HIBasicHolder that = (HIBasicHolder) o; return (this.value == that.value); } public int hashCode() { return (int) (this.value ^ this.value >>> 32); } } } |
最后,修改 hibernate 配置文件里的主键生成策略
1 2 3 4 5 6 7 |
<id name="id" type="java.lang.String"> <column name="ID" length="20" /> <!-- 此处的 class 即刚刚新建的 Generator --> <generator class="org.young.hibernate.common.HISequenceGenerator" > <param name="sequence">SEQ_ID</param> </generator> </id> |
本文的实验是在
hibernate-core-4.1.8.Final.jar
基础上完成。可至 GitHub 上查看相关代码。
参考:
http://my.oschina.net/liyuj/blog/386582?fromerr=4h5OjIKZ
加入讨论