1、JPA理解及实现:
    JPA(Java Persistence API)作为Java EE 5.0平台标准的ORM规范,将得到所有Java EE服务器的支持,是SUN在充分吸收现有ORM框架的基础上,得到了一个易于使用、伸缩性强的ORM规范。JPA通过JDK 5.0注解或XML描述对象-关系表的映射关系,并将运行期的实体对象持久化到数据库中。
    JPA由EJB 3.0软件专家组开发,作为JSR-220实现的一部分。可以在Web应用、甚至桌面应用中使用。JPA的宗旨是为POJO提供持久化标准规范,由此可见,经过这几年的实践探索,能够脱离容器独立运行,方便开发和测试的理念已经深入人心了。
    因为JPA是一个公开的规范,当前有不同的实现。Hibernate 3.2、TopLink 10.1.3以及OpenJpa都提供了对JPA的实现。

 ORM简单介绍
  对象关系映射,(Object Relational Mapping,简称ORM),是通过使用描述对象和数据库之间的映射的元数据,将面向对象语言程序中的对象自动持久化到关系数据库中,本质上讲就是将数据从一种形式转换为另一种形式,也就是在开发当中操作实体类对象就是操作数据库表。实际应用中即在关系型数据库和业务对象之间做一个映射,就不需要和SQL语句打交道,只要像平时操作对象一样就可以了,常见的ORM框架有Hibernate、TopLink、Castor JDO、Apache OBJ等。
2. 具有ORM元数据的领域对象称为实体(Entity),按JPA的规范,实体具备以下的条件:
    1)必须使用javax.persistence.Entity注解或者在XML映射文件中有对应的元素;
    2)必须具有一个不带参的构造函数,类不能声明为final,方法和需要持久化的属性也不能声明为final;
    3)如果游离状的实体对象需要以值的方式进行传递,如通Session bean的远程业务接口传递,则必须实现Serializable接口;
    4)需要持久化的属性,其访问修饰符不能是public,它们必须通过实体类方法进行访问。    
   参看博文: https://www.xuebuyuan.com/3247788.html  
3.常用注解:
1)@Entity:将领域对象标注为一个实体,表示需要保存到数据库中,默认情况下类名即为表名,通过name属性显式指定表名,如name = "T_TOPIC",表示Topic保存到T_TOPIC表中;
    备注:该实体类必须实现Serializable接口
2)@Table,这里通过它来设定对应的数据库表名字是什么
3)@Id则表示对应表的主键。默认情况下,
4)@Column这个用来设定对应的数据库字段名
5)@GeneratedValue(strategy = GenerationType.IDENTITY) 它表示这个主键的值可以自动来生成,而后面的GenerationType.IDENTITY表明它的生成方式是自动增长,类似于auto increment。JPA自动选择一个最适合底层数据库的主键生成策略。
     在javax.persistence.GenerationType中定义了以下几种可供选择的策略:
    a. IDENTITY:表自增键字段,Oracle不支持这种方式;
    b. AUTO: JPA自动选择合适的策略,是默认选项;
    c. SEQUENCE:通过序列产生主键,通过@SequenceGenerator注解指定序列名,MySql不支持这种方式;
    d. TABLE:通过表产生主键,框架借由表模拟序列产生主键,使用该策略可以使应用更易于数据库移植。
    备注:不同的JPA实现商生成的表名是不同的:如 OpenJPA生成openjpa_sequence_table表Hibernate生成一个hibernate_sequences表,而TopLink则生成sequence表。这些表都具有一个序列名和对应值两个字段,如SEQ_NAME和SEQ_COUNT。
    
6)@Temporal(TemporalType.DATE):
    如果属性是时间类型,因为数据表对时间类型有更严格的划分,所以必须指定具体时间类型。在javax.persistence.TemporalType枚举中定义了3种时间类型:
    a. DATE :等于java.sql.Date
    b. TIME :等于java.sql.Time
    c. TIMESTAMP :等于java.sql.Timestamp

