什么是jpa
1.jpa是对象关系映射(ORM)的规范
2.ORM 就是通过将Java对象映射到数据库表,通过操作Java象,就可以完成对数据表的操作
3.Hibernate是jpa规范的一个实现,不过Hibernate的出现比jpa早
jpa 的使用
1.环境搭建
1.1在maven中导入jpa依赖包
<!-- 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>
1.2核心配置persistence.xml,这个文件要配置在classpath目录的META-INF下(JPA规范要求),classpath指向的是编译后文件的所在地,例如:src/main/java和src/main/reosurce,这两个文件夹下的内容都会被编译到WEB-INF中的class文件夹中
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0">
<!--持久化单元名-->
<persistence-unit name="com.wal" transaction-type="RESOURCE_LOCAL">
<!--持久化单元属性-->
<properties>
<!--数据库链接属性-->
<property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver" />
<property name="hibernate.connection.url" value="jdbc:mysql:///db2020" />
<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" />
<!-- 可选配置 -->
<!-- 是否自动生成表 -->
<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>
2.创建实体对象Employee
//@Entity表示一个由jpa管理的持久对象,对应数据库的一个表
@Entity
// table数据库的表名
@Table(name = "t_employee")
public class Employee {
// @Id是必须的,是对应表的主键
@Id
// @GeneratedValue表示主键的生成方式
// AUTO自动选择数据库本地的策略:
// mysql:AUTO_INCREMENT自增
// oracle:序列
@GeneratedValue(strategy = GenerationType.AUTO)
//@Column设置该字段在数据库中的名字
@Column(name = "e_id")
private Long id;
private String name;
@Column(name = "pwd")
private String password;
2.1执行流程
创建实体管理工厂获得实体管理者
括号中对应配置文件里面的persistence-unit name=“com.wal”
EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory(“com.wal”);
EntityManager entityManager = entityManagerFactory.createEntityManager();
开启事务
执行操作CURD
提交事务
关闭资源
EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("com.wal");
// 获取Session对象
EntityManager entityManager = entityManagerFactory.createEntityManager();
// 开启事务
EntityTransaction transaction = entityManager.getTransaction();
transaction.begin();
// 持久操作CUD
entityManager.persist(employee);
// 提交事务
transaction.commit();
// 关闭资源
entityManager.close();
entityManagerFactory.close();
}
2.2通过jpql查询数据
//查询所有数据
String jpql = "select o from 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();
}
//通过id查询一条数据
EntityManager entityManager = JPAUtils.getEntityManager();
Employee employee = entityManager.find(Employee.class, 1L);
System.out.println(employee);
entityManager.close();
//persist持久化方法,保存方法
//merge方法,修改,必须要有id值
//remove方法,删除,必须要有id值
2.3建表策略
creat-drop:先删除表,再创建表,再删除表
cerat:先删除表,再创建表,不会再删除表,如果更改了domain类的映射,会马上生效(一般用于测试)
update:如果没表就根据最新的映射信息来创建表
如果表里面已经有这个属性,如修改属性的长度,不会更新到表里面
需要更新这个列先删除表或者删除这个属性对应的列名
如果表里面没有属性,映射信息存在,会增加这个列
validate:表不存在,会抛出异常
Domain类映射信息少属性,表比映射定义的列要多,不会报错
3entitymanagerfactory是一个重量级线程安全的对象,不适合平凡的创建和销毁
entitymanagerfactory中包含
3.1.数据库配置信息它里面有一个连接池(本身就重,创建与销毁太费时间)
3.2.二级缓存(查询缓存,…)
3.3.预定义的JPQL语句(JPQL,SQL)
3.4.所有实体及关系
二级缓存:同一个entitymanagerfactory创建出来的entitymanager共享二级缓存,当一个entitymanager查询一条数据后,如果二级缓存中没有该数据就会保存到二级缓存中,当其他entitymanager来查询同一条数据时不用从数据库中查询,直接从二级缓存中取
二级缓存配置
/依赖导入
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-ehcache</artifactId>
<version>4.3.8.Final</version>
</dependency>
添加persistence.xml配置信息
<!-- 启用二级缓存 -->
<property name="hibernate.cache.use_second_level_cache" value="true" />
<!-- 二级缓存的实现类 -->
<property name="hibernate.cache.region.factory_class" value="org.hibernate.cache.ehcache.EhCacheRegionFactory" />
<!-- 启用查询缓存 -->
<property name="hibernate.cache.use_query_cache" value="true" />
在上面添加配置二级缓存扫描的策略
<!-- ALL:所有的实体类都被缓存 -->
<!-- NONE:所有的实体类都不被缓存. -->
<!-- ENABLE_SELECTIVE:标识 @Cacheable(true) 注解的实体类将被缓存 -->
<!-- DISABLE_SELECTIVE:缓存除标识 @Cacheable(false) 以外的所有实体类 -->
<!-- UNSPECIFIED:默认值,JPA 产品默认值将被使用 -->
<shared-cache-mode>ENABLE_SELECTIVE</shared-cache-mode>
domain类的二级缓存
@Entity
@Cacheable(true)
public class Department
命中条件
@Test
public void test2() throws Exception {
EntityManager entityManager = JPAUtils.getEntityManager();
//先从一级缓存,二级缓存取数据?取不到,发出sql去获取,填充一级缓存,二级缓存
Department department1 = entityManager.find(Department.class, 1L);
//先从一级缓存,二级缓存取数据?一级缓存取到了,返回
Department department2 = entityManager.find(Department.class, 1L);// 一级缓存命中
entityManager.close();
EntityManager entityManager2 = JPAUtils.getEntityManager();
//先从一级缓存,二级缓存取数据?一级缓存没有取到,但是二级缓存取到了,返回
Department department3 = entityManager2.find(Department.class, 1L);// 二级缓存命中
//先从一级缓存,二级缓存取数据?一级缓存取到了,返回
Department department4 = entityManager2.find(Department.class, 1L);// 一级缓存命中
entityManager2.close();
}
二级缓存的使用场景
读取大于修改;
对数据要有独享控制,数据不会被第三方修改;
可以容忍出现无效数据,非关键数据(不是财务数据等)
数据量不能超过内存容量,数据量特别巨大,此时不适合于二级缓存(钝化
一级缓存
同一个EntityManagerFactory,同一个EntityManager,查询同一条数据