Hibernate 使用 Annotation 实现外键关联关系

因为在使用Hibernate的Annotation时遇到坑,坑了一晚上时间,所以写一篇文章记一下经验

如果并没有对Hibernate入门,还请在课室或者在技研中心,接入学校的教学网络,进入服务器smb://10.15.231.233/Video (在技研的网络里叫OPENSUSE-SERVER)。在 数据库->ORM->Hibernate 目录内查看视频教程了解

我的项目使用的是Hibernate 4.3.11.Final,是一个Maven工程。所用到的辅助工具有fastjson,用来把类直接输出成json查看,还有junit4,测试用。

依赖列表(pom.xml)节选

<dependencies>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-core</artifactId>
            <version>4.3.11.Final</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-simple</artifactId>
            <version>1.7.18</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.38</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.8.2</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.8</version>
        </dependency>
</dependencies>

我的工程是一个有关于评分的系统。在里面有两个类,一个是评分模板MarkingTemplate,一个是评分项目MarkingItem。

MarkingTemplate在数据库中的字段如下

字段名 数据类型 备注
id INT 数据编号(自动增长)
title nvarchar(50) 模板标题
commit nvarchar(50) 模板备注

实体类字段如下:

private int id;
private String title;
private String commit;
private int value;
private MarkingTemplate markingTemplate;

MarkingItem在数据库里的字段如下

字段名 数据类型 备注
id INT 数据编号(自增长)
title nvarchar(50) 评分项目标题
commit nvarchar(50) 评分项目备注
value INT 项目分值(只有整数)
belong_to_template INT 所属模板的编号(外键链接至contest_templates)

实体类字段如下:

private int id;
private String title;
private String commit;
private List<MarkingItem> markingItems;

很明显,我数据库里只有MarkingItem到MarkingTemplate的关联,没有明显的反过来的关联。看视频教程的话,都是用的实体类配置文件实现这些关系,但是我想尝试使用Annotation(注解)来实现这个关系,因为本身项目简单,而且注解很简洁很方便。

MarkingTemplate类源码和注解

@Entity
@Table(name = "marking_templates")
public class MarkingTemplate {
    private int id;
    private String title;
    private String commit;
    private List<MarkingItem> markingItems;

    @Id
    @GeneratedValue
    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getCommit() {
        return commit;
    }

    public void setCommit(String commit) {
        this.commit = commit;
    }

    @OneToMany(mappedBy = "markingTemplate")
    public List<MarkingItem> getMarkingItems() {
        return markingItems;
    }

    public void setMarkingItems(List<MarkingItem> markingItems) {
        this.markingItems = markingItems;
    }
}

MarkingItem源码和注解

@Entity
@Table(name = "marking_items")
public class MarkingItem {
    private int id;
    private String title;
    private String commit;
    private int value;
    private MarkingTemplate markingTemplate;

    @Id
    @GeneratedValue
    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getCommit() {
        return commit;
    }

    public void setCommit(String commit) {
        this.commit = commit;
    }

    public int getValue() {
        return value;
    }

    public void setValue(int value) {
        this.value = value;
    }

    @ManyToOne(targetEntity = MarkingTemplate.class)
    @JoinColumn(name = "belong_to_template")
    public MarkingTemplate getMarkingTemplate() {
        return markingTemplate;
    }

    public void setMarkingTemplate(MarkingTemplate markingTemplate) {
        this.markingTemplate = markingTemplate;
    }
}

如果要实现双向的关联,那么需要在两边的类关联的字段所对应的属性声明上添加注解。

先解释一下MarkingItem的getMarkingTemplate()

@ManyToOne(targetEntity = MarkingTemplate.class)
@JoinColumn(name = "belong_to_template")
public MarkingTemplate getMarkingTemplate() {
    return markingTemplate;
}

从数据库里提取belong_to_template字段的数值然后再利用其查询即可得出MarkingTemplate的数值。@ManyToOne表示了一个多对一的关系。模板内项目模板是多对一关系。targetEntity标明这个字段是关联到哪个类,通过这个,Hibernate可以很方便地把这个查出来的号码把MarkingItems所属的MarkingTemplate实体化出来。@JoinColumn表明插入列的字段名称,这个可以省去,我添加这个的原因是因为类中的属性名和数据库内的字段名不相符。

再解释一下MarkingTemplate的getMarkingItems()

