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>


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值