1.一对一(在考虑一对一的设计模式中优先选择主键关联方式,无论是单向还是双向)
1.1单向-》主键关联(Test->SubTest)从SubTest能获取Test对象
Test.class(idauto_increment)
SubTest.class
@Id
@GenericGenerator(name ="pkGenerator",strategy="foreign",parameters={@Parameter(name = "property", value ="test")})
@GeneratedValue(generator="pkGenerator")
@Column(name="id")
privateint id;
@OneToOne
//@JoinColumn(name="ddd") 默认不填JoinColumn会自动生成一个外键字段
//@PrimaryKeyJoinColumn 这样的对应的外键变为主键关联
@PrimaryKeyJoinColumn
privateTest test;
(主键关联必须采用@PrimaryKeyJoinColumn否则默认采用@JoinColumn这时会在SubTest表中多出一个字段,且有外键关联Test的主键约束)
主键策略必须为外键,虽然建表是没有外键约束。但在对SubTest的对象进行save时,会因为你的外键策略,先插入Test表的数据,获取Test记录的主键id为SubTest表的主键Id,然后进行insert。这样两张表的数据的主键id值一样,所以是主键关联,但是是单向的,只能从SubTest的对象中获取到Test的对象数据。在获取的同时,如果获取方式为LAZY的方式,则会先获取SubTest表的记录,通过主键的id,在去查询Test记录。如果方式是EAGER,则会通过SubTest左外连接Test(保留SubTest表,如果Test没有满足条件的记录则值为空(select的为空的字段,不受本身数据库字段是否能为空约束。)),条件为主键关联。
(级联方式还没测试)
1.2单向-》外键关联
Test.class(idauto_increment)
SubTest.class
@Id
@GeneratedValue
@Column(name="id")
privateint id;
@OneToOne
@JoinColumn(name="ddd")//默认不填JoinColumn会自动生成一个外键字段
privateTest test;
(当使用外键关联必须使用@JoinColumn否则不会生成外键。使用则会产生外键约束。)
两个表的主键策略都选择auto_increment,在SubTest表中会多一个字段,受到Test表的id 的外键约束。与1.1主键关联的约束不同的是,主键关联约束只需在SubTest对象中set一个Test对象,然后save一个SubTest对象即可完成两表的insert操作。而外键关联需要在SubTest对象中set一个Test对象,然后通过先save一个Test对象的条件,获取到Test记录保存的id才能save一个SubTest对象。总的来说,外键关联需要对两个对象都进行save操作,而且有先后顺序。
1.3单向-》表间关联
Test.class(idauto_increment)
@Id
@GeneratedValue
@Column(name="id")
privateint id;
@OneToOne
@JoinTable(name="dog",joinColumns = @JoinColumn(name="bcd"),
inverseJoinColumns= { @JoinColumn(name = "abc") } )
privateTest test;
表间关联需要使用@JoinTable(name="dog", joinColumns =@JoinColumn(name="bcd"),
inverseJoinColumns = { @JoinColumn(name = "abc") })
dog为关系表的名称,bcd,abc为dog表的外键约束,受SubTest的主键约束,abc受Test的主键约束。表间关联会额外产生一张关系表。同时需要对两个对象SubTest和Test都进行save操作。(其中,SubTest对象需要set一个Test对象)
2.1双向-》主键关联
Test.class
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
@Column(name="id")
privateint id;
@OneToOne
@PrimaryKeyJoinColumn
publicSubTest subtest;
SubTest.class
@Id
@GenericGenerator(name="pkGenerator",strategy="foreign" ,parameters={@Parameter(name= "property", value = "test")})
@GeneratedValue(generator="pkGenerator")
@Column(name="id")
privateint id;
@OneToOne
@PrimaryKeyJoinColumn
privateTest test;
双向的主键关联只能在一个类中(Test或者SubTest)的主键(id)策略上设置外键策略,并指向另一个的主键,另一个类为自动增长策略。同时两者都需要有OneToOne和PrimaryKeyJoinColumn的注解。这样两个类的区别在于,在save有一个数据的时候,只需对设置外键策略的对象进行save操作,(前提是SubTest对象中set一个Test对象),即可对两表完成insert操作。(其实这里已经不考虑Test对象中是否set了一个SubTest对象,无论是否为空,或者set了一个新的SubTest对象)
在查询时,都可从一个对象中获取到另一个对象。如果是从SubTest中获取Test对象,则SubTest的表会左外连接Test表。其次则相反。
2.2双向-》外键关联
Test.class
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
@Column(name="id")
privateint id;
@OneToOne
@JoinColumn(name="eee")
publicSubTest subtest;
SubTest.class
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
@Column(name="id")
privateint id;
@OneToOne
@JoinColumn(name="ddd")//默认不填JoinColumn会自动生成一个外键字段
privateTest test;
双向的外键关联对于两个类的配置一样,都需要OneToOne和JoinColumn注解,在save数据时,需要同时save两个对象SubTest和Test,并且两个对象需要互相set对方,否则没有set的一方在save时,外键约束的字段值为空。
若对OneToOne的注解没有设置fetch方式,默认为EAGER,如此当我们只获取SubTest时,会去左外连接Test。我们获取SubTest下的Test对象是,SubTest左外连接Test,继续左外连接SubTest。这样的效率是非常低的,我个人建议将加载方式设置成LAZY。
2.3双向-》表间关联(不建议使用)
查询时候的链接表重复链接