JPA学习Day1
1.什么是jpa?
1.JPA是Java Persistence API的简称。
2.JPA作为 Java EE 5.0 平台标准的 对象关系映射(ORM) 规范
2.Hibernate和JPA的关系
Hibernate是一个开放源代码的对象关系映射(ORM)框架,它对JDBC进行了非常轻量级(相对于EJB这一套)的对象封装,它将POJO(就是咱们的domain)与数据库表建立映射关系,是一个全自动的orm框架,Hibernate可以自动生成SQL语句,自动执行,使得Java程序员可以随心所欲的使用对象编程思维来操纵数据库。
3.JPA与原生JDBC的区别以及他们的优缺点?
3.1.JDBC:是面向sql操作
3.1.1.优势
①JDBC是操作数据库最底层,性能最高(前提是要对sql很熟悉)
3.1.2.劣势:
①.使用复杂(重复代码太多)
②.移植数据库很麻烦,改动比较多
主键的生成方式不同(mysql使用自增,oracle使用序列sequence)
分页的sql语句也是不同(mysql使用limit,oracle使用ROWNUM)
③.性能优化得自己处理,没有提供数据的缓存,需要自己实现
④.面向sql语句操作,不是面向对象的
3.2JPA处理:Java对象和关系型数据库表之间的转换,只是对JDBC再次做了一层封装
3.2.1JPA的优势?
1.程序员操作很简单,代码简单 entityManager.persist(employee);
2.直接面向持久对象操作
3.提供世界级数据缓存(现在几乎所有的ORM框架的缓存都是学的Hibernate)
一级缓存,二级缓存,查询缓存(空间换速度)
4.数据库移植性很强,很少的修改(通过配置方言搞定)
把各种数据库抽取了一个方言接口
不同数据库实现一个方言接口,如果换了数据库,必须修改方言实现,驱动jar文件,连接数据库信息。
缺点:
1.不能干预sql语句的生成
entityManager.find(User.class, 1L);
find方法默认查询t_user表的所有字段
自动生成select user0_.id,user0_.name,user0_.age from t_user user0_ where user0_.id=?
2.一个项目中,如果对sql语句的优化要求比较高,不适合用JPA(不过可以使用JPA对原生sql的支持来解决)
3.如果一张表中有上亿级别的数据量,也不适合用JPA,其实也不适合用jdbc(可以使用数据库读写分离,分库分表方案解决)。
4.ORM概念
ORM 就是通过将Java对象映射到数据库表,通过操作Java对象,就可以完成对数据表的
操作
5.第一个JPA程序
1.maven的pom文件配置导入jar
<?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>
2.核心配置文件persistence.xml的配置
注意:1.persistence.xml不要放错位置:必须在classpath/META-INF/下面
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0">
<!--
持久化单元名称
name :取一个单元的名称
transaction-type:事务类型 本地数据库的事务
-->
<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="123456" />
<!-- 必须配置1个方言属性 -->
<!-- 实现跨数据库关键类 :查询MySQLDialect的getLimitString方法 -->
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect" />
<!-- 可选配置 ddl数据定义语言(建库建表建约束)
dml数据操作语言 (insert update delete)
dql 数据查询语言(select)
tcl 事务控制语言 (commit rollback)
-->
<!-- 是否自动生成表
create 创建策略,先删除 在创建
update (测试)更新策略 不会删除 如果发现没有表,也会创建
如果是表里面新增的字段 ,配置都有效果
如果这个表里面已经存在该字段 去修改属性 没有效果 比如length
create-drop 先删除 在创建 在删除 不怎么会用 面试会问
把entityManagerFactory关闭
临时表 临时使用表 使用完之后,数据就不应该存在
validate 验证策略 当前实体配置和数据库的配置进行对比验证
如果有对应实体,但是没有对应的数据库表 报错
数据库多字段 OK
数据库少字段 不OK
使用场景:比如已知数据库的前提下 就可以把实体的配置和数据库的配置进行对比
-->
<property name="hibernate.hbm2ddl.auto" value="update" />
<!-- 是否显示sql -->
<property name="hibernate.show_sql" value="true" />
<!-- 格式化sql -->
<!--<property name="hibernate.format_sql" value="true" />-->
</properties>
</persistence-unit>
</persistence>
3.持久类Employee
//@Entity表示一个由jpa管理的持久对象,对应数据库的一个表
@Entity
// table数据库的表名(默认不写时表用会默认为类名)
@Table(name = "t_employee")
public class Employee {
// @Id是必须的,是对应表的主键
@Id
// @GeneratedValue表示主键的生成方式,多数都是使用AUTO
// AUTO自动选择数据库本地的策略:
// mysql:AUTO_INCREMENT自增
// oracle:序列
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "e_id")
private Long id;
private String name;
@Column(name = "pwd")//可配置该字段在表中的列名
private String password;
4.代码示例
public class HelloTest {
@Test
public void save() throws Exception {
Employee employee = new Employee();
employee.setName("xxxxx");
employee.setPassword("yyyyy");
// 对应配置文件里面的persistence-unit name="cn.itsource.jpa"
EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("cn.itsource.jpa");
// 获取Session对象
EntityManager entityManager = entityManagerFactory.createEntityManager();
// 开启事务
EntityTransaction transaction = entityManager.getTransaction();
transaction.begin();
// 持久操作CUD
entityManager.persist(employee);
// 提交事务
transaction.commit();
// 关闭资源
entityManager.close();
entityManagerFactory.close();
}
}
5.JPA工具类的抽取
@Before
public void save() throws Exception {
Employee employee = new Employee();
employee.setName("xxxxx");
employee.setPassword("yyyyy");
EntityManager entityManager = JPAUtils.getEntityManager();
entityManager.getTransaction().begin();
entityManager.persist(employee);
entityManager.getTransaction().commit();
entityManager.close();
}
6.修改
@Test
public void update() throws Exception {
Employee employee = new Employee();
employee.setId(1L);
employee.setName("itsource");
employee.setPassword("25度");
EntityManager entityManager = JPAUtils.getEntityManager();
entityManager.getTransaction().begin();
entityManager.merge(employee);
entityManager.getTransaction().commit();
entityManager.close();
}
7.删除
@Test
public void delete() throws Exception {
EntityManager entityManager = JPAUtils.getEntityManager();
entityManager.getTransaction().begin();
Employee employee = entityManager.find(Employee.class, 1L);
if (employee != null) {
entityManager.remove(employee);
}
entityManager.getTransaction().commit();
entityManager.close();
}
8.查询所有数据
@Test
public void getAll() throws Exception {
EntityManager entityManager = JPAUtils.getEntityManager();
// jpql:JPA的查询语言,类似于sql
// 1.里面不能出现表名,列名,只能出现java的类名,属性名
// 2.出现的sql关键字是一样的意思,
// 3.不能写select * 要写select 别名
// 建议用法
String jpql = "select o from Employee o";
// 最标准的用法
jpql = "select o from cn.itsource.jpa.crud.Employee o";
// 简写
jpql = "from Employee";
Query query = entityManager.createQuery(jpql);
List<Employee> list = query.getResultList();
System.out.println(list.size());
for (Employee employee : list) {
System.out.println(employee);
}
entityManager.close();
}
9.通过主键获取一条数据
@Test
public void get() throws Exception {
EntityManager entityManager = JPAUtils.getEntityManager();
Employee employee = entityManager.find(Employee.class, 1L);
System.out.println(employee);
entityManager.close();
}
10.一些小结
1.persist持久化方法,保存方法
2. merge方法,修改,必须要有id值
3. remove方法,删除,必须要有id值 ,先从数据库查出来,还在判断这个对象是否为空
4. 查询方法可以不要事务,提高性能
5. find方法,通过主键获取domain对象,传入的参数一定要和domain的id的类型匹配
6. jpql是JPA的查询语言,hql是hibernate的查询语言
jpql:不能出现表名,列名,*,只能是Java的类名,属性名,别名
如果在jpql出现的sql关键字,大小写不敏感,Java的类名,属性名,别名大小写敏感
11.JPA中的一级缓存
11.1.EntityManagerFactory的认识
EntityManagerFactory中应保存了对应的persistence unit中的数据库配置信息和所有实体及关系以及预定义的JPQL语句。同时,EntityManagerFactory还负责维护二级缓存。
EntityManagerFactory对象的创建会有较大的开销,而且EntityManagerFactory对象采取了线程安全的设计方式,因此在实际中EntityManagerFactory对象可以尽量的共享,
在大多数情况下,一个应用中针对一个持久化单元可以共享一个EntityManagerFactory实例。
注意:一个应用程序对应一个EntityManagerFactory
11.2EntityManager的认识
使用最广泛,类似于Hibernate的Session对象。
它提供和持久化相关的操作。增、删、改、查等。不是线程安全的,
因此,一个EntityManager对象只可以由一个线程使用。
避免多个线程共享。轻量级的,创建和销毁不需要消耗太多资源。
EntityManager中也有类似Hibernate的Session一级缓存。
11.3一级缓存的命中条件
一级缓存命中测试(同一个EntityManagerFactory,同一个的EntityManager
public void get() throws Exception {
EntityManager entityManager = JPAUtils.getEntityManager();
// 先从一级缓存取,取不到,发出sql获取,放入一级缓存
CacheDomain cacheDomain = entityManager.find(CacheDomain.class, 1L);
System.out.println(cacheDomain);
// 先从一级缓存取,取到,直接返回
CacheDomain cacheDomain2 = entityManager.find(CacheDomain.class, 1L);// OID相同
System.out.println(cacheDomain2);
entityManager.close();
}
Hibernate: insert into CacheDomain (name) values (?)
Hibernate: select cachedomai0_.id as id1_0_0_, cachedomai0_.name as name2_0_0_ from CacheDomain cachedomai0_ where cachedomai0_.id=?
cn.itsource.jpa.cache.CacheDomain@1e8ce150
cn.itsource.jpa.cache.CacheDomain@1e8ce150
打印相同内存地址
// 一级缓存命中:只会发出一条sql
// 一级缓存命中条件:同一个entityManager的OID是否相同