深入解析Java的Hibernate框架中的一对一关联映射

网友投稿 190 2023-07-23


深入解析Java的Hibernate框架中的一对一关联映射

作为一个ORM框架,hibernate肯定也需要满足我们实现表与表之间进行关联的需要。hibernate在关联方法的实现很简单。下面我们先来看看一对一的做法:

 不多说了,我们直接上代码:

 两个实体类,TUser和TPassport:

public class TUser implements Serializable{

private static final long serialVersionUID = 1L;

private int id;

private int age;

private String name;

private TPassport passport;

//省略Get/Set方法

}

public class TPassport implements Serializable{

private static final long serialVersionUID = 1L;

private int id;

private String serial;

private int expiry;

private TUser user;

//省略Get/Set方法

}

下面我们看一下映射文件有什么不同:

cascade="all" outer-join="true" />

这里我们看到有一个新标签,one-to-one,它表明当前类与所对应的类是一对一的关系,cascade是级联关系,all表明无论什么情况都进行级联,即当对TUser类进行操作时,TPassport也会进行相应的操作,outer-join是指是否使用outer join语句。

 我们再看另外一个TPassport的映射文件:

user

这里我们重点看到generator的class值,它为foreign表明参照外键,而参照哪一个是由param来进行指定,这里表明参照User类的id。而one-to-one标签中多了一个constrained属性,它是告诉hibernate当前类存在外键约束,即当前类的ID根据TUser的ID进行生成。

 下面我们直接上测试类,这次测试类没有用JUnit而是直接Main方法来了:

public static void main(String[] args) {

Configuration cfg = new Configuration().configure();

SessionFactory sessionFactory = cfg.buildSessionFactory();

Session session = sessionFactory.openSession();

session.beginTransaction();

TUser user = new TUser();

user.setAge(20);

user.setName("shunTest");

TPassport passport = new TPassport();

passport.setExpiry(20);

passport.setSerial("123123123");

passport.setUser(user);

user.setPassport(passport);

session.save(user);

session.getTransaction().commit();

}

代码很简单,就不说了。我们主要看这里:

session.save(user);

这里为什么我们只调用一个save呢,原因就在我们的TUser映射文件中的cascade属性,它被设为all,即表明当我们对TUser进行保存,更新,删除等操作时,TPassport也会进行相应的操作,所以这里我们不用写session.save(passport)。我们看到后台:

Hibernate: insert into USER4 (name, age) values (?, ?)

Hibernate: insert into passport4 (serial, expiry, id) values (?, ?, ?)

Hibernate:   它打印出两个语句,证明hibernate确定帮我们做了这个工作。

 

 

 下面我们再来一个测试类,测试查询:

public static void main(String[] args) {

Configuration cfg = new Configuration().configure();

SessionFactory sessionFactory = cfg.buildSessionFactory();

Session session = sessionFactory.openSession();

TUser user = (TUser)session.load(TUser.class,new Integer(3));

System.out.println(user.getName()+":"+user.getPassport().getSerial());

}

这里我们通过查询出TUser类GFOObHvw,取到TPassport对象。

 我们可以看到hibernate的SQL语句是:

复制代码 代码如下:

Hibernate:

select tuser0_.id as id0_1_, tuser0_.name as name0_1_, tuser0_.age as age0_1_, tpassport1_.id as id1_0_, tpassport1_.serial as serial1_0_, tpassport1_.expiry as expiry1_0_ from USER4 tuser0_ left outer join passport4 tpassport1_ on tuser0_.id=tpassport1_.id where tuser0_.id=?

我们看到语句当中有left outer join,这是因为我们前面在one-to-one当中设了outer-join="true",我们试着把它改成false,看到SQL语句如下:

复制代码 代码如下:

Hibernate:

select tuser0_.id as id0_0_, tuser0_.name as name0_0_, tuser0_.age as age0_0_ from USER4 tuser0_ where tuser0_.id=?

Hibernate:

select tpassport0_.id as id1_0_, tpassport0_.serial as serial1_0_, tpassport0_.expiry as expiry1_0_ from passport4 tpassport0_ where tpassport0_.id=?

现在是分成两条来查了,根据第一条查出的ID再到第二条查出来。

 

 也许很多人会问为什么测试的时候不用TPassport查出TUser呢,其实也可以的,因为它们是一对一的关系,谁查谁都是一样的。

外键关联

现在我们看一下通过外键来进行关联的一对一关联。

 还是一贯的直接上例子:我们写了两个实体类,TGroup和TUser

public class TGroup implements Serializable{

private static final long serialVersionUID = 1L;

private int id;

private String name;

private TUser user;

//省略Get/Set方法

}