@OneToMany(mappedBy = "markingTemplate")
public List<MarkingItem> getMarkingItems() {
    return markingItems;
}

@OneToMany注解声明了一个一对多关系。从数据库字段表可以看出,模板模板内项目是一对多关系。一个模板拥有多个模板内项目,这些项目在类里被存放在一个List里。而在数据库里,是每个项目都有一个字段标明它们属于哪个模板。mappedBy参数表明这个被在Many一方的类的那个属性给映射了。

当查出实体数据之后,Hibernate默认是对关联属性的数据进行延迟加载,就是等到调用get方法的时候再去生成SQL语句查询这个类。

测试类里我利用fastjson直接把数据可视化了。

获取MarkingTemplate

@Test
public void TestGetMarkingTemplate(){
    System.out.println(JSON.toJSONString(session.get(MarkingTemplate.class,1)));
}

输出结果

{
    "commit": "通用模板", 
    "id": 1, 
    "markingItems": [
        {
            "commit": "结合竞赛主题,作品选题具有实用性、合理性、创新性", 
            "id": 6, 
            "markingTemplate": {
                "$ref": "$"
            }, 
            "title": "选题", 
            "value": 10
        }, 
        {
            "commit": "界面友好,完成速度快,操作简洁明了", 
            "id": 7, 
            "markingTemplate": {
                "$ref": "$"
            }, 
            "title": "界面", 
            "value": 20
        }, 
        {
            "commit": "采用的软件开发方法与技术是否先进及与项目相宜", 
            "id": 8, 
            "markingTemplate": {
                "$ref": "$"
            }, 
            "title": "技术", 
            "value": 10
        }, 
        {
            "commit": "功能强大,具有实用性", 
            "id": 9, 
            "markingTemplate": {
                "$ref": "$"
            }, 
            "title": "功能", 
            "value": 40
        }, 
        {
            "commit": "作品的市场潜力与价值", 
            "id": 10, 
            "markingTemplate": {
                "$ref": "$"
            }, 
            "title": "市场", 
            "value": 10
        }, 
        {
            "commit": "对问题的实际理解程度", 
            "id": 11, 
            "markingTemplate": {
                "$ref": "$"
            }, 
            "title": "答辩", 
            "value": 10
        }
    ], 
    "title": "模板1"
}

因为fastjson在生成json string的时候调用了里面的get方法,所以这里没体现hibernate的延迟加载。

获取MarkingItem

@Test
public void TestGetMarkingItems(){
    List markingItems = session.createQuery("from MarkingItem").setFirstResult(0).setMaxResults(9).list();
    for(Object o: markingItems){
        System.out.println(JSON.toJSONString(o));
    }
}

输出结果

{"commit":"结合竞赛主题,作品选题具有实用性、合理性、创新性","id":6,"markingTemplate":{"commit":"通用模板","id":1,"markingItems":[{"$ref":"$"},{"commit":"界面友好,完成速度快,操作简洁明了","id":7,"markingTemplate":{"$ref":"$.markingTemplate"},"title":"界面","value":20},{"commit":"采用的软件开发方法与技术是否先进及与项目相宜","id":8,"markingTemplate":{"$ref":"$.markingTemplate"},"title":"技术","value":10},{"commit":"功能强大,具有实用性","id":9,"markingTemplate":{"$ref":"$.markingTemplate"},"title":"功能","value":40},{"commit":"作品的市场潜力与价值","id":10,"markingTemplate":{"$ref":"$.markingTemplate"},"title":"市场","value":10},{"commit":"对问题的实际理解程度","id":11,"markingTemplate":{"$ref":"$.markingTemplate"},"title":"答辩","value":10}],"title":"模板1"},"title":"选题","value":10}
{"commit":"界面友好,完成速度快,操作简洁明了","id":7,"markingTemplate":{"commit":"通用模板","id":1,"markingItems":[{"commit":"结合竞赛主题,作品选题具有实用性、合理性、创新性","id":6,"markingTemplate":{"$ref":"$.markingTemplate"},"title":"选题","value":10},{"$ref":"$"},{"commit":"采用的软件开发方法与技术是否先进及与项目相宜","id":8,"markingTemplate":{"$ref":"$.markingTemplate"},"title":"技术","value":10},{"commit":"功能强大,具有实用性","id":9,"markingTemplate":{"$ref":"$.markingTemplate"},"title":"功能","value":40},{"commit":"作品的市场潜力与价值","id":10,"markingTemplate":{"$ref":"$.markingTemplate"},"title":"市场","value":10},{"commit":"对问题的实际理解程度","id":11,"markingTemplate":{"$ref":"$.markingTemplate"},"title":"答辩","value":10}],"title":"模板1"},"title":"界面","value":20}
{"commit":"采用的软件开发方法与技术是否先进及与项目相宜","id":8,"markingTemplate":{"commit":"通用模板","id":1,"markingItems":[{"commit":"结合竞赛主题,作品选题具有实用性、合理性、创新性","id":6,"markingTemplate":{"$ref":"$.markingTemplate"},"title":"选题","value":10},{"commit":"界面友好,完成速度快,操作简洁明了","id":7,"markingTemplate":{"$ref":"$.markingTemplate"},"title":"界面","value":20},{"$ref":"$"},{"commit":"功能强大,具有实用性","id":9,"markingTemplate":{"$ref":"$.markingTemplate"},"title":"功能","value":40},{"commit":"作品的市场潜力与价值","id":10,"markingTemplate":{"$ref":"$.markingTemplate"},"title":"市场","value":10},{"commit":"对问题的实际理解程度","id":11,"markingTemplate":{"$ref":"$.markingTemplate"},"title":"答辩","value":10}],"title":"模板1"},"title":"技术","value":10}
{"commit":"功能强大,具有实用性","id":9,"markingTemplate":{"commit":"通用模板","id":1,"markingItems":[{"commit":"结合竞赛主题,作品选题具有实用性、合理性、创新性","id":6,"markingTemplate":{"$ref":"$.markingTemplate"},"title":"选题","value":10},{"commit":"界面友好,完成速度快,操作简洁明了","id":7,"markingTemplate":{"$ref":"$.markingTemplate"},"title":"界面","value":20},{"commit":"采用的软件开发方法与技术是否先进及与项目相宜","id":8,"markingTemplate":{"$ref":"$.markingTemplate"},"title":"技术","value":10},{"$ref":"$"},{"commit":"作品的市场潜力与价值","id":10,"markingTemplate":{"$ref":"$.markingTemplate"},"title":"市场","value":10},{"commit":"对问题的实际理解程度","id":11,"markingTemplate":{"$ref":"$.markingTemplate"},"title":"答辩","value":10}],"title":"模板1"},"title":"功能","value":40}
{"commit":"作品的市场潜力与价值","id":10,"markingTemplate":{"commit":"通用模板","id":1,"markingItems":[{"commit":"结合竞赛主题,作品选题具有实用性、合理性、创新性","id":6,"markingTemplate":{"$ref":"$.markingTemplate"},"title":"选题","value":10},{"commit":"界面友好,完成速度快,操作简洁明了","id":7,"markingTemplate":{"$ref":"$.markingTemplate"},"title":"界面","value":20},{"commit":"采用的软件开发方法与技术是否先进及与项目相宜","id":8,"markingTemplate":{"$ref":"$.markingTemplate"},"title":"技术","value":10},{"commit":"功能强大,具有实用性","id":9,"markingTemplate":{"$ref":"$.markingTemplate"},"title":"功能","value":40},{"$ref":"$"},{"commit":"对问题的实际理解程度","id":11,"markingTemplate":{"$ref":"$.markingTemplate"},"title":"答辩","value":10}],"title":"模板1"},"title":"市场","value":10}
{"commit":"对问题的实际理解程度","id":11,"markingTemplate":{"commit":"通用模板","id":1,"markingItems":[{"commit":"结合竞赛主题,作品选题具有实用性、合理性、创新性","id":6,"markingTemplate":{"$ref":"$.markingTemplate"},"title":"选题","value":10},{"commit":"界面友好,完成速度快,操作简洁明了","id":7,"markingTemplate":{"$ref":"$.markingTemplate"},"title":"界面","value":20},{"commit":"采用的软件开发方法与技术是否先进及与项目相宜","id":8,"markingTemplate":{"$ref":"$.markingTemplate"},"title":"技术","value":10},{"commit":"功能强大,具有实用性","id":9,"markingTemplate":{"$ref":"$.markingTemplate"},"title":"功能","value":40},{"commit":"作品的市场潜力与价值","id":10,"markingTemplate":{"$ref":"$.markingTemplate"},"title":"市场","value":10},{"$ref":"$"}],"title":"模板1"},"title":"答辩","value":10}

嗯。。。这里把模板也加载出来了。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容