每个持久化类都要有一个标识属性,也就是id,用来区分持久化对象,这个属性成为数据库标识。hibernate有几种不同的标识符生成器。比如序列sequence,hilo,increment。如果要自己分配就是assigned方式,很常用。generator元素没有指定时的默认生成策略。
要注意的是
@Id
@GeneratedValue
和
@Id不一样 = =!
另外,hibernate支持自定义生成方式,这样声明:
@Id
@GeneratedValue(generator = “paymentableGenerator”)
@GenericGenerator(name = “paymentableGenerator”, strategy = “你定义的生成类”)
如果要使用sequence,也可以这样定义:
@Id
@GeneratedValue(generator=“paymentableGenerator”)
@GenericGenerator(name=“paymentableGenerator” strategy=“sequence”)
我们在使用Hibernate的持久化类时,应该遵守如下规则:
1、提供一个无参的构造器:方便Hibernate使用Constructor.newInstance()来创建持久化类的实例。为了方便Hibernate的运行时生成代理类,构造器的访问控制修饰符至少是包可见的,即大于或等于默认的访问控制符
2、提供一个标识属性:表示属性通常映射数据库表的主键字段。其类型可以是任何的原始类型、原始类型的包装类型、Java.lang.String或Java.lang.Date。在关系数据库表中,主键(Primary Key)用来识别记录,并保证每条记录的唯一性。在Java语言中,通过比较两个变量所引用对象的内存地址是否相同,或者比较两个变量引用的对象值是否相同来判断两对象是否相等。Hibernate为了解决两者之间的不同,使用对象标识符(OID)来标识对象的唯一性。
Transaction tx = session.beginTransaction();
User user1 = (User)session.load(User.class,new Long(1));
User user2 = (User)session.load(User.class,new Long(1));
User user3 = (User)session.load(User.class,new Long(3));
System.out.println( user1 == user2 );
System.out.println( user1 == user3 );
应用程序在执行上述代码时,第一次加载OID为1的User对象,从数据库中查找ID为1的记录,然后创建相应的User实例,并把它保存在Session缓存中,最后将该实例的引用赋值给变量user1。第二次加载OID为1的对象时,直接把Session缓存中OID为1的实例的引用赋值给变量user2。因此,表达式user1==user2的结果为true。
3、为持久化的类每个属性提供setter和getter方法:Hibernate默认采用属性方式来访问类的持久化类的属性。如果需要,也可以切换属性访问策略。
4、使用非final类:在运行时生成代理是Hibernate的一个重要功能。如果持久化类没有实现任何接口的话,Hibernate使用CGLIB生成代理,该代理对象时持久化类子类的实例。如果使用了final类,将无法生成CGLIB代理。还有一个可选的策略,让Hibernate持久化类实现一个所有方法都声明为public的接口,此时将使用JDK的动态代理。同时应该避免在非final类中声明public final的方法。如果非要使用一个有public final的类,你必须通过设置lazy=”false“来明确地禁用代理
5、重写equals()和hashCode()方法:如果需要把持久化类的实例放入集合set中(当需要进行关联映射时,推荐这么做),则应该为持久化类重写equals()和hashCode()方法。实现equals()和hashCode()最常用的就是比较两个对象标识符的值。如果值相同,则两个对象对应于数据库的同一行,因此他们是相等的(如果都被添加到set中,则在set中只有一个元素)。但遗憾的是,对采用自动生成标识符值的对象不能使用此方法。Hibernate只会为那些持久化对象指定标识值,一个新创建的实例将不会有任何标识值。因此,一个实例如果没有被保存过,但他又确实在一个Set中,保存它将会给这个对象赋一个标识值。如果equals()和hashCode()是基于标识值实现的,则其hashCode()返回值会发生改变,这将违反Set的规则。