public class TUser implements Serializable{

private static final long serialVersionUID = 1L;

private int id;

private int age;

private String name;

private TGroup group;

//省略Get/Set方法

}

实体类完了我们就看一下映射文件:

这里我们看到是用many-to-one标签而不是one-to-one,为什么呢?

 这里以前用的时候也没多在注意,反正会用就行,但这次看了夏昕的书终于明白了,实际上这种通过外键进行关联方式只是多对一的一种特殊方式而已,我们通过unique="true"限定了它必须只能有一个,即实现了一对一的关联。

 接下来我们看一下TGroup的映射文件:

这里,注意,我们又用到了one-to-one,表明当前的实体和TUser是一对一的关系,这里我们不用many-to-one,而是通过one-to-one指定了TUser实体中通过哪个属性来关联当前的类TGroup。这里我们指定了TUser是通过group属性和Tuser进行关联的。property-ref指定了通过哪个属性进行关联。

 下面我们看测试类:

public class HibernateTest {

public static void main(String[] args) {

Configuration cfg = new Configuration().configure();

SessionFactory sessionFactory = cfg.buildSessionFactory();

Session session = sessionFactory.openSession();

session.beginTransaction();

TGroup group = new TGroup();

group.setName("testGroup");

TUser user = new TUser();

user.setAge(23);

user.setName("test");

user.setGroup(group);

group.setUser(user);

session.save(group);

session.save(user);

session.getTransaction().commit();

session.close();

}

}

注意,这次我们的代码中需要进行两次的保存,因为它们对各自都有相应的对应,只保存一个都不会对另外一个有什么操作。所以我们需要调用两次保存的操作。最后进行提交。

 hibernate打印出语句:

Hibernate: insert into group5 (name) values (?)

Hibernate: insert into USER5 (name, age, group_id) values (?, ?, ?)

这说明我们正确地存入了两个对象值。

 

 我们写多一个测试类进行查询:

public static void main(String[] args) {

Configuration cfg = new Configuration().configure();

SessionFactory sessionFactory = cfg.buildSessionFactory();

Session session = sessionFactory.openSession();

TUser user = (TUser)session.load(TUser.class,new Integer(1));

System.out.println("From User get Group:"+user.getGroup().getName());

TGroup group = (TGroup)session.load(TGroup.class,new Integer(1));

System.out.println("From Group get User:" + group.getUser().getName());

session.close();

}

我们都可以得到正确的结果,这表明我们可以通过两个对象拿出对方的值,达到了我们的目的。

 这个例子中用到的TGroup和TUser只是例子而已,实际上现实生活中的user一般都对应多个group。

cascade="all" outer-join="true" />

这里我们看到有一个新标签,one-to-one,它表明当前类与所对应的类是一对一的关系,cascade是级联关系,all表明无论什么情况都进行级联,即当对TUser类进行操作时,TPassport也会进行相应的操作,outer-join是指是否使用outer join语句。

 我们再看另外一个TPassport的映射文件:

user

这里我们重点看到generator的class值,它为foreign表明参照外键,而参照哪一个是由param来进行指定,这里表明参照User类的id。而one-to-one标签中多了一个constrained属性,它是告诉hibernate当前类存在外键约束,即当前类的ID根据TUser的ID进行生成。

 下面我们直接上测试类,这次测试类没有用JUnit而是直接Main方法来了:

public static void main(String[] args) {

Configuration cfg = new Configuration().configure();

SessionFactory sessionFactory = cfg.buildSessionFactory();

Session session = sessionFactory.openSession();

session.beginTransaction();

TUser user = new TUser();

user.setAge(20);

user.setName("shunTest");

TPassport passport = new TPassport();

passport.setExpiry(20);

passport.setSerial("123123123");

passport.setUser(user);

user.setPassport(passport);

session.save(user);

session.getTransaction().commit();

}

代码很简单,就不说了。我们主要看这里:

session.save(user);

这里为什么我们只调用一个save呢,原因就在我们的TUser映射文件中的cascade属性,它被设为all,即表明当我们对TUser进行保存,更新,删除等操作时,TPassport也会进行相应的操作,所以这里我们不用写session.save(passport)。我们看到后台:

Hibernate: insert into USER4 (name, age) values (?, ?)

Hibernate: insert into passport4 (serial, expiry, id) values (?, ?, ?)

Hibernate:   它打印出两个语句,证明hibernate确定帮我们做了这个工作。

 

 

 下面我们再来一个测试类,测试查询:

public static void main(String[] args) {

Configuration cfg = new Configuration().configure();

SessionFactory sessionFactory = cfg.buildSessionFactory();

Session session = sessionFactory.openSession();

TUser user = (TUser)session.load(TUser.class,new Integer(3));

System.out.println(user.getName()+":"+user.getPassport().getSerial());

}

这里我们通过查询出TUser类GFOObHvw,取到TPassport对象。

 我们可以看到hibernate的SQL语句是:

复制代码 代码如下:

Hibernate:

select tuser0_.id as id0_1_, tuser0_.name as name0_1_, tuser0_.age as age0_1_, tpassport1_.id as id1_0_, tpassport1_.serial as serial1_0_, tpassport1_.expiry as expiry1_0_ from USER4 tuser0_ left outer join passport4 tpassport1_ on tuser0_.id=tpassport1_.id where tuser0_.id=?

我们看到语句当中有left outer join,这是因为我们前面在one-to-one当中设了outer-join="true",我们试着把它改成false,看到SQL语句如下:

复制代码 代码如下:

Hibernate:

select tuser0_.id as id0_0_, tuser0_.name as name0_0_, tuser0_.age as age0_0_ from USER4 tuser0_ where tuser0_.id=?

Hibernate:

select tpassport0_.id as id1_0_, tpassport0_.serial as serial1_0_, tpassport0_.expiry as expiry1_0_ from passport4 tpassport0_ where tpassport0_.id=?

现在是分成两条来查了,根据第一条查出的ID再到第二条查出来。

 

 也许很多人会问为什么测试的时候不用TPassport查出TUser呢,其实也可以的,因为它们是一对一的关系,谁查谁都是一样的。

外键关联

现在我们看一下通过外键来进行关联的一对一关联。

 还是一贯的直接上例子:我们写了两个实体类,TGroup和TUser

public class TGroup implements Serializable{

private static final long serialVersionUID = 1L;

private int id;

private String name;

private TUser user;

//省略Get/Set方法

}

public class TUser implements Serializable{

private static final long serialVersionUID = 1L;

private int id;

private int age;

private String name;

private TGroup group;

//省略Get/Set方法

}

实体类完了我们就看一下映射文件:

这里我们看到是用many-to-one标签而不是one-to-one,为什么呢?

 这里以前用的时候也没多在注意,反正会用就行,但这次看了夏昕的书终于明白了,实际上这种通过外键进行关联方式只是多对一的一种特殊方式而已,我们通过unique="true"限定了它必须只能有一个,即实现了一对一的关联。

 接下来我们看一下TGroup的映射文件:

这里,注意,我们又用到了one-to-one,表明当前的实体和TUser是一对一的关系,这里我们不用many-to-one,而是通过one-to-one指定了TUser实体中通过哪个属性来关联当前的类TGroup。这里我们指定了TUser是通过group属性和Tuser进行关联的。property-ref指定了通过哪个属性进行关联。

 下面我们看测试类:

public class HibernateTest {

public static void main(String[] args) {

Configuration cfg = new Configuration().configure();

SessionFactory sessionFactory = cfg.buildSessionFactory();

Session session = sessionFactory.openSession();

session.beginTransaction();

TGroup group = new TGroup();

group.setName("testGroup");

TUser user = new TUser();

user.setAge(23);

user.setName("test");

user.setGroup(group);

group.setUser(user);

session.save(group);

session.save(user);

session.getTransaction().commit();

session.close();

}

}

注意,这次我们的代码中需要进行两次的保存,因为它们对各自都有相应的对应,只保存一个都不会对另外一个有什么操作。所以我们需要调用两次保存的操作。最后进行提交。

 hibernate打印出语句:

Hibernate: insert into group5 (name) values (?)

Hibernate: insert into USER5 (name, age, group_id) values (?, ?, ?)

这说明我们正确地存入了两个对象值。

 

 我们写多一个测试类进行查询:

public static void main(String[] args) {

Configuration cfg = new Configuration().configure();

SessionFactory sessionFactory = cfg.buildSessionFactory();

Session session = sessionFactory.openSession();

TUser user = (TUser)session.load(TUser.class,new Integer(1));

System.out.println("From User get Group:"+user.getGroup().getName());

TGroup group = (TGroup)session.load(TGroup.class,new Integer(1));

System.out.println("From Group get User:" + group.getUser().getName());

session.close();

}

我们都可以得到正确的结果,这表明我们可以通过两个对象拿出对方的值,达到了我们的目的。

 这个例子中用到的TGroup和TUser只是例子而已,实际上现实生活中的user一般都对应多个group。


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:谷歌Chrome浏览器扩展程序开发小记
下一篇:java解析XML几种方式小结
相关文章

 发表评论

暂时没有评论,来抢沙发吧~