概述
Hibernate映射即完成持久化类与关系数据库中一一对应,而要想将一个普通类变成一个持久化类,一般是通过两种方法,一种是通过持久化注解,另外就是通过配置文件来完成,这种用的比较少,而注解在一般用的比较多。
再使用注解的方法的时候,一般是有几个不可少的注解需要我们完成。一般我们完成一个最简单的数据库操作就是构建一个数据库创建一个表并完成对这个表的增删查改等操作,而这就需要我们完成实体类和数据库表的连接,当然这还不够,我们还要为实体类设置一些属性,并且设置标示性属性,就相当于数据库中的主键,因此还需要为实体类的一些属性进行配置,这个过程也是可以通过注解来完成。
所以,首先,我们需要完成实体类和数据库表的对应。Hibernate采用两个注解来修饰实体类
(1)@Entity:被注解的持久化类就是一个实体类,使用这个注解的时候可以指定一个name属性,指定注解修饰的类,当然也是可以省略的,省略则默认以该类名作为实体类,也就是这个类就是一个持久化类了。
(2)@Table:这个注解就代表持久化类所对应的数据库表咯。
这里,@Table注解有一些属性,这些属性虽然不是必须加上的,但是还是得了解下的:
(1)catalog:不是必须加上,用于设置将持久化类映射的表放入指定的catalog中,没有指定就放入默认catalog中。
(2)indexs:不是必须加上,为持久化类映射的表设置索引
(3)name:不是必须加上,设置持久化类映射的表的表名,不加该表会与持久化类名一样
(4)scheme:不是必须加上,将表放入指定的scheme中,没有则放入默认的scheme中
(5)UniqueConstraint:不是必须加上,用于为数据表定义唯一约束。
这里只是罗列出有这几个属性,当需要用这些的时候又不懂的可以再百度,此处就不进行详细介绍了。使用的时候直接在类的类名的上面添加注解就OK了。
接着我们就说说属性的映射了,属性的映射也包括很多方面,例如一个持久化类中某个属性是一个数组,一个对象,或者是一个图片类型的对象,这些就跟普通的字符串,整数型的处理会有一些不一样,因此接下来就一个一个的介绍。
首先,对于一般的,在默认情况下,被@Entity修饰的持久化类的所有属性都会被映射到底层数据表,可以用@Column注解来修饰某一个属性,例如指定一个属性对应的列名、列字段长度等,当然,@Column注解也是有一些常用的属性,这些属性都不是必须加上的,都是可选的:
(1) columnDefinition:指定创建该数据表的SQL语句,该值为一个代表列定义的SQL字符串
(2)insertable:该列是否包含在hibernate生成的insert语句的列列表中,默认为true
(3)length:列所能保存的最大长度,默认为255
(4)name:列名
(5)nullable:列是否为空,默认为true
(6)precision:当该列时decimal类型时,该属性指定该列支持的最大有效数字位
(7)scale:当该列时decimal类型时,该属性指定该列最大支持的小数位数
(8)table:指定该列所属的表名,当需要多个表保存一个实体时,往往需要指定该属性
(9)unique:指定该列是否具有唯一属性,默认false
(10)updatable:指定该列是否包含在hibernate的update语句的列列表中,默认为true
下面开始介绍不同的属性注解方法,所有的注解修饰都是在定义属性的上面(最好是上一行)定义注解即表示修饰的下面的注解
(一)使用@Transient修饰不想持久保存的属性
这种情况就是被修饰的属性将不会保存在数据表中的,这样对这个属性做任何修改都不会对数据库进行修改。
(二)使用@Enumerated修饰枚举类型的属性
有些时候我们的类中会用到一些枚举类型的属性,这种情况下我们可以通过使用@Enumerated来修饰该枚举类。首先,定义一个枚举类,例如定义一个season类
public enum Season{
春天,夏天,秋天,冬天
}
在选择枚举类型中的某个值的时候,可以按照枚举值的名字来代表,如“春天”,也可以通过枚举值的序号来代表,如0代表春天。在这里@Enumerated的value属性可以指定是按照那种类型来指定枚举的值。value属性有两个值:EnumType.STRING(按照名字)和EnumType.ORDINSL(按照序号),底层保存的是枚举值的序号。持久化类代码如下:
import javax.persistence.*;
@javax.persistence.Entity
@javax.persistence.Table
public class News {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;
@Column(name="news_title",length=50)
private String title;
//消息内容
private String content;
@Enumerated(EnumType.ORDINAL)
private Season happenSeason;
//此处省略所有的get方法和set方法
}
注意,在这里的所有注解都是在javax.persistence包中,在写的时候很容易搞混了注解的类了。
(3)使用@Lob、@Basic修饰大数据类型的属性
在数据库中不仅仅是保存着一些整数型,字符串型等数据,很多时候还是会保存着一些其他类型的数据,比如图片,文件,视屏等等,这些都是无法用普通的类型来表示的,因此就会用到Blob、Clob类型。hibernate使用@Lob来修饰这种大数据类型,当持久化类的属性为byte[]、Byte[]或java.io.Serializable类型时,@Lob修饰的属性将映射为底层的Blob列;当持久化类的属性为char[]、Character[]或java.lang.String类型时,@Lob修饰的属性将映射为底层的Clob列。下面举例说明
实体类:
import javax.persistence.*;
@javax.persistence.Entity
@javax.persistence.Table
public class News {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;
@Column(name="news_title",length=50)
private String title;
//消息内容
private String content;
@Enumerated(EnumType.ORDINAL)
private Season happenSeason;
@Lob
private byte[] pic;
//省略get方法和set方法
}
具体操作的类:
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
public class NewManager {
public static void main(String []args) throws FileNotFoundException, IOException
{
Configuration configuration=new Configuration();
configuration.configure();
SessionFactory sessionFactory=configuration.buildSessionFactory();
Session session=sessionFactory.openSession();
Transaction transaction=session.beginTransaction();
News news=new News();
File picture=new File("Picture/login.jpg");
byte[] pic=new byte[(int )picture.length()];
new FileInputStream(picture).read(pic);
news.setPic(pic);
session.save(news);
transaction.commit();
session.close();
sessionFactory.close();
}
}
在这里实体类就是加一个属性,用来表示图片的,在操作的类时,显示读取需要存入的文件,然后将其转换为流的形式放入数组中,再将数组赋值给实体类的数组,即完成图片的存储。
运行结果如图:
在这里我只插入了图片,其余的信息都没有设置,因此都是为空的,而主键是设置了自动生成的,所以会有主键1的。
另外,如果程序需要加载一个News类时,在默认的情况下是会自动加载所有属性的,但是picture是属于大数据类型,加载的时候会需要较大的系统开销。但是在某些情况下,程序并不需要知道picture的具体信息,只是想获取其他属性的信息,所以不需要获取picture的值,这时,hibernate提供了一种机制可以让对象在加载数据时不立即加载这种大数据类型的值,而只是加载一个“虚拟”的值,等到真正需要这个值的时候才从数据库中加载出来(所谓的代理模式),即在开发的时候使用@Basic修饰该属性,也就是在@Lobby下面添加@Basic注解,这个注解有两个属性:fetch:指定是否延迟加载该属性,可接受FetchType.EAGER、FetchType.LAZY两个值,前者代表立即加载,后者代表延迟加载;optional:指定该列是否允许使用null值
(四)使用@Temporal修饰日期类型的属性
我们知道,在java中,修饰时间日期的有两种,一个是Date类,另一个是Calendar类,但是在数据库中,表示时间的则有好几个:date、time、datetime、timestamp等,所以在映射的时候需要作出抉择。因此,hibernate使用@Temporal来修饰这种类型的属性,使用这个可以指定一个value属性:TemporalType.DATE、TemporalType.TIME、TemporalType.TIMESTAMP三个属性值,处理方法和上面的一样,只需在实体类定义的属性上面添加注解就行。
(五)映射主键
在通常情况下hibernate建议为持久化类建立一个标识属性,用于唯一地标识某个持久化实例,而标识属性则需要映射到底层的数据库表的主键。但是一般的数据库建模理论都不推荐使用具有实际意义的物理主键,而是推荐使用没有什么实际作用的逻辑主键。(具体意义可以百度,此处不展开)逻辑主键仅仅使用来标识一行记录,我们之前的代码中实体类中都是有id这个属性的,但是如果去掉id 这个属性,其余的代码还是不变,依然加上@Id,这样执行的话,发现,数据库的表中依然会有一个id 的属性列。hibernate还为这种逻辑主键提供了主键生成器,他负责为每个持久化实例生成唯一的逻辑主键值。
如果实体类的表示属性是基本数据类型,基本类型的包装类、Spring,Date等类型,可以简单的使用@Id修饰该实体属性即可,这里无需指定任何属性,但是应该使用@GeneratedValue来修饰实体的标识属性,其有四个属性,这里就仅介绍一个主要的属性strategy,其有四个属性值,但是这里只介绍两个比较常见的:GenerationType.AUTO :自己选择最适合底层数据的主键生成器策略,这时默认值。GenerationType.IDENTITY:对于MySQL、SQL server这样的数据库,选择自增长的主键生成策略。这两个属性在上面的代码中都有所应用,所以就不在给出代码了。
(六)使用hibernate的主键生成器
hibernate提供了很多的主键生成策略,如果想要用hibernate提供的主键生成策略,就需要使用hibernate本身的@GenericGenerator注解,该注解含有两个属性:
(1)name:必需属性,设置该主键生成器的名称,该名称可以被@GeneratdValue的generator属性引用
(2)strategy:必须属性,设置该主键生成器的主键生成策略。
并且,hibernate提供了一些策略实现类:
(1)IncrementGenerator:为long、short、或者int类型主键生成唯一标识。
(2)IdentityGenerator:提供自增长主键支持的数据表中使用。返回的标识属性时long、short、或int类型
(3)SequenceStyleGenerator:提供Sequence支持的数据表中适应,返回long、short或int类型
(4)MultiplehiLoPerTableGenerator:使用一个高/低位算法高效地生成long、short或int类型的标识符
(5)UUIDGenerator:用一个128位的UUID算法生成字符串类型的标识符,这在一个网络中时唯一的
(6)GUIDGenerator:在SQL server中使用数据库生成GUID字符串
(7)SelectGenerator:通过数据库触发器选择某个唯一的主键的行,并返回其主键值作为标识属性值
(8)ForeignGenerator:表明直接使用另一个关联的对象的标识属性值。
这里的这些实现类在使用时是直接写在@GenericGenerator的strategy属性中,不过得加上其包org.hibernate.id。
由于篇幅问题,接下来还有集合的映射、对象的映射和组件的映射将在后面的文章中介绍。
最后
以上就是欣喜小天鹅为你收集整理的Hibernate之深入Hibernate映射的全部内容,希望文章能够帮你解决Hibernate之深入Hibernate映射所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复