数据库中存在一个email字段,并允许其中存储多个email地址,各地址之间使用 ; 分割,但是在POJO中,为了便于处理,email定义为一个List对象。
如何将String字段映射为List类型,Hibernate并没有提供原生支持,需要我们实现自己的UserType。
1.数据库定义
DROP TABLE t_user; CREATE TABLE t_user ( id INT NOT NULL AUTO_INCREMENT , name VARCHAR ( 50 ) , age INT , email VARCHAR ( 300 ) , PRIMARY KEY (id) );
2.实现了UserType的自定义数据类型类EmailList
package tuser; import java.io.Serializable; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Types; import java.util.ArrayList; import java.util.List; import org.hibernate.Hibernate; import org.hibernate.HibernateException; import org.hibernate.usertype.UserType; public class EmailList implements UserType { private static final char SPLITTER = ';'; private static final int[] TYPES = new int[]{Types.VARCHAR}; @Override public int[] sqlTypes() { return TYPES; } @Override public Class returnedClass() { return List.class; } @Override public boolean equals(Object x, Object y) throws HibernateException { if(x == y){ return true; } if(x != null && y != null){ List xList = (List)x; List yList = (List)y; if(xList.size() != yList.size()){ return false; } for(int index = 0; index < xList.size(); index++){ String str1 = (String) xList.get(index); String str2 = (String) yList.get(index); if(str1 != str2){ return false; } } return true; } return false; } @Override public Object nullSafeGet(ResultSet rs, String[] names, Object owner) throws HibernateException, SQLException { String value = Hibernate.STRING.nullSafeGet(rs, names[0]); if(value != null){ return parse(value); }else{ return null; } } @Override public void nullSafeSet(PreparedStatement st, Object value, int index) throws HibernateException, SQLException { System.out.println("Set method executed"); if(value != null){ String str = assemble((List)value); Hibernate.STRING.nullSafeSet(st, str, index); }else{ Hibernate.STRING.nullSafeSet(st, null, index); } } @Override public Object deepCopy(Object value) throws HibernateException { List sourceList = (List)value; List targetList = new ArrayList(); targetList.addAll(sourceList); return targetList; } @Override public boolean isMutable() { return false; } /** * 将String拼装为一个字符串,以“;”分隔 * @param emailList * @return */ private String assemble(List emailList){ StringBuffer strBuf = new StringBuffer(); for(int i = 0; i < emailList.size() - 1; i++){ strBuf.append(emailList.get(i)).append(SPLITTER); } strBuf.append(emailList.get(emailList.size() - 1)); return strBuf.toString(); } /** * 将以“;”分隔的字符串解析为一个字符串数组 * @param value * @return */ private List parse(String value){ String[] strs = value.split(SPLITTER + ""); List emailList = new ArrayList(); for(int i = 0; i < strs.length; i++){ emailList.add(strs[i]); } return emailList; } @Override public Object assemble(Serializable arg0, Object arg1) throws HibernateException { return null; } @Override public Serializable disassemble(Object arg0) throws HibernateException { return null; } @Override public int hashCode(Object arg0) throws HibernateException { return 0; } @Override public Object replace(Object arg0, Object arg1, Object arg2) throws HibernateException { return null; } }
3.配置文件TUser.hbm.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="tuser.TUser" table="T_USER">
<id name="id" type="java.lang.Integer">
<column name="ID"/>
<generator class="native"></generator>
</id>
<property name="name" type="java.lang.String">
<column name="NAME"/>
</property>
<property name="age" type="java.lang.String">
<column name="AGE"/>
</property>
<property name="email" type="tuser.EmailList">
<column name="EMAIL"/>
</property>
</class>
</hibernate-mapping>
4.在hibernate.cfg.xml载入TUser.hbm.xml
<?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="connection.driver_class">
com.mysql.jdbc.Driver
</property>
<property name="connection.url">
jdbc:mysql://localhost:3306/hibernate
</property>
<property name="connection.username">
root
</property>
<property name="connection.password">
system
</property>
<property name="dialect">
org.hibernate.dialect.MySQLDialect
</property>
<property name="javax.persistence.validation.mode">
none
</property>
<property name="c3p0.min_size">5</property>
<property name="c3p0.max_size">20</property>
<property name="c3p0.timeout">300</property>
<property name="c3p0.max_statements">50</property>
<property name="c3p0.idle_test_period">3000</property>
<property name="show_sql">false</property>
<property name="format_sql">false</property>
<mapping resource="hello/Message.hbm.xml"/>
<mapping resource="user/User.hbm.xml"/>
<mapping resource="tuser/TUser.hbm.xml"/>
</session-factory>
</hibernate-configuration>
5.测试类HibernateTest.java
package test; import java.util.ArrayList; import java.util.List; import junit.framework.TestCase; import org.hibernate.HibernateException; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Ignore; import org.junit.Test; import tuser.TUser; import user.User; public class HibernateTest extends TestCase { Session session = null; @Before protected void setUp() throws Exception { try { Configuration configure = new Configuration().configure(); SessionFactory sessionFactory = configure.buildSessionFactory(); session = sessionFactory.openSession(); } catch (HibernateException e) { e.printStackTrace(); } } @After protected void tearDown() throws Exception { try { session.close(); } catch (HibernateException e) { e.printStackTrace(); } } @Test public void testTUser(){ Transaction tran = null; try { tran = session.beginTransaction(); TUser user = new TUser(); user.setName("byf"); List list = new ArrayList(); list.add("[email protected]"); list.add("[email protected]"); user.setEmail(list); session.save(user); session.flush(); tran.commit(); Assert.assertEquals(user.getId().intValue()>0 ,true); } catch (HibernateException e) { e.printStackTrace(); Assert.fail(e.getMessage()); if(tran != null) { try { tran.rollback(); } catch (Exception e1) { e1.printStackTrace(); } } } } /** * 对象读取测试(Select方法) */ public void testSelect(){ String hql = " from TUser where name='byf'"; try { List userList = session.createQuery(hql).list(); TUser user = (TUser)userList.get(0); List mailList = user.getEmail(); Assert.assertEquals((String)mailList.get(0), "[email protected]"); Assert.assertEquals((String)mailList.get(1), "[email protected]"); } catch (Exception e) { e.printStackTrace(); Assert.fail(e.getMessage()); } } }
6.TUser类
package tuser; import java.io.Serializable; import java.util.List; public class TUser implements Serializable { private static final long serialVersionUID = 1901560971512450430L; private Integer id; private String name; private Integer age; private List email; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public List getEmail() { return email; } public void setEmail(List email) { this.email = email; } }
运行测试代码,观察数据库中,可以发现email地址信息已经以";"分隔的形式保存。同时,在数据读取时,我们也无需面对原始的";"分隔字符串,转而只需要处理List类型数据即可。