本文章只是自己在学习中记的笔记(可能有点乱),只提供参考。如有错误请指出
什么是jpa
JPA (Java Persistence API)Java持久化API。是一套Sun公司Java官方制定的ORM方案,是规范,是标准 ,sun公司自己并没有实现
-
ORM是什么
对象关系映射
,ORM是一个实现使用对象操作数据库的设计思想
,主要目的是操作实体类就相当于操作数据库。不再重点关注sql语句。 -
JPA的实现者
JPA只是是一套标准。它只是一套实现ORM理论的接口。没有实现的代码。那么我们必须要有具体的实现者才可以完成ORM操作功能的实现!
市场上的主流的JPA框架(实现者)有:
- Hibernate (JBoos)
- EclipseTop(Eclipse社区)
- OpenJPA (Apache基金会)
Hibernate实现
hibernate是一个开放源码的对象关系映射框架
它对jdbc进行了非常轻量级的对象封装。
它将实体类与数据库表建立映射关系,是一个全自动的orm框架。
案例说明
对用户的增删改查操作
-
项目搭建
导入对应的maven坐标
<!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-entitymanager --> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-entitymanager</artifactId> <version>5.4.10.Final</version> </dependency> <!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-c3p0 --> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-c3p0</artifactId> <version>5.4.10.Final</version> </dependency> <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.19</version> </dependency> <!-- https://mvnrepository.com/artifact/log4j/log4j --> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.12</version> <scope>provided</scope> </dependency>
-
配置相关的jpa配置文件
配置文件在类路径下的一个叫
META-INF
的文件下。-
它的文件命名也有要求。叫persistence.xml
<?xml version="1.0" encoding="UTF-8"?> <persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0"> <!-- 持久化单元,name 持久化单元名称 transaction-type事务管理的方式 RESOURCE_LOCAL: 本地事务管理 JPA:分布式事务管理 --> <persistence-unit name="myJpa" transaction-type="RESOURCE_LOCAL"> <!-- jpa的实现方式 --> <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider> <!-- <class>com.wlm.pojo.Customer</class>--> <!-- 数据库信息 --> <properties> <property name="javax.persistence.jdbc.user" value="root"/> <property name="javax.persistence.jdbc.password" value="123"/> <property name="javax.persistence.jdbc.driver" value="com.mysql.cj.jdbc.Driver"/> <property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/website?serverTimezone=UTC&useUnicod=true&characterEncoding=utf-8"/> <!-- 可配置,配置jpa实现放的配置信息,也就是hibernate 显示sql 自动创建数据库表: create:程序运行时创建数据库表(如果有表,先删除再创建) ipdate:程序运行时再创建表(如果有表不会创建) none:不会创建表 --> <property name="hibernate.show_sql" value="true"/><!-- 显示sql--> <property name="hibernate.hbm2ddl.auto" value="update"/><!--自动创建数据库表--> <!-- <property name = "hibernate.dialect" value="org.hibernate.dialect.MySQLDialect" /><!–方言–>--> </properties> </persistence-unit> </persistence>
-
<persistence-unit name="myJpa" transaction-type="RESOURCE_LOCAL">
配置持久化数据单元。- name是 持久化单元名称,名称可以随便写,后面我们在程序中就是更具这名称获取对象。
- transaction-type事务管理的方式,它有2个选项:
- RESOURCE_LOCAL: 本地事务管理。
- JPA: 分布式事务管理。
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
jpa的实现方式。因为jpa是接口,是规范,它没有对数据库的操作的实现。所以我们还要选择是那种方法实现jpa操作。这里是选用了hibernate方式。-
<properties>
里配置的是数据库信息。注意:其中数据库的信息字段,都要以
javax.persistence.jdbc.
开头。
-
再后面2个属性,可配可不配,它是配置jpa实现放的配置信息,也就是hibernate。
重点说下`hibernate.hbm2ddl.auto`,自动创建数据库表。它有3个可选对象。
- create:程序运行时创建数据库表(如果有表,先删除再创建)
- update:程序运行时再创建表(如果有表不会创建)
- none:不会创建表。
-
创建实体类
@AllArgsConstructor @NoArgsConstructor @Setter @Getter @ToString //--------上面是lombok的注解-------- @Entity @Table(name="User") public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "id") private Integer id; private String name; private String pwd; @Column(name = "create_time") private Date createTime; }
注意:上面我用到了lombok。还有,所有的非lombok注解都是
javax.persistence.*
里的上面的注解是配置映射关系。映射关系的配置有两个方向:
- 实体类和表的映射:
- @Entity:声明此类是一个实体类。
- @Table(name="User"):对应的是数据库中的表。name就是数据库中的表名
- 实例类中属性和表中的字段映射:
- @Id:主键。
- @GeneratedValue(strategy = GenerationType.IDENTITY):定义的主键生成策略,其中有:
- GenerationType.IDENTITY:自增。底层数据库必须支持自增才可以使用。像mysql。
- GenerationType.SEQUENCE:序列。底层数据库必须支持序列才可以使用,像orac就支持,mysql不支持
- GenerationType.TABLE:jpa提供的一种机制,它通过一张表的形式完成自增操作。(会在数据库中创建一张表),通过这张表来维护自增
- GenerationType.AUTO:程序自动的选择主键策略。根据自己的表或运行环境选择上面三种策略。
- @Column(name = "id"):表中的字段映射,name,数据库中对应的字段名。
- 实体类和表的映射:
-
api操作
-
增加操作
@Test public void test() { //1.加载配置文件创建工厂(实体管理类工厂)对象,传入的是持久化数据单元,也就是配置文件里我们配置的数据单元。 EntityManagerFactory jpa = Persistence.createEntityManagerFactory("myJpa"); //2.通过工厂获取实体管理器 EntityManager manager = jpa.createEntityManager(); //获取事务对象 EntityTransaction tx = manager.getTransaction(); tx.begin();//开启事务 //完成增删改查 User User = new User(); user.setName("nihao"); user.setPwd("123"); user.setCreateTime(new Date()); //保存 manager.persist(user);//保存操作 //提交事务 tx.commit(); //关闭资源 manager.close(); jpa.close(); }
-
-
根据id查询用户
引入一个概念,上面频繁通过工厂获取实体管理器,是一个比较耗资源和耗时的操作。所以我们可以把它放到一个静态代码块中,封装成一个工具类来获取,解决耗资源和耗时问题
public class JpaUtils { private static EntityManagerFactory factory; static { factory = Persistence.createEntityManagerFactory("myJpa"); } /*获取实体类管理器对象*/ public static EntityManager getEntityManager(){ return factory.createEntityManager(); } }
那么我们根据id查询代码实现:
@Test public void test2() { //获取EntityManager对象 EntityManager entityManager = JpaUtils.getEntityManager(); //查询不需要事务,所以不用开启事务。 //根据id查询操作 /* * 要传入2个参数 * class:查询数据的结果需要包装的实体类型的字节码 * id:查询的主键的信息 * */ // User user = entityManager.find(User.class, 1);//查询的第一种方法find(); User user = entityManager.getReference(User.class, 1);//第二种方法。参数代表的类型都一样。 /* * 这2种方法的区别有什么不一样? * find():查询的对象就是当前Userr本身。再调用的时候,sql发送的时机是立刻去数据库查询 * getReference():查询的对象是一个代理类对象。sql发送的时机是什么时候调用,就什么时候发送。 * 一般是使用getReference(),延迟加载方式。 * */ System.out.println(user); //释放EntityManager资源 entityManager.close(); }
其中
entityManager.find
和entityManager.getReference
的作用和结果都是一样的。为啥要定义两个方法?- find():查询的对象就是当前User本身。再调用的时候,sql发送的时机是立刻去数据库查询
- getReference():查询的对象是一个代理类对象。sql发送的时机是什么时候调用,就什么时候发送。(延迟加载)
我们一般是使用getReference(),延迟加载方式来使用。
-
删除客户的操作
@Test public void testRemove() { EntityManager entityManager = JpaUtils.getEntityManager(); //开启事务 EntityTransaction tx = entityManager.getTransaction(); tx.begin();//开启事务的操作 //删除操作 // 操作步骤 /* * 1,先根据id查询到用户 * 2,传入查询到的用户进行删除 * */ User User = entityManager.getReference(User.class, 2); entityManager.remove(User); tx.commit(); entityManager.close(); }
-
更新操作
@Test public void testUpdate() { EntityManager entityManager = JpaUtils.getEntityManager(); EntityTransaction tx = entityManager.getTransaction(); tx.begin(); User User = entityManager.getReference(User.class, 2); User.setName("我我我我"); //更新操作 entityManager.merge(User); tx.commit(); entityManager.close(); }
如果实体类中有写属性没值,那么更新操作后数据库那些字段也会没值。
-
查询所有的操作
@Test public void testFindAll() { EntityManager entityManager = JpaUtils.getEntityManager(); //查询全部jqpl /* * jqpl:form User * sql:select * from User * */ String jpql = "from User"; Query query = entityManager.createQuery(jpql); //发送查询,并封装结果集 List<User> list = query.getResultList(); for (User o : list) { System.out.println(o); } entityManager.close(); }
这里引入了一个jpql
sql:是查询表和表中的字段。
jpql:是查询的实体类和类中的属性
它们两的语法相识。
比如:
jqpl:form User sql:select * from User
-
倒序查询全部用户,根据id倒序
EntityManager entityManager = JpaUtils.getEntityManager(); String jpql = "from User order by id desc"; Query query = entityManager.createQuery(jpql); List<User> resultList = query.getResultList(); for (User User : resultList) { System.out.println(User); } entityManager.close();
-
使用jpql查询用户的总数
@Test public void testCount() { EntityManager entityManager = JpaUtils.getEntityManager(); String jpql = "select count(id) from User "; Query query = entityManager.createQuery(jpql); Object singleResult = query.getSingleResult();//获取一个结果的。 System.out.println(singleResult); entityManager.close(); }
-
分页查询
EntityManager entityManager = JpaUtils.getEntityManager(); String jpql = "from User"; //1.根据jpql创建query对象 Query query = entityManager.createQuery(jpql); //2.对参数负赋值--分页参数 query.setFirstResult(4);//起始索引,从0开始查,不包含0 query.setMaxResults(2);//每页查询的条数 List<User> resultList = query.getResultList(); for (User User : resultList) { System.out.println(User); } entityManager.close();
-
条件查询
@Test public void testLike() { EntityManager entityManager = JpaUtils.getEntityManager(); String jpql = "from User where name like ?1"; //1.根据jpql创建query对象 Query query = entityManager.createQuery(jpql); /* * 第一个参数是占位符的位置,默认是1开始 * 第二个是 取值 * */ query.setParameter(1, "ni%"); List<User> resultList = query.getResultList(); for (User User : resultList) { System.out.println(User); } entityManager.close(); }
在
String jpql = "from User where name like ?1"
中,占位符后是hpa的样式规定,有多个占位符,比如name like ?1 or pwd = ?2
这样写,后面的数字是你设置占位符里的值的时候根据这数字去设置值。像query.setParameter(1, "ni%");