7)继承关系
    Topic和PollTopic是父子类,JPA 采用多种方法来支持实体继承。在父类中必须声明继承实体的映射策略。对于继承的实体,在javax.persistence.InheritanceType定义了3种映射策略:
    a.SINGLE_TABLE:父子类都保存到同一个表中,通过字段值进行区分。这是我们Topic实体所采用的策略,Topic和PollTopic都保存到同一张表中,通过TOPIC_TYPE字段进行区分,Topic在T_TOPIC表中对应TOPIC_TYPE= 1的记录,而PollTopic对应TOPIC_TYPE=2的记录(稍后在PollTopic实体中指定);区别的字段通过 @DiscriminatorColumn 说明,区分字段对应该实体的值通过@DiscriminatorValue 指定;
    示列:
    @DiscriminatorColumn(name = "TOPIC_TYPE", discriminatorType =DiscriminatorType.INTEGER, length = 1)
    @DiscriminatorValue(value="1")
    b.TABLE_PER_CLASS:每一个类对应自己的表,一般不推荐采用这种方式。父子类相同的部分保存在同一个表中,不同的部分分开存放,通过表连接获取完整数据
8)关联关系
    JPA规范规定任何属性都默认映射到表中,所以虽然我们没有给multiple属性提供注解信息,但JPA将按照默认的规则对该字段进行映射:字段名和属性名相同,类型相同。如果我们不希望将某个属性持久化到数据表中,则可以通过 @Transient 注解显式指定: @Transient
    a. 一对一级联关系:
    @OneToOne    表示他们是一对一的关系;
    cascade表示他们的级联关系
    @JoinColumn里面指定了Employee表里引用到Address时关联的名字是什么。
    Address对象只是设定为employee对象的一个属性。我们希望是employee对象被保存到数据库里的时候address对象也自动保存进去。那么我们就需要设定这个cascade的级联访问属性。
否则我们就需要显式的利用em.persist()来保存address对象。这也就是为什么我们要用一个cascade的属性。
    示列:单独的映射 address_id字段
        @OneToOne(cascade=CascadeType.ALL)  
        @JoinColumn(name="address_id")  
        private Address address;

映射整张表
        @OneToOne(cascade=CascadeType.ALL)  
        @JoinTable(name="employee_address",joinColumns=@JoinColumn(name="address_id"),inverseJoinColumns=@JoinColumn(name="employee_id"))  
        private Address address; 
    c. 一对多的关联关系:@OneToMany的映射关系
    d. 多对多的映射:@ManyToMany       
9)Lob字段:在JPA中Lob类型类型的持久化很简单,仅需要通过特殊的Lob注解就可以达到目的。下面,我们对Post中的Lob属性类型进行标注:
    Java代码  收藏代码
    @Lob
    @Basic(fetch = FetchType.EAGER)
    @Column(name = "POST_TEXT", columnDefinition = "LONGTEXT NOT NULL")
    private String postText;  
    postText属性对应T_POST表的POST_TEXT字段,该字段的类型是LONTTEXT,并且非空。
    JPA 通过@Lob将属性标注为Lob类型,通过@Basic指定Lob类型数据的获取策略,FetchType.EAGER表示非延迟加载,而FetchType. LAZY表示延迟加载通过@Column的columnDefinition属性指定数据表对应的Lob字段类型
4.通过jpa、及远程服务调用方案实现数据库表中数据的手动迁移示列:

