JPA学习Day1

本文详细介绍了JPA的学习,包括JPA的概念、与Hibernate的关系、与原生JDBC的区别及其优缺点。讨论了ORM的概念,并展示了第一个JPA程序的实现,最后讲解了一级缓存的工作原理和重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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是否相同
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值