从 Hibernate 3 升级到 Hibernate 4 序列号(Sequence)不能用 String 了?(已解决)

从 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

 

加入讨论

您的电子邮箱地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据