您的位置:首页 > 其它

hibernate主键生成策略

2011-12-05 13:13 113 查看
使用mySql生成联合主键需要注意的地方:

生成联合主键的各个列不可以为空,首先要设置好,也不可以有一个为主键,

因为主键只有一个,如果联合主键其中的一个为主键的话,那么就没有必要再去

生成联合主键了.

使用联合主键的时候要注意:联合主键需要实现serializable接口,实现了这个接口后还最好要重写

equals和toString()方法,这两个方法如果不写的话,刚开始是看不到错误的,但是等你开始真正的运行的时候就会报错了.

应该是任何的数据库的主键生成策略都是一样的.

在改造系统自动生成的联合主键的过程中注意修改好:

比如系统自动生成的是:

<composite-id name="id" class="com.dada.foreign.TwoId">

<key-property name="id" type="java.lang.Integer">

<column name="id" />

</key-property>

<key-property name="name" type="java.lang.String">

<column name="name" length="20" />

</key-property>

</composite-id>

如果想自己改造一下这个实体,让它只是需要一个类就可以,这种情况下

要这样来修改:

<composite-id>

<key-property name="id" type="java.lang.Integer">

<column name="id" />

</key-property>

<key-property name="name" type="java.lang.String">

<column name="name" length="20" />

</key-property>

</composite-id>

就是只是需要把composite标签里面的属性给删除掉就好了,然后再修改

系统自动生成的实体类,这个时候需要把包含在那个生成联合逐渐的实体

类中的属性都放入到生成实体的主体类当中,而且需要提供每个属性的

get和set方法,之后再添加一个只是包含了联合主键的构造方法就可以了.

然后再把没有用的属性都给删除掉,在对实体进行操作的时候,记住要首先

使用构造方法生成主键,然后再执行其他的操作.

联合主键是需要生成这个主键的hashCode和equals方法的

public class TwoId implements java.io.Serializable {

// Fields

private Integer id;

private String name;

getter and setters

public boolean equals(Object other) {

if ((this == other))

return true;

if ((other == null))

return false;

if (!(other instanceof TwoId))

return false;

TwoId castOther = (TwoId) other;

return ((this.getId() == castOther.getId()) || (this.getId() != null

&& castOther.getId() != null && this.getId().equals(

castOther.getId())))

&& ((this.getName() == castOther.getName()) || (this.getName() != null

&& castOther.getName() != null && this.getName()

.equals(castOther.getName())));

}

public int hashCode() {

int result = 17;

result = 37 * result + (getId() == null ? 0 : this.getId().hashCode());

result = 37 * result

+ (getName() == null ? 0 : this.getName().hashCode());

return result;

}

}

--------------------------------------------------------------------------------------------------

使用annotation生成联合主键

1.把提供主键的类设置为@Embeddable表明这个类可以作为一个嵌入的类,然后在需要此类的地方进行引用时为这个

组件的引用加上@Id注解就可以了.

2.将组件的属性设置为Embeddable,就是说这个组件类本身是不带有注解的,但是对它进行引用的实体就需要在使用

它的时候对他加上Embedded这个注解

3.将实体类设置为IdClass,然后把实体中所有属于主键的属性给标注为@Id就行了.

三种方式的使用情况,第一种的使用情况是非常少的,因为第二种就可以直接的比它少了一步,第二种方式是最常用的,

第三种也有用的,但是用的少,为什么呢?

这个是因为如果使用了联合主键之后,自己总还是需要从数据库中去读取东西的,这个时候呢就有必要把它给读出来,

怎么读呢?使用面向对象的方法就需要提供主键的对象,这个时候就需要使用到它了.

--------------------------------------------------------------------------------------------------

一对一单相外键关联

这种情况就会导致的是在此表中会多生成一个字段那就是wife_id是作为这个表的一个外键.

如果要指定生成的外键字段就需要这样设置:

@OneToOne

@JoinColumn(name="wifeId")

private Wife1 wife;

@Entity

public class Husband1 {

@Id

@GeneratedValue

private Integer id;

private String name;

@OneToOne

private Wife1 wife;

public Wife1 getWife() {

return wife;

}

}

当然双向关联就容易了,只需要在wife实体中也持有一个对Husband的引用就可以了.

但是又这样的一个需求,就是,需要设置双向的关联,但是实际上只需要在自己或者对方

设置一个引用就可以了,就是说,两个表虽然是双向的关联,但是并不需要设置两个外键