同事写的jpa代码分析:
@RequestMapping(value = "/beginTTrsanfer", method = RequestMethod.GET)
@ResponseBody
public Object beginTrsanfer(String batchSize,String className,String key) {
ResponseDTO responseDTO = new ResponseDTO(ErrorCode.OK);
TransferDBInfo transferDBInfo = new TransferDBInfo();
try {
if (!StringUtils.equals(key,validateKey)){
responseDTO.setErrorCode("-1");
responseDTO.setErrorMsg("validate error");
return responseDTO;
} if (StringUtils.isEmpty(className)){
responseDTO.setErrorCode("-1");
responseDTO.setErrorMsg("className不能为空");
return responseDTO;
} Class clazz = Class.forName(className);
transferDBInfo.setFullName(clazz.getName());
transferDBInfo.setLid(RandomStringUtils.randomNumeric(10));
if (NumberUtils.isNumber(batchSize)){
transferDBInfo.setBatchSize(Integer.valueOf(batchSize));
}else {
transferDBInfo.setBatchSize(defaultBatchSize);
}
//迁移服务实现:实际开发中应该将该迁移服务抽象在一个方法中
Class clazz = getClazz(transferDBInfo.getFullName());
transferDBInfo.setBeginTime(DateUtils.formatDate(new Date(),DateUtils.FORMAT_LONG));
transferDBInfo.setTableName(getTableName(clazz));
if (clazz==null){
return transferDBInfo;
} long minTableId = getMinTableId(clazz);
long maxTableId = getMaxTableId(clazz);
long totalCount = getTotalCount(clazz); transferDBInfo.setDataBaseSourceDataCount(totalCount);
transferDBInfo.setMinTableId(minTableId);
transferDBInfo.setMaxTableId(maxTableId); //获取迁移前目的地数据库中该表中的数据量信息
beforeTransfer(info,clazz);
//读取源数据库中指定条数的数据,然后分批次写入到目标库中
beginTransfer(info);
//获取迁移后目的地数据库中该表中的数据量信息
afterTransfer(info,clazz); } catch (ClassNotFoundException e) {
LOGGER.error(e.getMessage(),e);
responseDTO.setErrorCode("-1");
responseDTO.setErrorMsg("className错误");
return responseDTO;
}catch (Exception e){
LOGGER.error(e.getMessage(),e);
responseDTO.setErrorCode("-1");
responseDTO.setErrorMsg(e.getMessage());
return responseDTO;
}
responseDTO.setData(transferDBInfo);
return responseDTO;
} //使用泛型
public class ResponseDTO <T> implements Serializable { /**
* 错误码
*/
private String errorCode; /**
* 错误码描述
*/
private String errorMsg; /**
* 返回数据值
*/
private T data; public ResponseDTO() {
} public ResponseDTO(ErrorCode errorCode) {
this.errorCode=errorCode.getErrorCode();
this.errorMsg=errorCode.getErrorMsg();
} public ResponseDTO(String errorCode, String errorMsg) {
this.errorCode = errorCode;
this.errorMsg = errorMsg;
} public void setErrorCodeEnum(ErrorCode errorCode) {
this.errorCode=errorCode.getErrorCode();
this.errorMsg=errorCode.getErrorMsg();
} public String getErrorCode() {
return errorCode;
} public void setErrorCode(String errorCode) {
this.errorCode = errorCode;
} public String getErrorMsg() {
return errorMsg;
} public void setErrorMsg(String errorMsg) {
this.errorMsg = errorMsg;
} public T getData() {
return data;
} public void setData(T data) {
this.data = data;
} @Override
public String toString() {
return "ResponseDTO{" +
"errorCode='" + errorCode + '\'' +
", errorMsg='" + errorMsg + '\'' +
", data=" + data +
'}';
}
} 如何根据类名获取表明
public String getTableName(Class clazz) {
if (clazz == null) {
return null;
}
Entity annotation = (Entity) clazz.getAnnotation(Entity.class);
return annotation.name();
} import javax.persistence.*;
import java.io.Serializable;
import java.util.Date; @Entity(name = "user_info_table")
public class UserInfoTableDto implements Serializable {
/*
* 主键id
* */
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
/*
*客户编码
* */
@Column(name="org_code")
private String OrgCode;
/*
* 目录编码
* */
@Column(name="second_category_code")
private String categoryCode; /*
* 创建时间
* */
@Column(name="create_time")
private Date createTime; /*
* 修改时间
* */
@Column(name="update_time")
private Date updateTime; public Long getId() {
return id;
} public void setId(Long id) {
this.id = id;
} public String getOrgCode() {
return OrgCode;
} public void setOrgCode(String orgCode) {
OrgCode = orgCode;
} public String getCategoryCode() {
return categoryCode;
} public void setCategoryCode(String categoryCode) {
this.categoryCode = categoryCode;
} public Date getCreateTime() {
return createTime;
} public void setCreateTime(Date createTime) {
this.createTime = createTime;
} public Date getUpdateTime() {
return updateTime;
} public void setUpdateTime(Date updateTime) {
this.updateTime = updateTime;
} @Override
public String toString() {
return "UserInfoTableDto{" +
"id=" + id +
", OrgCode='" + OrgCode + '\'' +
", categoryCode='" + categoryCode + '\'' +
", createTime=" + createTime +
", updateTime=" + updateTime +
'}';
}
}

参看文章:
https://www.jianshu.com/p/38d247f02724
https://www.iteye.com/blog/shmilyaw-hotmail-com-1969190
https://cloud.tencent.com/developer/article/1028104

英文单词:Embedded  嵌入;   embeddable 可嵌入的;  discriminator 辨别者

