Hibernate高级照射技术(一)自定义数据类型StringList (转)
核心提示:我们在设计数据库时往往会遇到例如用户的多个手机号码的一对多问题,如果设计一个T_MOBILE表保存未免太大动干戈而且影响速度,所以如果没有严格的要求,一般情况我们在T_USER表里设计一个 mobiles字段,其中的多个手机号码用;分隔。尽管这样不符合数据库范式
我们在设计数据库时往往会遇到例如用户的多个手机号码的一对多问题,如果设计一个T_MOBILE表保存未免太大动干戈而且影响速度,所以如果没有严格的要求,一般情况我们在T_USER表里设计一个mobiles字段,其中的多个手机号码用;分隔。尽管这样不符合数据库范式的设计原则,但在性能和编码复杂度上确实最低的。
这样如果用Hibernate的String类型来映射,就会得到一个长字符串,每次必须按;分隔后才能使用,这样代码就很冗余。
幸好Hibernate有自定义数据类型的支持,只要实现UserType或CompositeUserType接口。不过这两个接口的内容比较复杂,有很多方法需要实现,不能偷懒哦:-)
下面是我对于用;分隔的字段的自定义数据类型的实现。
1. package com.willishz.framework.dao.usertype;
2.
3. import java.io.Serializable;
4. import java.sql.PreparedStatement;
5. import java.sql.ResultSet;
6. import java.sql.SQLException;
7. import java.sql.Types;
8. import java.util.ArrayList;
9. import java.util.List;
10.
11. import org.hibernate.Hibernate;
12. import org.hibernate.HibernateException;
13. import org.hibernate.usertype.UserType;
14.
15. /**
16. * 用分隔符分隔的字符串数组.分隔符默认为";"
17. * @author willishz
18. */
19. public class StringList implements UserType, Serializable {
20.
21. public StringList() {
22. super();
23. }
24.
25. public StringList(char splitter) {
26. super();
27. this.splitter = splitter;
28. }
29.
30. public StringList(List<String> attributeList) {
31. super();
32. this.attributeList = attributeList;
33. }
34.
35. private List<String> attributeList;
36.
37. /**
38. * 分隔符
39. */
40. private char splitter = SPLITTER;
41.
42. /**
43. * 分隔符默认为";"
44. */
45. private static final char SPLITTER = ';';
46.
47. private static final int[] SQLTYPES = new int[] { Types.VARCHAR };
48.
49. public boolean isMutable() {
50. return false;
51. }
52.
53. public int[] sqlTypes() {
54. return SQLTYPES;
55. }
56.
57. public Object assemble(Serializable id, Object obj) throws HibernateException {
58. return null;
59. }
60.
61. /**
62. * 将List类型的数组拼接成字符串
63. * @param attributeList
64. * @return
65. * @throws HibernateException
66. */
67. public Object assemble(List<String> attributeList) throws HibernateException {
68. if (attributeList == null) {
69. return null;
70. }
71. StringBuffer asbl = new StringBuffer();
72. asbl.append(attributeList.get(0));
73. for (int i = 1; i < attributeList.size(); i++) {
74. asbl.append(splitter).append(attributeList.get(i));
75. }
76. return asbl.toString();
77. }
78.
79. /**
80. * 自定义类型的完全复制方法,返回一个和原自定义数据相同的新对象
81. *
82. * @param value the object to be cloned, which may be null
83. * @return Object a copy
84. * @see org.hibernate.usertype.UserType#deepCopy(java.lang.Object)
85. */
86. public Object deepCopy(Object value) throws HibernateException {
87. if (value == null) {
88. return null;
89. }
90. ArrayList sourceList = (ArrayList) value;
91. ArrayList targetList = new ArrayList();
92. List<String> _attributeList = new ArrayList<String>();
93. targetList.addAll(sourceList);
94. return targetList;
95. }
96.
97. /**
98. * 自定义数据类型的比较方法
99. *
100. * @param x
101. * @param y
102. * @return boolean
103. * @see org.hibernate.usertype.UserType#equals(java.lang.Object, java.lang.Object)
104. */
105. public boolean equals(Object x, Object y) throws HibernateException {
106. if (x == y) {
107. return true;
108. }
109. if (x != null && y != null) {
110. List<String> xList = (List<String>) x;
111. List<String> yList = (List<String>) y;
112. if (xList.size() != yList.size()) {
113. return false;
114. }
115. String _x = null;
116. String _y = null;
117. for (int i = 0; i < xList.size(); i++) {
118. _x = xList.get(i);
119. _y = yList.get(i);
120. if (!_x.equalsIgnoreCase(_y)) { // case insensitive
121. return false;
122. }
123. }
124. return true;
125. }
126. return false;
127. }
128.
129. public int hashCode(Object arg0) throws HibernateException {
130. return attributeList.hashCode();
131. }
132.
133. /**
134. * 将以分隔符分隔的字符串解析成一个字符串数组
135. *
136. * @param value
137. * @return
138. */
139. public List<String> parse(String value) {
140. if (value == null) {
141. return null;
142. }
143. String[] strs = org.apache.commons.lang.StringUtils.split(value, splitter);
144. List<String> attributeList = new ArrayList<String>();
145. for (int i = 0; i < strs.length; i++) {
146. attributeList.add(strs[i]);
147. }
148. return attributeList;
149. }
150.
151. /**
152. * 从JDBC的ResultSet中读取数据,并将其转换为自定义类型后返回。
153. * 此方法要求对可能出现null的情况做处理。
154. * names中包含了当前自定义类型的映射字段名称。
155. *
156. * @param rs a JDBC result set
157. * @param names the column names
158. * @param owner the containing entity
159. * @return Object
160. * @throws HibernateException
161. * @throws SQLException
162. * @see org.hibernate.usertype.UserType#nullSafeGet(java.sql.ResultSet, java.lang.String[], java.lang.Object)
163. */
164. public Object nullSafeGet(ResultSet rs, String[] names, Object owner)
165. throws HibernateException, SQLException {
166. String value = (String) Hibernate.STRING.nullSafeGet(rs, names[0]);
167. if (value != null) {
168. return parse(value);
169. }
170. return null;
171. }
172.
173. /**
174. * 在Hibernate进行数据保存时被调用
175. * 可以通过PreparedStatement将自定义数据写入对应的数据库字段中
176. * names中包含了当前自定义类型的映射字段名称。
177. *
178. * @param st a JDBC prepared statement
179. * @param value the object to write
180. * @param index statement parameter index
181. * @throws HibernateException
182. * @throws SQLException
183. * @see org.hibernate.usertype.UserType#nullSafeGet(java.sql.ResultSet, java.lang.String[], java.lang.Object)
184. */
185. public void nullSafeSet(PreparedStatement pst, Object value, int index)
186. throws HibernateException, SQLException {
187. if (value != null) {
188. Hibernate.STRING.nullSafeSet(pst, assemble((List<String>) value), index);
189. } else {
190. Hibernate.STRING.nullSafeSet(pst, value, index);
191. }
192. }
193.
194. public Class returnedClass() {
195. return StringList.class;
196. }
197.
198. public Object replace(Object arg0, Object arg1, Object arg2) throws HibernateException {
199. return null;
200. }
201.
202. public Serializable disassemble(Object arg0) throws HibernateException {
203. return null;
204. }
205. }
Hibernate配置文件的相关内容如下:
1. <?xml version="1.0"?>
2. <!DOCTYPE hibernate-mapping PUBLIC
3. "-//Hibernate/Hibernate Mapping DTD//EN"
4. "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >
5.
6. <hibernate-mapping package="com.willishz.apocalypse.ebid.domain">
7. <class
8. name="User"
9. table="t_user"
10. >
11. .................
12. <property
13. name="mobiles"
14. column="mobiles"
15. type="com.willishz.framework.dao.usertype.StringList"
16. not-null="false"
17. length="100"
18. />
19. .................
20. </class>
21. </hibernate-mapping>
Hibernate映射实体文件的相关内容:
1. package com.willishz.apocalypse.ebid.domain.base;
2.
3. import java.io.Serializable;
4.
5. public abstract class User implements Serializable {
6. .................
7.
8. private java.util.List<String> mobiles;
9.
10. public java.util.List<String> getMobiles() {
11. return mobiles;
12. }
13.
14. public void setmobiles(java.util.List<String> mobiles) {
15. this.mobiles = mobiles;
16. }
17. .................
18. }