在之前的例子中,我们使用了@Entity、@Table、@Id、@GeneratedValue等注解,将一个不同的POJO变成PO类。下面让我们来详细介绍一下Hibernate中的各种注解。

@Entity:被该注释修饰的POJO就是一个实体。使用该注解能够制定一个name属性,用于指定实体类的名称。但平时我们无需指定,因为系统会默认以该类的名字作为实体类的名称。

@Table:该注解指定持久化类所映射的表。一般常用name属性,用于指定表名。

@UniqueConstraint用于为数据表定义唯一约束。

@Index用于为数据表定义索引。

还有其他注释但是我们不常用。


映射属性

在默认情况下被@Entity修饰的持久化类的所有属性都会被映射到底层数据表。为了指定某个属性所映射的数据列的详细信息,比如列明,列字段长度,我们可以在实体类中使用@Column修饰属性。@Column也有它自己的属性。

columnDefinition:该属性的值是一个代表列定义的SQl字符串,指定创建该数据列的SQL语句。

insertable:指定该列是否包含在Hibernate生成的insert语句的列的列表中,默认为true。

length:指定字段能保存的最大长度,默认255.

name:指定列明,默认的与@Column修饰的属性名一样。

nullable:指定该列是否允许为空。

precision:当该列类型是decimal,该属性用于指定支持的最大youxi8ao数字位。

scale:当该列是decimal,这个属性用于指定支持的最大小数位数。

table:指定该列所属表名。当需要使用多个表来保存一个实体,常用这个属性。

unique:指定是否具有唯一约束,默认为false。

updatable:指定该列是否在Hibernate生成的update语句中,默认true。


Hibernate同样允许使用@Access修饰属性,用于单独改变Hibernate对该属性的访问策略,用于覆盖在持久化类中的@Access注解。

@Formula注解能够指定一个SQL表达式,指定属性的值将按照表达式来计算。当然table中是没有这个属性列的。它的value属性允许对象属性包含表达式,包括运用sum、average、max求值的结果。

@Generated表明该属性是否由数据库生成,属性值可以为GenerationTime.NEVER(不由数据库生成)、GenerationTime.INSERT(insert时由数据库生成,但update时不会)和GenerationTIme.ALWAYS(该属性值在执行insert和update时都会被重新生成)。每当Hibernate执行一条update或者insert属性时,Hibernate就会立刻执行一次select语句来获得最新的这个属性的值,并赋值给当前属性。

下面来看一个例子,该例子中我们使用Formula设定一个不存在于表中的属性。

@Entity
@Table(name="news_inf")
public class News {
	@Id
	@GeneratedValue(strategy=GenerationType.IDENTITY)
	private Integer id;
	private String title;
	private String content;
	@Formula("(select concat(nt.title,nt.content)"+"from news_inf nt where nt.id=id)")
	private String fullContent;
	//下面省略了set、get方法

}
public class test {

	public static void main(String[] args) throws Exception {
		Configuration conf = new Configuration();
		conf.configure();
		ServiceRegistry sr = new ServiceRegistryBuilder().applySettings(
				conf.getProperties()).buildServiceRegistry();

		SessionFactory sf = conf.buildSessionFactory(sr);
		Session sess = sf.openSession();
		Transaction tx = sess.beginTransaction();

		News n=new News();
		n.setTitle("title");
		n.setContent("abc123");
		sess.save(n);

		tx.commit();
		sess.close();
		System.out.println(new Date());
	}
}

运行程序,数据库中会创建一个person_inf表,里面有一行数据。然后我们再打开事务取出FullContent里面的内容:

public class test {

	public static void main(String[] args) throws Exception {
		Configuration conf = new Configuration();
		conf.configure();
		ServiceRegistry sr = new ServiceRegistryBuilder().applySettings(
				conf.getProperties()).buildServiceRegistry();

		SessionFactory sf = conf.buildSessionFactory(sr);
		Session sess = sf.openSession();
		Transaction tx = sess.beginTransaction();

		News n=(News)sess.get(News.class,1);
		System.out.println(n.getFullContent());

		tx.commit();
		sess.close();
		System.out.println(new Date());
	}
}

