• Hibernate中的自己定义类型——UserType、CompositeUserType


    一、UserType

    Hibernate拥有自己定义映射表属性的机制。主要通过实现接口UserType,详细的UserType:

    import java.sql.PreparedStatement;     
    import java.sql.ResultSet;     
    import java.sql.SQLException;     
         
    import net.sf.hibernate.HibernateException;     
         
    /**   
     * @author hy-he   
     *   
     */     
    public interface UserType {     
         
     /**   
      * 返回UserType所映射字段的SQL类型(java.sql.Types)   
      * 返回类型为int[],当中包括了映射个字段的SQL类型代码   
      * (UserType能够映射到一个或者多个字段)   
      * @return   
      */     
     public int[]sqlTypes();     
         
         
     /**   
      * UserType.nullSafeGet()所返回的自己定义数据类型   
      * @return   
      */     
     public Class returnedClass();     
         
         
     /**   
      * 自己定义数据类型的比对方法   
      * 此方法将用作脏数据检查。參数x、y分别为数据的两个副本   
      * 假设equals方法返回false,则Hibernate将觉得数据发生变化,并将变化更新到数据库表中   
      * @param x   
      * @param y   
      * @return   
      * @throws HibernateException   
      */     
     public boolean equals(Object x,Object y)throws HibernateException;     
         
         
     /**   
      * 从JDBC ResultSet读取数据,将其转换为自己定义类型后返回   
      * (此方法要求对克能出现null值进行处理)   
      * names中包括了当前自己定义类型的映射字段名称   
      * @param rs   
      * @param names   
      * @param owner   
      * @return   
      * @throws HibernateException   
      * @throws SQLException   
      */     
     public Object nullSafeGet(ResultSet rs,String[] names,Object owner)throws HibernateException,SQLException;     
         
         
     /**   
      * 本方法将在Hibernate进行数据保存时被调用   
      * 我们能够通过PreparedStateme将自己定义数据写入到相应的数据库表字段   
      * @param st   
      * @param value   
      * @param index   
      * @throws HibernateException   
      * @throws SQLException   
      */     
     public void nullSafeSet(PreparedStatement st,Object value,int index)throws HibernateException,SQLException;     
         
         
     /**   
      * 提供自己定义类型的全然复制方法   
      * 本方法将用构造返回对象   
      * 当nullSafeGet方法调用之后,我们获得了自己定义数据对象。在向用户返回自己定义数据之前,   
      * deepCopy方法将被调用。它将根据自己定义数据对象构造一个全然拷贝。并将此拷贝返回给用户   
      * 此时我们就得到了自己定义数据对象的两个版本号,第一个是从数据库读出的原始版本号。其二是我们通过   
      * deepCopy方法构造的复制版本号,原始的版本号将有Hibernate维护,复制版由用户使用。原始版本号用作   
      * 稍后的脏数据检查根据;Hibernate将在脏数据检查过程中将两个版本号的数据进行对照(通过调用   
      * equals方法)。假设数据发生了变化(equals方法返回false),则运行相应的持久化操作   
      *   
      * @param value   
      * @return   
      * @throws HibernateException   
      */     
     public Object deppCopy(Object value)throws HibernateException;     
         
         
     /**   
      * 本类型实例是否可变   
      * @return   
      */     
     public boolean isMutable();     
    }     
    样例:一个学生有联系地址。而联系地址又分为家庭地址和工作地址,我们能够把两个地址信息抽象成一个新的Address类。作为Student的成员变量。

    数据库结构:

     

    create table typestu (id varchar(32primary key,name varchar(32),homeaddr varchar(32),workaddr varchar(32));

    Hibernate.cfg.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"
    >

    <!-- Generated by MyEclipse Hibernate Tools.                   -->
    <hibernate-configuration>

    <session-factory>
        
    <property name="connection.username">root</property>
        
    <property name="connection.url">
            jdbc:mysql://localhost:3306/schoolproject?characterEncoding=gb2312
    &amp;useUnicode=true
        
    </property>
        
    <property name="dialect">
            org.hibernate.dialect.MySQLDialect
        
    </property>
        
    <property name="myeclipse.connection.profile">mysql</property>
        
    <property name="connection.password">1234</property>
        
    <property name="connection.driver_class">
            com.mysql.jdbc.Driver
        
    </property>
        
    <property name="hibernate.dialect">
            org.hibernate.dialect.MySQLDialect
        
    </property>
        
    <property name="hibernate.show_sql">true</property>
        
    <property name="current_session_context_class">thread</property>
        
    <mapping resource="Search/UserType/Student.hbm.xml" />

    </session-factory>

    </hibernate-configuration>

     Pojo

     

    package Search.UserType;


    public class Student {
        
    private String id; //标识id
        private String name; //学生姓名
        private AddressType address;//地址
        public String getId() {
            
    return id;
        }

        
    public void setId(String id) {
            
    this.id = id;
        }

        
    public String getName() {
            
    return name;
        }

        
    public void setName(String name) {
            
    this.name = name;
        }

        
    public AddressType getAddress() {
            
    return address;
        }

        
    public void setAddress(AddressType address) {
            
    this.address = address;
        }


     
     
     
    }

     

    自己定义类型

     


    package Search.UserType;

    import java.io.Serializable;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.sql.Types;

    import org.apache.commons.lang.builder.EqualsBuilder;
    import org.apache.commons.lang.builder.HashCodeBuilder;
    import org.hibernate.HibernateException;
    import org.hibernate.usertype.UserType;

    public class AddressType implements UserType, Serializable {
        
    private String homeAddr;
        
    private String workAddr;

        
    /* 有几个字段就有几个值,这里easy出错。要多注意 */
        
    private static final int[] SQL_TYPES = { Types.VARCHAR, Types.VARCHAR };

        
    /* 这种方法告诉Hibernate在成生DDL时对列採用什么样的SQL语法 */
        
    public int[] sqlTypes() {
            
    return SQL_TYPES;
        }


        
    /*
         * Hibernate返回什么样的映射类型。与 <property name="address" type="model.AddressType">
         * 指定的类一致。其实也能够把AddressType拆分为两个类,一个类是仅仅携带信息的JavaBean,它里面
         * 没有逻辑操作也没有实现UserType(比方AddressBean)。而还有一个类实现了UserType。它所面对的就不是如今这个
         * AddressType类的homeAddr和homeAddr属性,它面对的是AddressBean。在本例中为了简洁方便。仅仅用了一个类。


         */
        
    public Class returnedClass() {
            
    return AddressType.class;
        }


        
    /*
         * 表明这个类的实例在创建以后就不能够改变属性。Hibernate能为不可改变的类作一些性能优化。
         
    */

        
    public boolean isMutable() {
            
    return false;
        }


        
    /*
         * 因为AddressType是不可变的,所以深拷贝能够直接返回对象引用。

    拷贝的对象由应用程序使用。 而原版对象由Hibernate维护以做脏数据检查
         */
        
    public Object deepCopy(Object value) {
            
    return value; // Address is immutable
        }


        
    /* 两个对象是否相等,使用了apache的common工具包来进行属性比对 */
        
    public boolean equals(Object x, Object y) {
            
    if (x == y)
                
    return true;
            
    if (x == null || y == null)
                
    return false;
            AddressType add1 
    = (AddressType) x;
            AddressType add2 
    = (AddressType) y;
            
    return new EqualsBuilder() //使用EqualsBuilder类来方便地进行比对
                    .append(add1.getHomeAddr(), add2.getHomeAddr()).append(
                            add2.getWorkAddr(), add2.getWorkAddr()).isEquals();
        }


        
    /* 得到hash码 */

        
    public int hashCode(Object x) throws HibernateException {
            AddressType address 
    = (AddressType) x;
            
    return new HashCodeBuilder()//使用HashCodeBuilder类来方便地进行比对
                    .append(address.getHomeAddr()).append(address.getWorkAddr())
                    .toHashCode();
        }


        
    /* 读取数据并组装成一个AddressType对象。

    names[]中的參数顺序按照映射文件里定义的顺序 */
        
    public Object nullSafeGet(ResultSet rs, String[] names, Object owner)
                
    throws HibernateException, SQLException {
            
    if (rs.wasNull())
                
    return null;
            String homeAddr 
    = rs.getString(names[0]);
            String schoolAddr 
    = rs.getString(names[1]);
            AddressType address 
    = new AddressType(homeAddr, schoolAddr);
            
    return address;
        }


        
    /* 保存数据。index的顺序依照映射文件定义的顺序。从0開始。 */
        
    public void nullSafeSet(PreparedStatement st, Object value, int index)
                
    throws HibernateException, SQLException {
            AddressType address 
    = (AddressType) value;
            
    if (value == null{
                  st.setNull(index, Types.VARCHAR);
                  st.setNull(index
    +1, Types.VARCHAR);
            }
     else {
                st.setString(index, address.getHomeAddr());
                st.setString(index 
    + 1, address.getWorkAddr());
            }

             System.out.println(
    "Data has been saved! ");
        }


        
    /* 当把AddressType类型数据写入二级缓存时,此方法被调用 */
        
    public Serializable disassemble(Object value) throws HibernateException {
            
    return null;
        }


        
    /* 当从二级缓存中读取AddressType类型数据时。此方法被调用 */
        
    public Object assemble(Serializable cached, Object owner)
                
    throws HibernateException {
            
    // TODO 自己主动生成方法存根
            return null;
        }


        
    public Object replace(Object original, Object target, Object owner)
                
    throws HibernateException {
            
    // TODO 自己主动生成方法存根
            return null;
        }


        
    public AddressType() {
            
    super();
        }


        
    public AddressType(String homeAddr, String workAddr) {
            
    super();
            
    this.homeAddr = homeAddr;
            
    this.workAddr = workAddr;
        }


        
    /**
         * 
    @return 返回 sQL_TYPES。
         
    */

        
    public static int[] getSQL_TYPES() {
            
    return SQL_TYPES;
        }


        
    /**
         * 
    @return 返回 homeAddr。


         */
        
    public String getHomeAddr() {
            
    return homeAddr;
        }


        
    /**
         * 
    @param homeAddr
         *            要设置的 homeAddr。
         
    */

        
    private void setHomeAddr(String homeAddr) {
            
    this.homeAddr = homeAddr;
        }


        
    private String getWorkAddr() {
            
    return workAddr;
        }


        
    private void setWorkAddr(String workAddr) {
            
    this.workAddr = workAddr;
        }






    }

     

    Student.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"
    >
    <!-- 
        Mapping file autogenerated by MyEclipse - Hibernate Tools
    -->
    <hibernate-mapping>
        
    <class name="Search.UserType.Student" table="typestu" lazy="false">
            
    <id name="id" unsaved-value="null" type="string" column="id">
                
    <generator class="uuid.hex" />
            
    </id>
            
    <property name="name" type="string" />
            
    <property name="address" type="Search.UserType.AddressType">
                
    <column name="homeaddr"/>
                
    <column name="workaddr"/>
            
    </property>
        
    </class>
    </hibernate-mapping>

     

    測试代码:

     

    package Search.UserType;

    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.IOException;
    import java.sql.Blob;
    import java.sql.Clob;

    import org.hibernate.Hibernate;
    import org.hibernate.Session;
    import org.hibernate.SessionFactory;
    import org.hibernate.Transaction;
    import org.hibernate.cfg.Configuration;

    public class Test {


        
    public static void main(String[] args) {
            String filePath
    =System.getProperty("user.dir")+File.separator+"src/Search/UserType"+File.separator+"hibernate.cfg.xml";
            File file
    =new File(filePath);
            SessionFactory sessionFactory
    =new Configuration().configure(file).buildSessionFactory();
            Session session
    =sessionFactory.openSession();
            Transaction tx
    =session.beginTransaction();
            AddressType address
    =new AddressType("home","work");
            Student stu
    =new Student();
            stu.setName(
    "tome1");
            stu.setAddress(address);
            session.save(stu);
            tx.commit();
            
            

        }


    }


    二、CompositeUserType

    CompositeUserType拥有UserType全部的接口,并提供了更加丰富的功能。能够实现更加复杂的功能。

    待续...

  • 相关阅读:
    贪吃蛇 666
    安装postgresql
    linux CentOS6.5 yum安装mysql 5.6
    centos--git搭建之Gogs安装
    查看mysql 默认端口号和修改端口号
    centos之mysql安装配置使用
    流媒体服务器SRS部署
    vue用webpack打包时引入es2015插件
    log4j2的log输出到tomcat/logs目录下及使用(转)
    log4j2的配置文件log4j2.xml笔记
  • 原文地址:https://www.cnblogs.com/clnchanpin/p/7159115.html
Copyright © 2020-2023  润新知