十八、sun JPA理解及使用的更多相关文章

  1. 条目二十八《正确理解由reverse_iterator的base()成员函数所产生的iterator的用法》

    条目二十八<正确理解由reverse_iterator的base()成员函数所产生的iterator的用法> 迭代器的种类一共有四种,上面已经说过了.这里就不再次写出来. 这一个条目主要是 ...

  2. Spring Boot 入门系列(二十八) JPA 的实体映射关系,一对一,一对多,多对多关系映射!

    前面讲了Spring Boot 使用 JPA,实现JPA 的增.删.改.查的功能,同时也介绍了JPA的一些查询,自定义SQL查询等使用.JPA使用非常简单,功能非常强大的ORM框架,无需任何数据访问层 ...

  3. 最全的MySQL基础【燕十八传世】

    1.课前准备! 开启mysql服务:1).配置环境变量;2).net start mysql 将该sql文件导入到你的数据库中,以下所有操作都是基于该数据库表操作的!!! [此笔记是本人看着视频加上自 ...

  4. 【转】设计模式 ( 十八 ) 策略模式Strategy(对象行为型)

    设计模式 ( 十八 ) 策略模式Strategy(对象行为型) 1.概述 在软件开发中也常常遇到类似的情况,实现某一个功能有多种算法或者策略,我们可以根据环境或者条件的不同选择不同的算法或者策略来完成 ...

  5. NeHe OpenGL教程 第二十八课:贝塞尔曲面

    转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...

  6. NeHe OpenGL教程 第十八课:二次几何体

    转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...

  7. 设计模式 ( 十八 ) 策略模式Strategy(对象行为型)

    设计模式 ( 十八 ) 策略模式Strategy(对象行为型) 1.概述 在软件开发中也经常遇到类似的情况,实现某一个功能有多种算法或者策略,我们能够依据环境或者条件的不同选择不同的算法或者策略来完毕 ...

  8. WCF技术剖析之十八:消息契约(Message Contract)和基于消息契约的序列化

    原文:WCF技术剖析之十八:消息契约(Message Contract)和基于消息契约的序列化 [爱心链接:拯救一个25岁身患急性白血病的女孩[内有苏州电视台经济频道<天天山海经>为此录制 ...

  9. 【OpenCV新手教程之十八】OpenCV仿射变换 &amp; SURF特征点描写叙述合辑

    本系列文章由@浅墨_毛星云 出品,转载请注明出处. 文章链接:http://blog.csdn.net/poem_qianmo/article/details/33320997 作者:毛星云(浅墨)  ...

随机推荐

  1. Oracle的表空间、用户和表的区别和联系

    Oracle的表空间.用户和表的区别和联系 Oracle数据库是通过表空间来存储实际存在的那些表.索引.视图的, 表空间分类: 临时表空间:   用于存储数据库中单持久性模型对象,如表.索引.视图等, ...

  2. Oracle的表空间、用户和模式

    Oracle 的 表空间(Tablespace).用户(User).模式(Schema)   前面有整理了一篇 Oracle 数据库(database) 与 实例(instance) 的概念及关系整理 ...

  3. Redis如果内存满了怎么办?

    Redis占用内存大小 我们知道Redis是基于内存的key-value数据库,因为系统的内存大小有限,所以我们在使用Redis的时候可以配置Redis能使用的最大的内存大小. 1.通过配置文件配置 ...

  4. 从相亲的角度理解 K8S 的 Node Affinity, Taints 与 Tolerations

    这是昨天晚上阅读园子里的2篇 k8s 博文时产生的想法,在随笔中记录一下. 这2篇博文是 K8S调度之节点亲和性 与 K8S调度之Taints and Tolerations . 如果我们把 node ...

  5. android:Android 6.0权限控制代码封装

    新建的Activity类可以继承这个Activity,这个类封装了关于新版的权限处理相关的代码 使用方法: package com.glsite.phone; import android.conte ...

  6. Python(二):做题函数记录

    一,10进制 转 2,8,16进制 bin(<int>) ,oct(<int>),hex(<int>) 输出示例 '0b10011010010' '0o2322' ...

  7. 【visio】数据可视化 - 形状数据

    visio在对数据处理方面也是有一整套的设施,用户可以用visio存储.管理对象数据,利用数据驱动图形设计,让数据形象化,并在团队沟通的时候清晰地展示数据,沟通数据. 1.属性 每个图形都可以设置多个 ...

  8. h5 datalist标签获取值

    今天使用datalist标签时,想要获得选中的值,发现使用datalist标签上的val()输出结果一直都是空的 后面改用配套的input获得值 代码如下 <!DOCTYPE html> ...

  9. kotori和bangdream

      #include<cstdio> #include<iostream> using namespace std; int n,x,a,b; int main() { cin ...

  10. Python环境搭建后,多种方式的使用进行程序的执行。

    Python环境搭建后,可以使用多种方式进行程序的执行. 第一种: 进入CMD命令提示符 输入python 进入python环境(可以使用Ctrl+C退出) 输入print("hello&q ...