这样我们就能得到由FullContent属性的SQL表达式确定的字符串了。


使用@Transient能够修饰不想持久化保存的属性。

使用@Enumerated修饰枚举类型的属性。在程序中调用枚举时,我们既可以使用序号,也可以使用内容。@Enumerated的EnumType属性能够设置在数据库中是怎么存的,ORDINAL还是STRING。

public enum Season{
		spring,summer, fall, winter
	}

@Enumerated(EnumType.ORDINAL)
	@Column(name="happen_season")
	private Season happenseason;
	
	
	public Season getHappenseason() {
		return happenseason;
	}
	public void setHappenseason(Season happenseason) {
		this.happenseason = happenseason;
	}


使用@Lob来标注大数据类型,@Basic来设定加载策略。当属性类型为byte[],Byte[]或者java.io.Serializable类型时,@Lob修饰的属性自动变为Blob。当属性类型为char[],Character[]或者java.long.String时,@Lob修饰的属性变为Clob。下面我们使用程序演示将一个图片存到数据库中。

@Entity
@Table(name="person_inf")
public class Person {
	
	@Id
	@GeneratedValue(strategy=GenerationType.IDENTITY)
	private Integer id;
	@Column(name="person_name",length=50)
	private String name;
	@Lob
	private byte[] pic;
}
public class test {

	public static void main(String[] args) throws Exception {
		Configuration conf = new Configuration();
		conf.configure();
		ServiceRegistry sr = new ServiceRegistryBuilder().applySettings(
				conf.getProperties()).buildServiceRegistry();

		SessionFactory sf = conf.buildSessionFactory(sr);
		Session sess = sf.openSession();
		Transaction tx = sess.beginTransaction();

		Person p = new Person();
		File file = new File("C:\\Users\\Administrator\\Desktop\\log.jpg");
		byte[] content = new byte[(int) file.length()];
		new FileInputStream(file).read(content);
		p.setPic(content);
		sess.save(p);

		tx.commit();
		sess.close();
		System.out.println(new Date());
	}
}

有的时候加载了Person这个实体,虽然花费了很多开销,但是并没有访问这个大数据属性,为了避免资源浪费,我们可以为这个pic属性设置@Basic注解。这个注解能够让架构先返回一个代理,而真正用到pic属性时才去加载。它还有fetch属性用于指定是否延迟加载该属性,可以接受FetchTyep.EAGER和FetchTyep.LAZY两个值。前者立即加载,后者延时加载。optional属性能够指定属性的数据列是否可以为null。

使用@Temporal修饰时间类型。由于java中只有Date和Calendar,而数据库中有data、time、datatime和timestamp等类型,所以我们需要告诉架构到底要转到哪种数据库类型。

@Temporal(TemporalType.DATA)
private Date birth;

它的TemporalType属性能够接受DATA、TIME和TIMESTAMP三个值。


映射主键

Hibernate建议为持久化类定义一个表示属性,用于为异地表示某个持久化类。标识属性一般就是table的主键列。如果实体类的表示属性是基本数据类型,基本类型的包装,String,Date等,则可以直接使用@Id来修饰属性,无需指定任何属性。

如果希望Hibernate为逻辑主键自动生成键值,则还应该使用@GeneratedValue来修饰属性。它有如下一些属性:

strategy:指定使用怎样的主键生成策略。可以接受如下几个值:

    GenerationType.AUTO:自动选择最适合底层数据库的主键生成策略,是默认值。

    GenerationType.IDENTITY:对于MySQL、SQL Server,选择自增长的主键生成策略。

    GenerationType.SEQUENCE:适用于Oracle这样的数据库,选择使用基于Sequence的主键生成策略,与@SequenceGenerator一起使用。

    GenerationType.TABLE:使用辅助表来生成主键,与@TableGenerator一起使用。

generator属性能够在使用SEQUENCE、TABLE主键策略时引用@SequenceGenerator、@TableGenerator所定义的生成器的名。