这样设置是多余的,这种情况下应该怎么弄呢?

这个时候应该在不需要设置外键的一方中设置好mappedBy就好了,如下

@OneToOne(mappedBy="wife")

private Husband1 husband1;

其中mappedBy的意思是这个外键关系是由对方来主导的,使用的是对方的wife属性来主导的.

这样设置之后就可以达到使用一个外键而得到双向关联的目的了.

在xml中这种双向关联,只生成一个外键的设置方式是:

<one-to-one name="wife" property-ref="student">

同样的,这里的student也是对方实体里面的一个引用.

只要有双向关联必然需要设置mapped

如果是设置为一对一的主键关联的话,就把

@JoinColumn(name="wifeId")

修改为

@PrimaryKeyJoinColumn

--------------------------------------------------------------------------------------------------

多对多单向关联

单向关联只需要在一方设置好关联关系就好了,另外的一方不要设置的.

@Entity

public class Student {

@Id

private int id;

private String name;

@ManyToMany

private Set<Teacher> teachers = new HashSet<Teacher>();

}

注意在这个地方设置@ManyToMany的mappedBy属性是没有用的,因为

它根本不需要生成外键,而是生成一个中间表,这个时候如果想要指定

生成的中间表的名称和中间表中的字段的名字的话,就需要设置:

@JoinTable(

name="t_s",//指明中间表的名字

joinColumns={@JoinColumn(name="stu_id")},//指明本实体

//的主键在中间表中的外键的名字

inverseJoinColumns={@JoinColumn(name="tea_id")}

//指明另外一方实体在中间表中的外键的名字.

)

在xml配置中中间表的名称是在类的hbm的<set>标签中配置的.

---------------------------------------------------------------------------------------------------------------------------------------------------

Hibernate更新指定的字段

1需求,有一个表里面记录的是学生的姓名,学号和他的爱好论文这个时候如果这个表需要更新,

那么在hibernate中默认的更新是把所有的字段全部都更新一遍,因此就会出现在更新一个人的

爱好的时候却需要把论文也更新的情况,这种情况很显然很耗资源也没有必要,这个时候可以这样

配置

在对应的论文字段上加上注解@Colum(updatable=false);

或者在对应的xml的配置文件中配置一下<property>标签的update属性也是可以的.

但是上面的这两种方式都太不灵活了,因此需要使用第三种方式就是在xml中配置

<hibernate-mapping>

<class catalog="shopping" name="com.dada.entities.Notebook" table="notebook" dynamic-update="true">

这个时候呢就是dynamic-update="true"这句话起作用了,它可以动态的去修改.

不过这种动态的改变有个限制就是只能够在xml文件中去配置,而不可以在annotation中去配置,所以

如果需要使用动态的改变的话,就使用xml去配置这个文件就好了.

当然如果不想使用这种动态的配置的话,也可以使用类似于sql的hql语句来实现对特定的一个字段进行修改.

但是即便是动态的修改它还是有条件的,条件就是动态修改的条件,如何才能知道哪些属性改变了呢?

肯定是拿现在的属性跟数据库的属性进行了比较了,那怎么跟数据库里面的数据进行比较呢?

那肯定是把数据库里面的东西给load进入内存里面了,这样才能对修改后的内容跟修改之前的内容进行比较

所以就是执行动态代理的条件就是,被执行动态代理的对象是持久化的也就是被load或者get进入内存的.

但是有的时候会出现这种需求就是跨session去修改数据库,这个时候应该使用的是merge()它的意思是合并

这个在hibernate中实现的细节是:先从数据库中去load这个对象,之后再把要合并的东西跟数据库里面的进行

对比,然后再去修改到数据库里面.

clear()清空缓存内容;

flush:强制缓存内容与数据库同步;

比如

p.setName("a");

p.setName("aa");

session.save(p);

这个时候hibernate中会生成一条语句这个时候只是执行最后一次的更新.

如果使用的是

p.setName("a");

session.flush();

p.setName("aa");

session.save(p);

session.flush();

这句话会产生这样的效果:

1.hibernate会向数据库发送两条语句,一条是执行第一个更改

2.执行第二次更改

如果把session.flush();换成为session.clear();

那么结果就是内存被清空,然后呢持久化的对象都没有了这个时候,当然就谈不上是更改了.

当然在执行commit();方法的时候,系统就会默认的实现flush();这个方法的.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: