用了一段时间的Spring,到现在也只是处于会用的状态,对于深入一点的东西都不太了解。所以决定开始深入学习Spring。

本文主要记录JPA学习。在学习JPA之前,需要了解一些ORM的概念。

ORM概念:

对象关系映射ORM(Object/Relation Mapping)是一种为了解决面向对象和关系数据之间存在互不匹配现象的技术(范式不匹配)。简而言之,ORM是通过使用描述对象和数据库之间映射的元数据,将程序中的对象自动持久化到数据库中。本质上是将数据从一种形式转换到另外一种形式。(个人考虑:但是这么做,感觉好像和一般方法比起来会有额外的开销吧?待解决)

范式不匹配:

  1. 问题1:对象之间相互管理,且这些管理又有方向信息。如果关联是双向的,那么两个对象之间可以相互导航。在关系表中联系可以通过外键设置,但是外键并没有保存任何方向信息。
  2. 问题2:粒度。在一个类和一个表之间可能没有确切的一对一的映射。例如一个用户表可以用来保存用户数据及其联系方式,家庭住址等信息。但是在对对象进行建模的时候,可以使用多个独立的类,如用户类,地址类,联系方式类等。所以在面向对象中,对象模型的粒度更趋向于细化,而数据库里则更希望表之间的两句数量更少。
  3. 问题3:继承和多态。我们可以创建多个不同类型的对象层次结构,可以建立抽象类型之间的关联,从而在运行时使用多个具体类生产的对象关联。然而在关系数据里没有层次结构的概念,所以只能在表之间建立外键关系。为了处理多态,必须创建一个表到多个不同表的外键关系。
  4. 问题4:对象按需遍历和关系数据的获取方法之间互不适用。在对象世界,关系是通过节点到节点的方式遍历的,所以访问目标对象时,才需要适用改对象的状态。在关系世界里,最好的做法是通过连接表减少SQL查询的数量,从而使用最少的查询量就可以获取所需数据。很明显,这样做与对象按需遍历是冲突的,可能导致程序端内存问题。而另一方面,如果以表到表方式获取数据,那数据库端会产生性能问题。

ORM具备功能:

一般ORM框架包括以下四个功能:

  1. 对象模型和关系模型之间的元数据映射
  2. 一个队持久类对象进行CRUD操作的API
  3. 一种对象查询语言
  4. 不同的数据获取策略和对象网络遍历功能,以便提高内存使用率已经数据获取时间性能

映射发生情况:

对象-关系映射一般发生在以下情况:

  1. 类和表
  2. 类的属性和表中的列
  3. 对象关联和外键
  4. Java类型和SQL类型

以上就是JPA的一些概念,接下来上JPA。

JPA功能:

JPA(Java persistence API)主要用用于Java中处理持久化操作。对ORM特性和功能进行标准化。分别定义了用来将对象模型映射到关系模型的API、可以在对象上执行CRUD操作、一种对象查询语言以及通过对象图获取数据的标准API。

JPA好处:???都还没怎么用,没法做出比较。还是先使用一段时间后,再来评价

使用JPA:

定义实体:

实体定义:一个对象在数据库端与一个带有主键的记录相对应,那么该对象就称为实体。

下面代码定义了一个最简单的实体类:

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table; /**
*
* <p>ClassName: User.java<p>
* <p>用户实体类<p>
* @author linzj
* @createTime 2016年3月17日 下午1:08:35
*/
@Entity
@Table(name="user")
public class User { @Id
@GeneratedValue
private Long id; }

JPA为映射提供了java注解,可以发现这些注解都在javax.persistence包下。上面的@Entity注解定义了User类为持久化类型,并有一个对应的表。@Table注解指定了表名,如果没有指定表明则默认使用类名为其表名。

@Id注解标记了主键属性。如果主键列名与属性名不匹配,则可以使用@Column来指定对应的主键列名,如添加上@Column(name=”uid”),就与uid列表对应。应用程序并不负责生成主键值,而是在新记录插入期间由JPA供应商分配(如Hibernate)。通过@GenerateValue注解告诉JPA,应用程序将不会负责分配主键值,而是有JPA供应商处理。

属性映射到列:

为了更加直观的理解。我先建了一张User表:

mysql> create table user(
-> id int(5) not null primary key auto_increment,
-> username varchar(60) not null,
-> passwd varchar(60) not null);
Query OK, 0 rows affected (0.14 sec) mysql> describe user;
+----------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------+-------------+------+-----+---------+----------------+
| id | int(5) | NO | PRI | NULL | auto_increment |
| username | varchar(60) | NO | | NULL | |
| passwd | varchar(60) | NO | | NULL | |
+----------+-------------+------+-----+---------+----------------+

接下来我们就可以将刚刚的User实体类添加对应的属性,并将属性映射到上面这张user表中对应的列了:

/**
*
* <p>ClassName: User.java<p>
* <p>用户实体类<p>
* @author linzj
* @createTime 2016年3月17日 下午1:08:35
*/
@Entity
@Table(name="user")
public class User { @Id
@GeneratedValue
private Long id; private String username; @Column(name = "passwd")
private String password; @Transient
private String others;
}

因为表中没有password这个字段,所以我们必须指定映射的列名,即指定password映射到passwd。我们还发现实体类中多了一个表里没有的属性others,注意这个others属性已经注解为@Transient,因此others属性将被JPA忽略,不会进行映射。

对象之间创建关联:

数据库关联类型有:

  • 一对一(1:1)
  • 多对一(M:1)
  • 一对多(1:M)
  • 多对多(M:M)

一对一关联:

/**
*
* <p>ClassName: User.java<p>
* <p>
* 用户实体类,通过@OneToOne注解标识一对一关联,
* @JoinColumn注解更加User和Adress实体指定了
* 表之间的外键关系。用户表中的列引用了地址表
* <p>
* @author linzj
* @createTime 2016年3月17日 下午1:08:35
*/
@Entity
@Table(name="user")
public class User { @Id
@GeneratedValue
private Long id; private String username; @Column(name = "passwd")
private String password; @OneToOne
@JoinColumn(name = "adress_id")//添加外键
private Adress adress;
} /**
*
* <p>ClassName: Adress.java<p>
* <p>地址实体类<p>
* @author linzj
* @createTime 2016年3月17日 下午1:52:30
*/
@Entity
public class Adress {
//...pass
}

多对一:

/**
*
* <p>ClassName: Employe.java<p>
* <p>
* 雇员实体类,使用了@ManyToOne注解,并使用了@JoinColumn指定两表之间的外键关系,
* optional=false 标识关联是Employe必须的,即:Employe不能单独存在。
* <p>
* @author linzj
* @createTime 2016年3月17日 下午1:55:11
*/
@Entity
public class Employe { //...pass @ManyToOne(optional = false)
@JoinColumn(name = "company_id")
private Company company; } @Entity
public class Company {
//...pass
}

多对一:

/**
*
* <p>ClassName: Student.java<p>
* <p>
* 学生实体类,@OneToMany注解在学生和书本之间创建了一对多的关系,
* 用@JoinColumn指定外键,不同的是这次外键列存在于Book实体中。
* <p>
* @author linzj
* @createTime 2016年3月17日 下午2:01:23
*/
@Entity
public class Student { //...pass
@OneToMany
@JoinColumn(name = "student_id")
private Set<Book> books = new HashSet<Book>(); } @Entity
public class Book { //...pass }

多对多:

/**
*
* <p>ClassName: Product.java<p>
* <p>
* 产品实体类,@ManyToMany创建多对多关联,
* 注意这里用的是@JoinTable而不是@JoinColumn,
* 因为一边的多个实例可以与另一边的多个实例相关联。因此无法再一个列中保存指向另一个表的关联数据。
* 所以这里就需要提供一个关联表,该表包含每个表的主键列引用。
* 本示例中,关联表是product_catalog,joinColumns和inverseJoinColumns指定
* product_catalog表中的列名,joinColumns指定Product表主键的引用,inverseJoinColumns
* 指定Catalog表主键的引用。
* <p>
* @author linzj
* @createTime 2016年3月17日 下午2:07:47
*/
@Entity
public class Product {
@Id
@GeneratedValue
private Long id; @ManyToMany(cascade=CascadeType.ALL)
@JoinTable(name = "product_catalog", joinColumns = @JoinColumn(name = "product_id"),
inverseJoinColumns = @JoinColumn(name = "catalog_id"))
private Set<Catalog> catalog = new HashSet<Catalog>(); public Long getId() {
return id;
} public void setId(Long id) {
this.id = id;
} public Set<Catalog> getCatalog() {
return catalog;
} public void setCatalog(Set<Catalog> catalog) {
this.catalog = catalog;
}
} @Entity
public class Catalog {
@Id
@GeneratedValue
private Long id;
}
/**
对应的表如下:
mysql> describe product_catalog;
+------------+------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+------------+------------+------+-----+---------+-------+
| product_id | bigint(20) | NO | PRI | NULL | |
| catalog_id | bigint(20) | NO | PRI | NULL | |
+------------+------------+------+-----+---------+-------+
2 rows in set (0.01 sec) mysql> select * from product_catalog;
+------------+------------+
| product_id | catalog_id |
+------------+------------+
| 1 | 1 |
| 1 | 2 |
+------------+------------+
2 rows in set (0.00 sec) mysql> select * from product;
+----+
| id |
+----+
| 1 |
+----+
1 row in set (0.00 sec) mysql> select * from catalog;
+----+
| id |
+----+
| 1 |
| 2 |
+----+
*/

关联的方向性:

关联的方向性只有两种:单向和双向。

在单向关联中,只能从关联的源对象到目标对象。双向关联则处理能从关联的源对象到目标对象外,还可以从目标对象到源对象。

在如下代码中,我们只是将上面的Adress实体类修改了下,就构成了双向关联。我们在Adress实体类代码中,添加了@OneToOne(mappedBy = "adress"),并且添加了mappedBy属性,通过该属性,JPA可以识别该属性,从而管理两个实体之间的关联。使用mappedBy属性的一边可以看作成一个镜子,或者是只读的。它并不会对数据库的数据产生影响。拿下面的代码说明就是,用下面的实体类做持久化操作后,数据库的Adress表里并不会多一列关于user的字段。

@Entity
@Table(name="user")
public class User { @Id
@GeneratedValue
private Long id; private String username; @Column(name = "passwd")
private String password; @OneToOne
@JoinColumn(name = "adress_id")//添加外键
private Adress adress; public Long getId() {
return id;
} public void setId(Long id) {
this.id = id;
} public String getUsername() {
return username;
} public void setUsername(String username) {
this.username = username;
} public String getPassword() {
return password;
} public void setPassword(String password) {
this.password = password;
} public Adress getAdress() {
return adress;
} public void setAdress(Adress adress) {
this.adress = adress;
} } @Entity
public class Adress {
@Id
@GeneratedValue
private Long id; @OneToOne(mappedBy = "adress")
private User user; public Long getId() {
return id;
} public void setId(Long id) {
this.id = id;
} public User getUser() {
return user;
} public void setUser(User user) {
this.user = user;
} }

上面代码放在我的GITHUB

另外提供一些关于JPA的博客:

http://www.cnblogs.com/holbrook/archive/2012/12/30/2839842.html

http://www.cnblogs.com/chenying99/p/3143516.html

以上是本人学习JPA的记录,下一篇介绍配置和使用JPA。

Spring学习---JPA学习笔记的更多相关文章

  1. Spring Data JPA 学习记录1 -- 单向1:N关联的一些问题

    开新坑 开新坑了(笑)....公司项目使用的是Spring Data JPA做持久化框架....学习了一段时间以后发现了一点值得注意的小问题.....与大家分享 主要是针对1:N单向关联产生的一系列问 ...

  2. spring data jpa 学习笔记

    springboot 集成 springData Jpa 1.在pom.xml添加依赖 <!-- SpringData-Jpa依赖--> <dependency <groupI ...

  3. Spring学习笔记(八)Spring Data JPA学习

    ​ jpa简单的命名规则如下,这个不多做介绍,放在这里也是给自己以后查找起来方便,这篇文章主要介绍之前一直忽略了的几个点,像@NoRepositoryBean这个注解,以及怎么自定义Repositor ...

  4. Spring Data JPA学习笔记

    下面先来介绍一下JPA中一些常用的查询操作: //And --- 等价于 SQL 中的 and 关键字,比如 findByHeightAndSex(int height,char sex): publ ...

  5. SpringBoot学习笔记:Spring Data Jpa的使用

    更多请关注公众号 Spring Data Jpa 简介 JPA JPA(Java Persistence API)意即Java持久化API,是Sun官方在JDK5.0后提出的Java持久化规范(JSR ...

  6. spring data jpa入门学习

    本文主要介绍下spring data jpa,主要聊聊为何要使用它进行开发以及它的基本使用.本文主要是入门介绍,并在最后会留下完整的demo供读者进行下载,从而了解并且开始使用spring data ...

  7. spring cloud(学习笔记)高可用注册中心(Eureka)的实现(二)

    绪论 前几天我用一种方式实现了spring cloud的高可用,达到两个注册中心,详情见spring cloud(学习笔记)高可用注册中心(Eureka)的实现(一),今天我意外发现,注册中心可以无限 ...

  8. JPA学习笔记(8)——映射一对多关联关系

    一对多关联关系 本文有很多和多对一是一样的,因此不会写得非常具体. 有看不懂的.能够參考JPA学习笔记(7)--映射多对一关联关系 Order实体类 package com.jpa.helloworl ...

  9. spring 中bean学习笔记

    spring 中bean 一.bean的定义和应用 1. bean 形象上类似于getXX()和setXX()的一种. 2. 由于java是面向对象的,类的方法和属性在使用中需要实例化. 3. 规律: ...

随机推荐

  1. margin:0 auto

    <!doctype html> <html> <head> <meta charset="utf-8"> <title> ...

  2. vue数据源转json问题

    开发过程中使用到了vue框架进行前端批量数据的处理,将批量数据转换为json格式进行ajax传参时需要注意将vue数据源得到的json结果进行如下处理,webservice接收json数据时无法有效的 ...

  3. linux找回密码

    开机启动系统,在进入系统之前按键盘上面的Esc键,会进入下面的界面 按键盘上的e键,出现下面界面 用键盘上的方向键移动光标到第二项,然后再按键盘上面的e,会出现下面的界面 输入一个空格键,然后在输入数 ...

  4. dyld: Symbol not found: _OBJC_CLASS_$_UIBlurEffect

    信息如下: 不知道为撒出现这个问题,查资料也木有查到..看提示信息可能是UIKit的问题,所以就试着这样解决,结果居然好了....有谁知道原因的告诉额一声啊,拜托!

  5. android Spinner 续

    android Spinner 续 动态增删Spinner中的数据项 public class EX04_09 extends Activity{  private static final Stri ...

  6. Android中的自定义Adapter(继承自BaseAdapter)——与系统Adapter的调用方法一致——含ViewHolder显示效率的优化(转)

    Android中很多地方使用的是适配器(Adapter)机制,那我们就要好好把这个Adapter利用起来,并且用出自己的特色,来符合我们自行设计的需要喽~~~ 下面先上一个例子,是使用ViewHold ...

  7. hrbustoj 2033 A Funny Game(对称博弈)

    对称博弈,注释在代码里 #include<iostream> #include<cstdio> using namespace std; ///这个地方其实是博弈原理里面的对称 ...

  8. CDOJ UESTC 1220 The Battle of Guandu

    The 2015 China Collegiate Programming Contest 2015第一届中国大学生程序设计竞赛 F题 本质就是求单源最短路!注意会爆int 对于每一个村庄i,其实就是 ...

  9. 防止aspx木马的IIS SPY变态功能

    防止aspx木马的IIS SPY变态功能 如果服务器支持aspx语言,而且被上传了aspx木马,利用木马里面的IIS SPY 功能,可以读出IIS里面的所有用户的密码,包括用IIS做FTP的,也能读出 ...

  10. zencart的modules下数据库操作templates排版和common首页引用

    把这个学会,zencart的数据库操作,以及各种函数的调用基本会了 这个东西非常有用,你需要认真看一下,不要闲代码多. 如何在数据库中调出自己想要的产品,让它显示在首页. 据我本人不科学的理解,在in ...