JPA 入门
什么是JPA、为什么需要JPA、JPA优缺点/ORM的概念;
1.什么是JPA:
1.JPA是Java Persistence API的简称。
2.JPA作为 Java EE 5.0 平台标准的 对象关系映射(ORM) 规范
ORM:对象关系映射(object relational mapping,简称ORM)
id | name |
---|---|
1 | 2 |
t_employee — 类对应上Employee
字段id/name — 类里面的属性 Id name
一行数据 — new Employee(1,‘星星’);
对象(Domain类 Entity<实体>类 对象)
3.将得到所有 Java EE 服务器的支持。 Sun 这次吸取了之前 EJB 规范惨痛失败的经历,在充分吸收现有 ORM 框架(如Hibernate)的基础上,得到了一个易于使用、伸缩性强的 ORM 规范。
从目前的开发社区的反应上看
JPA 受到了极大的支持和赞扬, JPA 作为 ORM 领域标准化整合者的目标已经实现。
2.为什么需要JPA
2.1以前使用JDBC,再对象和数据库之间转换特别麻烦
2.2JPA是Sun官方提出的Java持久化规范。它为Java开发人员提供了一种对象/关系映射工具来管理Java应用中的关系数据。
3.Hibernate和JPA的关系(面试)
Hibernate是一个开放源代码的对象关系映射(ORM)框架,它对JDBC进行了非常轻量级(相对于EJB这一套)的对象封装,它将POJO(就是咱们的domain)与数据库表建立映射关系,是一个全自动的orm框架,Hibernate可以自动生成SQL语句,自动执行,使得Java程序员可以随心所欲的使用对象编程思维来操纵数据库。
JPA:他是ORM的规范
Hibernate: 它是ORM这个规范实现的框架
JDBC和JPA的优缺点:
本质:处理Java对象和关系型数据库表之间的转换
JDBC优缺点:
操作数据库最底层,性能最高(前提是你要有相应的经验,并且是一个数据库高手)
1.使用复杂(重复代码太多)
2.移植数据库很麻烦,改动比较多
主键的生成方式不同(mysql使用自增,oracle使用序列sequence)
分页的sql语句也是不同(mysql使用limit,oracle使用ROWNUM)
- JDBC自身没有缓存(Cache),性能优化得自己处理,没有提供数据的缓存,需要自己实现
- JDBC是面向sql语句操作,不是面向对象的
- 比较简单,比较直接,就可以操作数据库
JPA优点:
1.面向对象操作,操作对象就相当于操作数据,比如 entityManager.perisit(employee)
2.移植数据比较方法,以后如果想换数据库,只需要换数据库的方言就OK了
3.JPA有缓存,效率不错(一级缓存 二级缓存 查询缓存)提供世界级的缓存,使用空间换取时间
JPA缺点:
1.不能干预sql语句的生成 查询一个数据 findOne, 默认查询所有字段(select * from)
2.有些优化JPA做不了,比如特别大的数据量的时候,jpa也不适合,mybatis也解决不了(架构,分布式)
3.一个项目里面对SQL要求比较高的话,就不适合JPA
总结:
- 什么是JPA?java persistence api 对象关系映射(ORM) 规范(持久化)
- Hibernate和JPA的关系? JPA是规范,Hibernate是它的一个实现。
- Hibernate是一个完整的对象关系映射框架 mybatis半自动ORM框架
- 什么是ORM? 对象关系映射
- JDBC与JPA的优缺点?
JDBC操作更加底层,它的性能是完全可控的(前提:有控制它性能的能力)
JPA对JDBC的封装,快速开发,自身已经有了很好的性能优化,兼容各种数据库
缺点:不能干涉SQL生成(有些性能问题无法解决)
第一个JPA程序;
导入jar包: pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>cn.itsource</groupId>
<artifactId>jpa-demo</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>
<modules>
<module>jpaday01</module>
</modules>
<dependencies>
<!-- hibernate的包 -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>4.3.8.Final</version>
</dependency>
<!-- hibernate对于jpa的支持包 -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>4.3.8.Final</version>
</dependency>
<!-- mysql的驱动包 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
</dependency>
<!-- junit的测试包 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
<build>
<finalName>pss</finalName>
<plugins>
<plugin>
<!-- Maven的编译插件-->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
配置 核心配置文件persistence.xml:
<persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
version="2.0">
<persistence-unit name="cn.itsource.jpa" transaction-type="RESOURCE_LOCAL">
<properties>
<!-- 必须配置4个连接数据库属性 -->
<property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver" />
<property name="hibernate.connection.url" value="jdbc:mysql:///jpa" />
<property name="hibernate.connection.username" value="root" />
<property name="hibernate.connection.password" value="admin" />
<!-- 必须配置1个方言属性 -->
<!-- 实现跨数据库关键类 :查询MySQLDialect的getLimitString方法 -->
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect" />
<!-- 可选配置 -->
<!-- 是否自动生成表-->
/*
create:创建策略,每次都要删除再创建新的
update:修改策略,不用每次都删除再创建 如果发现没有表,
也会创建表 如果是表里面新增的字段,配置都有效果,
如果这个表里面已经存在该字段 去修改属性是没有效果的
比如length长度 一般都用这个update策略
create-drop:先删除 再创建 再删除 不怎么会用 面试会问
而且要使用的话必须把 entityManager手动关闭了才行
一般临时表才会用 用一次就不要了
validate:验证策略,当前配置和数据库的配置进行对比验证,
如果有对应实体,但是没有对应的数据库表 就会报错
必须表数据等于或者大于实体类
不能表数据小于实体类 否则会报错丢失列
使用场景:比如已知数据库的前提下
就可以把实体的配置和数据库的配置进行对比
*/
<property name="hibernate.hbm2ddl.auto" value="create" />
<!-- 是否显示sql -->
<property name="hibernate.show_sql" value="true" />
<!-- 格式化sql -->
<!-- <property name="hibernate.format_sql" value="true" /> -->
</properties>
</persistence-unit>
</persistence>
@Entity //表示这个类是一个实体类 @Entity表示一个由jpa管理的持久对象,对应数据库的一个表
@Id // @Id是必须的,是对应表的主键
@GeneratedValue // @GeneratedValue表示主键的生成方式,多数都是使用AUTO
@GeneratedValue(strategy = GenerationType.AUTO)//默认省略了后面的(strategy = GenerationType.AUTO)
//strategy: 策略 GenerationType:生成
@Table(name = "t_employee")// table 写数据库的表名
@Column(name = "e_id") //定义列的名字
// AUTO自动选择数据库本地的策略:
// mysql:AUTO_INCREMENT自增
// oracle:序列
// 对应配置文件里面的persistence-unit name="cn.itsource.jpa"
EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("cn.itsource.jpa");//得到EntityManagerFactory 实体管理工厂
// createEntityManager : 创建实体管理对象
//getTransaction(): 获取事务
// gettransaction.begin();开启事务
// gettransaction.commit():提交事务
//通过entityManager就可以管理实体 persist(“对象”): 持久化方法
entityManager.persist(user);
// gettransaction.close(); 清理
// entityManagerFactory.close();关闭资源
//create:创建策略,每次都要删除再创建新的
//update:修改策略,不用每次都删除再创建
JPA抽取工具类
public class JPAUtils {
// 保证EntityManagerFactory是单例
private static EntityManagerFactory entityManagerFactory;
static {
try {
// 对应配置文件里面的persistence-unit name="cn.itsource.jpa"
entityManagerFactory = Persistence.createEntityManagerFactory("cn.itsource.jpa");
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("解析配置文件或者映射配置出现异常:" + e.getMessage());
}
}
public static EntityManager getEntityManager() {
return entityManagerFactory.createEntityManager();
}
}
JPA的CRUD (极其重要);
//查询一条数据
System.out.println(entityManager.find(User.class,1L));//传入字节码文件和对象
/*
查询所有数据
使用JPQL语句:类似于sql的语句 jpa提供查询数据库的语言
写法: 面向对象的思维
jpql: select o(对象的别名) from User o(设置的别名);
如果查询某一个 就: select o.name(写出属性名) from User o;
entityManager.createQuery(jpql,User.class);
query.getResultList(); //获取结果集
list.iter 遍历for循环
*/
list.forEach(user->{
System.out.println(user);
}) //新特性增强for循环
/*
删除 一个游离状态的数据的时候就会报错, 没有和实体类关联起来
先让需要删除的数据跟entitymanager发生关系再删除
就是通过获取ID来先查询再进行删除
User user = entitymanager.find(User.class,1L);
if( user != null){
entityMangeger.remove(user);
}
*/
@Column(name = "e_id",length=255)
JPA的核心 API 认识;
[外链图片转存失败(img-dOBns2kC-1563871210833)(file:///C:/Users/kira/AppData/Local/Temp/msohtmlclip1/01/clip_image002.jpg)]
Persistence:
获取EntitymanagerFactory工厂的
EntitymanagerFactory:实体管理工厂 这个类他是重量级的,
不要频繁的创建和销毁,很消耗性能,这个类该怎么设计呢?
1:1:1 设计 1给应用程序 对应一个entityManagerFactory 对应1个数据库
这个类也应该设计成共享的。再设计成共享的时候尽量线程安全(ThreadLocal <加锁>)
- 《重量级》数据库库配置信息他里面有一个连接池(本身就中,创建和销毁太费时间)
- 又二级缓存(查询缓存,…)
- 预定义的JPQL语句(JPQL,SQL)
- 维护所有实体以及他们之间的关系
entityManager:
它是实体管理的类,可以管理实体(CRUD),是一个轻量级的类,可以频繁的创建
和销毁,不会消耗太多的性能,它是线程不安全的,但是再设计,多个线程来访问的时候,尽量的保证线程是安全的,如果没有线程安全,出现事务并发带来的问题;
事务并发:多个事务同时操作同一个数据的时候(转账的例子)
1.管理实体(CRUD)
2.entitymanager里面又一个一级缓存
缓存:Cache 在内存里面开辟一个空间来临时存储数据
目的:提高查询的效率,空间换取时间
缓存什么时候才能用上:(一级缓存命中之后就可以用了)
同一个EntityManagerFactory 同一个EntityManager 痛一个OID(实体对象的ID–主键ID)
EntityTransaction:
实体事务对象
现在EntityTransaction – 都是本地事务,同一个库里面的事务
不同数据库的事务:(不同的银行转账) 分布式事务
persist持久化方法,保存方法
配置自动生成表(掌握);
建表策略
/*
create:创建策略,每次都要删除再创建新的
update:修改策略,不用每次都删除再创建 如果发现没有表,
也会创建表 如果是表里面新增的字段,配置都有效果,
如果这个表里面已经存在该字段 去修改属性是没有效果的
比如length长度 一般都用这个update策略
create-drop:先删除 再创建 再删除 不怎么会用 面试会问
而且要使用的话必须把 entityManager手动关闭了才行
一般临时表才会用 用一次就不要了
validate:验证策略,当前配置和数据库的配置进行对比验证,
如果有对应实体,但是没有对应的数据库表 就会报错
必须表数据等于或者大于实体类
不能表数据小于实体类 否则会报错丢失列
使用场景:比如已知数据库的前提下
就可以把实体的配置和数据库的配置进行对比
*/
<property name="hibernate.hbm2ddl.auto" value="create" />
单表映射细节(掌握);
@Id
@GeneratedValue
private Long id; //要求:主键,使用数据库的自动生成策略
@Column(length=20,name="username",)
private String name; //要求:varchar(20),数据库名称为username,不能为空,唯一
private String password;
@Column(columnDefiniton="int(20) default 25",)
private Integer age = 25; //要求:默认值是25,在插入数据时不允许覆盖(添加数据时不操作该字段)
private Boolean sex;// 数据库没有布尔类型,bit对象
@Column(columnDefiniton="decimal(19,2)")
private BigDecimal salary;// 19,2
@Column(updatable = false)
@Temporal(TemporalType.TIMESTAMP)
private Date createTime;//包含年月日时分秒,不允许修改
@Temporal(TemporalType.DATE)
private Date birthday;//包含年月日
@Temporal(TemporalType.TIME)
private Date time;//包含时分秒
@Lob
private String text;//这是一个大文本 longtext
@Transient
private String temp;//这一个字段不要同步到数据库