JPA1
1.JPA入门
1.1.JPA概述
jpa:(1)Java持久层API,jpa就是做持久层,操作数据库
(2)它是对象映射框架(ORM)的==规范==
ORM: 对象关系映射(Object Relational Mapping,简称ORM)
1.2.为什么需要JPA
(1)以前使用jdbc,在对象和数据库数据之间转换特别麻烦
(2)他以面向对象的思维来操作数据,比如我操作一个java里面对象,就相当于操作数据库表数据
1.3.Hibernate和JPA的关系
JPA:是ORM的规范
Hibernate:是ORM这个JPA规范实现的框架
1.4.JDBC和JPA的优缺点
(1)JDBC的优缺点
本质:处理Java对象和关系型数据库表之间的转换
优点:操作数据库最底层,性能最高(前提是你要有相应的经验,并且是一个数据库高手)
缺点:
1.使用复杂(重复代码太多)
2.移植数据库很麻烦,改动比较多
主键的生成方式不同(mysql使用自增,oracle使用序列sequence)
分页的sql语句也是不同(mysql使用limit,oracle使用ROWNUM)
3.性能优化得自己处理,没有提供数据的缓存,需要自己实现
4.面向sql语句操作,不是面向对象的
(2)JPA的优缺点
本质:处理Java对象和关系型数据库表之间的转换,只是对JDBC再次做了一层封装
优点:
5.程序员操作很简单,代码简单 entityManager.persist(employee);
6.直接面向持久对象操作
7.提供世界级数据缓存(现在几乎所有的ORM框架的缓存都是学的Hibernate)
一级缓存,二级缓存,查询缓存(空间换速度)
8.数据库移植性很强,很少的修改(通过配置方言搞定)
把各种数据库抽取了一个方言接口
不同数据库实现一个方言接口,如果换了数据库,必须修改方言实现,驱动jar文件,连接数据库信息。
缺点:
(1)不能干预sql的生成 ,查询一个数据 find 默认查询所有字段 (select * from )
(2)有些优化 jpa做不了,比如特别大数据量的时候,jpa也不适合,mybatis也解决不了 (架构策略 分库 分表 (分布式))
(3)一个项目里面 对sql要求比较高,就不适合jpa
(4)JPA适用项目规模:中小型的项目
2.第一个JPA程序
2.1.导入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>
注意:如果数据库引入不了,把仓库中的mysql版本5.1.6删除,联网重新下载
2.2.核心配置文件persistence.xml
而JPA中我们也需要先找到这些常用配置:
persistence.xml放在classpath目录的META-INF下
将META-INF移到resources下面(JPA规范要求)
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" />
<!-- 可选配置 -->
<!-- 是否自动生成表 -->
<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>
2.3. 类里面的代码
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();
}
}
3.JPA CRUD
3.1.抽取JPAUtils工具类
用于生成EntityManager类
public class JpaUtil {
//得到EntityManagerFactory
private static EntityManagerFactory entityManagerFactory;
static{
try {
entityManagerFactory = Persistence.createEntityManagerFactory("cn.itsource.jpa");
}catch (RuntimeException e){
throw new RuntimeException("解析配置文件出问题了");
}
}
//得到EntityManager
public static EntityManager getEntityManager(){
EntityManager entityManager = entityManagerFactory.createEntityManager();
return entityManager;
}
}
3.2.CRUD代码
(1)添加:entityManager.persist(obj);
(2)修改:entityManager.merge(obj);
(3)删除:/删除前,必须与entityManager有关联,所以先查找出来,再删除
User user = entityManager.find(User.class, 2L);
System.out.println(user);
transaction.begin();
if (user != null){
entityManager.remove(user);//持久操作
}
(4)查找单行:User user = entityManager.find(User.class,4L);
(5)查找全部:需现用jpql语句,查找出来,再获得结果集
String jpql = "select o from User o";//jpql语句
TypedQuery<User> query = entityManager.createQuery(jpql, User.class);
List<User> resultList = query.getResultList();
注:查找的时候,不需要事务
(1)添加
public void testadd() throws Exception{
User user = new User();
user.setName("老刘星");
EntityManager entityManager = JpaUtil.getEntityManager(); // 获取entityManager对象
// 开启事务
EntityTransaction transaction = entityManager.getTransaction();
transaction.begin();
entityManager.persist(user);//持久操作
transaction.commit();// 提交事务
entityManager.close();// 关闭资源
}
(2)删除
public void testdel() throws Exception{
EntityManager entityManager = JpaUtil.getEntityManager(); // 获取entityManager对象
EntityTransaction transaction = entityManager.getTransaction(); // 开启事务
//删除前,必须与entityManager有关联,所以先查找一次
User user = entityManager.find(User.class, 2L);
System.out.println(user);
transaction.begin();
if (user != null){
entityManager.remove(user);//持久操作
}
transaction.commit();// 提交事务
entityManager.close();// 关闭资源
}
(3)修改
public void testupdate() throws Exception{
User user = new User();
user.setName("老刘星");
user.setId(1L);
EntityManager entityManager = JpaUtil.getEntityManager();// 获取entityManager对象
// 开启事务
EntityTransaction transaction = entityManager.getTransaction();
transaction.begin();
entityManager.merge(user);//持久操作
transaction.commit(); // 提交事务
entityManager.close(); // 关闭资源
}
(4)查找单行
public void testfindOne() throws Exception{
EntityManager entityManager = JpaUtil.getEntityManager(); // 获取entityManager对象
User user = entityManager.find(User.class, 1L);//持久操作
System.out.println(user);
entityManager.close(); // 关闭资源
}
(5)查找全部
public void testfindAll() throws Exception{
EntityManager entityManager = JpaUtil.getEntityManager(); // 获取entityManager对象
//持久操作
String jpql = "select o from User o";//jpql语句
TypedQuery<User> query = entityManager.createQuery(jpql, User.class);
List<User> resultList = query.getResultList();
for (User user : resultList) { //循环
System.out.println(user);
}
entityManager.close(); // 关闭资源
}
4.配置自动生成表(建表策略)
(1)create 创建策略,先删除 在创建
(2) update (测试)更新策略 不会删除 如果发现没有表,也会创建
(3)create-drop 先删除 在创建 在删除
(4) validate 验证策略 当前实体配置和数据库的配置进行对比验证
5.核心API简介
(1)EntityManagerFactory
EntityManagerFactory中应保存了对应的persistence unit中的数据库配置信息和所有实体及关系以及预定义的JPQL语句。同时,EntityManagerFactory还负责维护二级缓存。
EntityManagerFactory这个类他是重量级的,不要频繁创建和销毁,很销毁性能
这个类也应该设计成共享的。在设计成共享的时候,尽量线程安全(利用同步)
(2)EntityManager
EntityManager 它是实体管理的类,可以管理实体(crud),它是轻量级的类,可以频繁创建和销毁不会销毁太多的性能,他是线程不安全的,但是在设计,多个线程来访问的时候,尽量的保证线程是安全,如果没有线程安全,出现事务并发带来的问题;
用途:A管理实体(crud)
B.EntityManager里面有一个一级缓存(掌握)
缓存:Cache 在内存里面开辟一块空间来临时存储数据
缓存什么时候才能用上:(一级缓存命中之后就可以用来)
同一个EntityManagerFactory 同一个EntityManager 同一个OID(实体对象的ID --主键ID)
(3)EntityManager
只能控制相同一个数据库不同表的事务管理,大多数情况都使用这种
处理不同数据库不同表的事务管理
Tomcat默认不支持JTA事务(不过可以通过添加插件来解决),或者需要用JavaEE服务器:如jboss,weblogic服务器
JTA事务适用场景:比如跨行转账,就需要用到JTA事务
6.单表映射配置细节
@Entity
@Table(name = "t_employee")
public class Employee {
@Id
@GeneratedValue
private Long id; //要求:主键,使用数据库的自动生成策略
@Column(length=20,name = "username",unique =true,nullable = false)
private String name; //要求:varchar(20),数据库名称为username,不能为空,唯一
private String password;
@Column(columnDefinition = "int(20) default 25",insertable = false)
private Integer age = 25; //要求:默认值是25,在插入数据时不允许覆盖(添加数据时不操作该字段)
private Boolean sex;// 数据库没有布尔类型,bit对象
@Column(columnDefinition = "decimal(19,2)")
private BigDecimal salary;// 19,2 长度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;//这是一个大文本
@Transient
private String temp;//这一个字段不要同步到数据库