Hibernate_5

Hibernate映射类型分为两种:内置映射类型和客户化映射类型。内置映射类型负责把一些常见的java类型映射到相应的SQL类型;此外,Hibernate还允许用户实现UserType或CompositeUserType接口,来灵活定制客户化映射类型。客户化映射类型能够把用户定义的java类型映射到数据库表的相应字段。

Java基本类型的Hibernate映射类型
Hibernate映射类型         Java类型          标准SQL类型     大小和取值范围
integer或int    int或java.lang.Integer    INTEGER   4字节,-2^31~2^31-1
long           long或java.lang.Long       BIGINT    8字节,-2^63~2^63-1
short          short或java.lang.Short     SMALLINT  2字节,-2^15~2^15-1
byte           byte或java.lang.Byte       TINYINT   1字节,-128^127
float          float或java.lang.Float     FLOAT     4字节,单精度浮点数
double         double或java.lang.Double   DOUBLE    8字节,双精度浮点数
character      char或java.lang.Character/String CHAR   定长字符
string         java.lang.String           Varchar      变长字符串
boolean        boolean或java.lang.Boolean  BIT         布尔类型
yes_no         boolean或java.lang.Boolean  CHAR(1)('Y'/'N') 布尔类型
true_false     boolean或java.lang.Boolean  CHAR(1)('T'/'F') 布尔类型

Hibernate映射类型、对应的Java时间和日期类型及对应的标准SQL
映射类型          Java类型                  标准SQL类型           描述
date      java.util.Date或java.sql.Date   DATE     代表日期  YYYY-MM-DD
time      java.util.Date或java.sql.Time   TIME     代表时间  HH:MM:SS
timestamp java.util.Date或java.sql.Timestamp TIMESTAMP  YYYYMMDDHHMMSS
celendar  java.util.Calender            TIMESTAMP   YYYYMMDDHHMMSS
calendar_date java.util.Calender          DATE     代表日期  YYYY-MM-DD

Hibernate映射类型、对应的Java大对象类型及对应的标准SQL
映射类型         Java类型        标准SQL类型     MYSQL类型    Oracle类型     
binary         byte[]     VARBINARY(或BLOB)   BLOB        BLOB
text     java.lang.String     CLOB            TEXT        CLOB
serializable  实现该接口的类   VARBINARY(或BLOB)   BLOB     BLOB
clob     java.sql.Clob        CLOB            TEXT        CLOB
blob     java.sql.Blob        BLOB            BLOB        BLOB

当应用程序运行时,Java应用程序通过Hibernate访问数据库,而Hibernate又通过JDBC驱动程序访问数据库。JDBC驱动程序对底层数据库使用的SQL进行封装,向上提供标准SQL类型接口,使得Hibernate可以使用标准SQL类型来生成DML(Data Manipulation Language)。

若没有指定映射类型,Hibernate会运用反射机制,判别属性的java类型,采用相应的Hibernate映射类型。
但在一下几种情况下必须显示指定Hibernate映射类型:若希望通过hbm2java工具由映射文件来生成持久化类,必须在映射文件中显式指定Hibernate映射类型。一个java类型对应多个Hibernate映射类型的场合。

org.hibernate.UserType接口中的方法:
sqlTypes()方法:设置java类型为int的在数据库中对应varchar类型
privat static final int[] SQL_TYPES = {Types.VARCHAR};
public int[] sqlTypes(){ return SQL_TYPES;}

returnedClass()方法:当从数据库中读取后运行在java应用程序中是integer类型
public Class returnedClass(){return false;}

isMutable()方法:了解这个类是否是可变类.Hibernate在处理不可变类时会采取一些性能优化
public boolean isMutable(){return false;}

deepCopy(Object value):生成对应属性的快照
public Object deepCopy(Object value){return value;}

equals(Object x, Object y)方法:比较当前值和快照是否相同
public boolean equals(Object x, Object y){
   if(x == y)  return true;
   if(x == null || y == null ) return false;
   return x.equals(y);
}

hasCode(Objec x)方法:获得该属性的哈希码
public int hasCode(Object x){
   return x.hasCode();
}

nullSafeGet(ResultSet resultSet, String[] names, Object owner)方法:获取属性的属性值
public Object nullSafeGet(ResultSet resultSet, String[] names, Object ower) throws HibernateException, SQLException{
     String phone = resultSet.getString(name[0]);
     if(resultSet.wasNull) return null;
     return new Integer(XX);
}

nullSafeSet(PrepareStatement statement, Object value, int index)方法:当Hibernate把对象持久化到数据库时,调用nullSafeSet()方法把属性添加到SQL insert语句中。
public void nullSafeSet(PrepareStatement statement, Object value, int index) throws HibernateException, SQLException{
    if(value == null){
         statement.setNull(index, Types.VARCHAR);
    }else{
         String phone = ((Interger)value).toString();
         statement.setString(index, phone);
    }
}

assemble(Serializable cached, Object owner)方法:当Hibernate把第二级缓存中的对象加载到Session缓存中,调用assemble()方法来获得属性的反序列化数据
public Object assemble(Serializable cached, Object owner){
    return cached;
}

disassemble(Object value)方法:Hibernate把第二级缓存中的对象加载到Session缓存中,调用disassemble()方法来获得属性的序列化数据
public Serializable disassemble(Object value){
    return (Serializable)value;
}

replace(Object original, Object target, Object owner)方法:当Session的merge()方法把一个游离对象融合到持久化对象中时,会调用此replace()方法来获得用于替代持久化对象的属性的值。
public Object replace(Object original, Object target, Object owner){
    return original;
}
  
Hibernate组件采用的是XML配置方式,具有较好的维护性。客户化映射类型采用的是编程方式,能够完成更加复杂灵活的映射。

在持久化类中,二进制大对象可以声明为byte[]或java.sql.Blob类型;字符串大对象可以声明为java.lang.String或java.sql.Clob类型。java.sql.Blob和java.sql.Clob是JDBC API中的接口。在默认的情况下,Blob和Clob接口的实现会使用SQL定位器,当程序从数据库加载Blob类型或Clob类型的数据时,实际上加载的是Blob类型或Clob类型的数据的逻辑指针。接下来程序需要通过Blob.getBinaryStream()或Clob.getCharacterStream()方法得到Blob或Clob类型的数据的输入流,才可以真正读取到大数据对象。
Customer customer = (Customer)session.get(Customer.class, new Long(1));
Blob image = customer.getImage();     //逻辑指针
InputStream in = image.getBinaryStream();   //读取大数据

org.hibernate.Hibernate类提供了一系列用于创建Blob和Clob对象的静态方法:
public static Blob createBlob(byte[] bytes)
public static Blob createBlob(InputStream stream, int length)
public static Blob createBlob(InputStream stream)
public static Clob createClob(String string)
public static Clob createClob(Reader reader, int length)

public class BusinessService{
    public static SessionFactory sessionFactory;
    static{...}  //初始化Hibernate

    public Long saveCustomer() throw Exception{
        //读取photo.gif的二进制文件
        InputStream in = this.getClass().getResourceAsStream("photo.gif");
       byte[] buffer = new byte[in.available];
       in.read(buffer);
       in.close();
      
       Session session = sessionFactory.openSession();
       Transaction tx = session.beginTransaction();

       Customer customer = new Customer():;
       customer.setName("Tom");
      
       //创建一个Blob对象
        customer.setImage(Hibernate.createBlob(buffer));
       session.save(customer);

       tx.commit();
       session.close();
       return customer.getId();
    }

    //加载Customer对象
    public void loadCustomer(Long id) throws Exception{
       Session session = sessionFactory.openSession();
       Transaction tx = session.beginTransaction();
       Customer customer = (Customer) session.get(Customer.class,id);
       getBlob(customer);
       tx.commit();
       session.close();
    }

    public void getBlob(Customer customer) throws Exception{
       Blob image = customer.getImage();
       InputStream in = image.getBinaryStream();
       FileOutputStream fout = new FileOutputStream("11.3\\photo_bak.gif");
       int b = -1;
       while((b = in.read())!= -1)
       fout.write(b);
       fout.close();
       in.close();
    }
}

使用java.sql.Blob和java.sql.Clob受到一下限制:
程序只有在一个数据库事务范围内,才可以访问Blob或Clob类型的实例;有些数据库系统的驱动程序不支持java.sql.Blob或java.sql.Clob;持久化类中必须引入JDBC API中的java.sql.Blob或java.sql.Clob类型。

数据库表之间并不存在继承关系,有3种映射方式可以把域模型的继承关系映射到关系数据模型中:
继承关系树的每个具体类对应一个表:关系数据模型完全不支持域模型中的继承关系和多态。
继承关系树的根类对应一个表:对关系数据模型进行非常规设计,在数据库表中加入额外的区分子类型的字段。通过这种方式,可以使关系数据模型支持继承关系和多态。
继承关系树的每个类对应一个表:在关系数据模型中用外键参照关系来表示继承关系。

继承关系树的每个具体类对应一个表
把每个具体类映射到一张表是自简单的映射方式。这种映射方式不支持多态查询。

继承关系树的根类对应一个表
这种映射方式只需为继承关系树的根创建一张表。在这张表中,会提供它的子类的所有属性对应的字段。此外,还要添加一个标识符字段用来区分不同的子类。
<hibernate-mapping>
   <class name="Employee" table="EMPLOYEE">
       <id name="id"  type="long">
           <generator class="increment" />
       </id>
       <discriminator column="EMPLOYEE_TYPE"  type="string" />
       <many-to-one
           name="company"  column="COLUMN_ID" class="Company"
       />
 
       <subclass name="HourlyEmployee" discriminator-value="HE">
           <property name="rate" column="RATE" type="double" />
       </subclass>

       <subclass name="SalaryEmployee" discriminator-value="SE">
           <property name="salary" column="SALARY" type="double" />
       </subclass>
   </class>
</hibernate-mapping>

继承关系树的每个类对应一个表
继承关系树的每个类及接口都对应一个表,这种映射方式支持多态关联。
<hibernate-mapping>
   <class name="Employee" table="EMPLOYEE">
       <id name="id"  type="long">
           <generator class="increment" />
       </id>
       <many-to-one
           name="company"  column="COLUMN_ID" class="Company"
       />
   
       <joined-subclass name="HourlyEmployee" table="HOURLY_EMPLOYEE">
           <key column="EMPLOYEE_ID" />
           <property name="rate" column="RATE" type="double" />
       </joined-subclass>
    
       <joined-subclass name="HourlyEmployee" table="HOURLY_EMPLOYEE">
           <key column="EMPLOYEE_ID" />
           <property name="salary" column="SALARY" type="double" />
       </joined-subclass>
   </class>
</hibernate-mapping>

比较三种映射方式:
关系数据模型的复杂度:
每个具体类对应一个表:每个具体类对应一个表,这些表中包含重复字段
根对应一个表:只需创建一个表
每个类对应一个表:表的数目最多,并且表之间还有外键参照关系
查询性能:
每个具体类对应一个表:如果查询父类的对象,必须查询所有具体子类对应的表  
根对应一个表:有很好的查询性能,无需进行表的连接   
每个类对应一个表:需要进行表的内连接或左外连接
数据库Schema的可维护性:
每个具体类对应一个表:若父类的属性发生变化,必须修改所有具体的子类对应的表  
根对应一个表:只需修改一张表   
每个类对应一个表:如果某个类的属性发生变化,只需修改和这个类对应的表
是否支持多态查询和多态关联
每个具体类对应一个表:不支持  
根对应一个表:支持  
每个类对应一个表:支持
是否符合关系数据模型的常规设计规则
每个具体类对应一个表:符合  
根对应一个表:在表中引入额外的区分子类的类型的字段;若子类中的某个属性不允许为null,在表中无法为对应的字段创建not null约束   
每个类对应一个表:符合

若不需支持多态查询和多态关联,可以采用给每个具体类对应一个表的映射方式,若需要支持多态查询和多态关联,并且子类包含的属性不多,可以采用根类对应一个表的映射方式,若需要支持多态查询和多态关联,并且子类包含的属性很多,可以采用每个类对应一个表的映射方式。

由于关系数据库模型不允许一个表的外键同时参照两个表的主键,因此,可以通过触发器来保证字段的完整性。
<any name="a" meta-type="string" id-type="long"
     cascade="save-update">
     <meta-value value="B" class="ClassB"  />
     <meta-value value="C" class="ClassC"  />
     <column name="A_TYPE"  />  //指定继承子类的类型
     <column name="A_ID"    />  //子类的id
</any>


今天看了乔布斯斯坦福大学毕业典礼的演讲,感觉还是蛮深刻的。很受鼓舞,人的一生是应该追求自己喜欢的东西,与其自怨自艾,不如努力奋斗!要好好加油哦~~

你可能感兴趣的:(Hibernate,映射类型,大对象,映射方式)