Springboot系列-理解JPA

Springboot系列-理解JPA

前言:前两篇博客主要介绍了springboot整合JdbcTemplate和Mybatis对于数据持久化的操作,本篇博客将主要针对于博主对于JPA的学习和理解进行阐述,什么是JPA,JPA在开发的时候有什么优势?

1.关于JPA

1.JPA(Java Persistence API): 用于对象持久化的API

2.Java EE 5.0 平台标准规范,使得应用程序以统一的方式访问持久层

在这里插入图片描述

3.JPA是Hibernate的一个抽象,同时更是一套规范,JPA 本质上就是一种 ORM 规范,不是 ORM 框架,因为 JPA 只是制订了一些规范,提供了一些编程的 API 接口,可以说Hibernate 是JPA的一种实现

4.JPA优势

  • 标准化:提供相同的 API,这保证了基于 JPA 开发的企业应用能够经过少量的修改就能够在不同的 JPA 框架下运行
  • 简单易用:JPA 的主要目标之一就是提供更加简单的编程模型,在 JPA 框架下创建实体和创建 Java 类一样,只需要使用 javax.persistence.Entity 进行注解
  • 查询能力:JPA的查询语言是面向对象的,可媲美JDBC,JPA 定义了独特的JPQL,而且能够支持批量更新和修改
  • 支持面向对象高级特性:JPA 中能够支持面向对象的高级特性,如类之间的继承、多态和类之间的复杂关系等

5.JPA技术

  • ORM 映射元数据:JPA 支持 XML 和 JDK 5.0 注解两种元数据的形式,元数据描述对象和表之间的映射关系,框架据此将实体对象持久化到数据库表中
  • JPA - > API:用来操作实体对象,执行CRUD操作,拜托繁琐的JDBC和SQL代码
  • 查询语言(JPQL):通过面向对象而非面向数据库的查询语言查询数据,避免程序和具体的 SQL 紧密耦合

6.Spring Data是Spring 的一个子项目,用于简化数据库访问,支持NoSQL 和 关系数据存储 ,主要目的是访问数据库便捷 ,Spring Data 具有如下特点:

  • SpringData 项目支持 NoSQL 存储(MongoDB、Neo4j、Redis、Hbase )
  • SpringData 项目所支持的关系数据存储技术(JDBC、JPA)
  • Spring Data JPA 减少了数据访问层的开发量,只需要声明持久层接口,其他由spring data jpa完成

2.JPA的使用

1.首先我们先来介绍下关于JPA的使用,还是新创建一个工程,选择JavaEE Persistence,如下:

在这里插入图片描述

2.创建完成之后,添加相应jar包,因为Hibernate 是JPA规范的一种实现,所以添加的jar基本上都是关于Hibernate ,如下:

在这里插入图片描述

3.新建User实体类,如下:

@Entity(name = "user")
public class User{
    private Integer id;
    private String username;
    private String address;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    public Long getId() {
        return id;
    }
    // 省略getter/setter
}

以上首先@Entity注解表示这是个实体类,项目启动后根据实体类对象生成一个数据库表,默认表明为类名,如上可根据name自定义;@Id 注解表示这个字段是一个 id,@GeneratedValue 注解表示主键的自增长策略,默认类其他属性都会对应表字段,开发者可以使用@Column注解自定义配置

4.创建 persistence.xml 文件,JPA 规范要求在类路径的 META-INF 目录下放置 persistence.xml

<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0">
    <persistence-unit name="NewPersistenceUnit" transaction-type="RESOURCE_LOCAL">
        <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
        <class>com.wxy.User</class>
        <properties>
            <property name="hibernate.connection.url"  value="jdbc:mysql:///jpa?useUnicode=true&amp;characterEncoding=UTF-8"/>
            <property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver"/>
            <property name="hibernate.connection.username" value="root"/>
            <property name="hibernate.connection.password" value="123456"/>
            <property name="hibernate.archive.autodetection" value="class"/>
            <property name="hibernate.show_sql" value="true"/>
            <property name="hibernate.format_sql" value="true"/>
            <property name="hibernate.hbm2ddl.auto" value="update"/>
        </properties>
    </persistence-unit>
</persistence>
  • persistence-unit 的 name 属性用于定义持久化单元的名字, 必填
  • transaction-type:指定 JPA 的事务处理策略,RESOURCE_LOCAL:默认值,数据库级别的事务,只能针对一种数据库,不支持分布式事务;如果需要支持分布式事务,可以选择使用JTA:transaction-type=“JTA”
  • class 节点表示显式的列出实体类
  • properties 中的配置分为两部分:数据库连接信息以及Hibernate信息

5.持久化操作

EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("NewPersistenceUnit");
EntityManager manager = entityManagerFactory.createEntityManager();
EntityTransaction transaction = manager.getTransaction();
transaction.begin();
User user = new User();
user .setUserName("王帅帅");
user .setAdress("Peking");
manager.persist(user );
transaction.commit();
manager.close();
entityManagerFactory.close();

首先根据上面的配置文件创建EntityManagerFactory ,再根据EntityManagerFactory 实例创建EntityManager ,然后开启事务,调用 EntityManager 中的 persist 方法执行一次持久化操作,最后提交事务、关闭,完成后可以观察刚才配置的jpa数据库,新增一条数据


3.Spring Data JPA的使用

刚刚上面介绍了关于JPA以及JPA的使用,那么Spring Data Jpa 如何配置呢?

1.首先创建一个maven工程,添加依赖如下:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-orm</artifactId>
    <version>5.0.2.RELEASE</version>
</dependency>

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-oxm</artifactId>
    <version>5.0.2.RELEASE</version>
</dependency>

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aop</artifactId>
    <version>5.0.2.RELEASE</version>
</dependency>

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aspects</artifactId>
    <version>5.0.2.RELEASE</version>
</dependency>

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context-support</artifactId>
    <version>5.0.2.RELEASE</version>
</dependency>

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-expression</artifactId>
    <version>5.0.2.RELEASE</version>
</dependency>

<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-core</artifactId>
    <version>5.2.12.Final</version>
</dependency>

<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-jpamodelgen</artifactId>
    <version>5.2.12.Final</version>
</dependency>

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.1.10</version>
</dependency>

<dependency>
    <groupId>org.springframework.data</groupId>
    <artifactId>spring-data-jpa</artifactId>
    <version>1.11.3.RELEASE</version>
</dependency>

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.12</version>
</dependency>

2.接下来创建一个 User 实体类

@Entity(name = "user")
public class User {

    private Integer id;
    private String username;
    private String address;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }
}

3.在resources 目录下创建一个 applicationContext.xml 文件,并配置Spring 和 Jpa,如下:

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:jpa="http://www.springframework.org/schema/data/jpa"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:context="http://www.springframework.org/schema/context">

    <context:property-placeholder location="classpath:db.properties"/>

    <context:component-scan base-package="com.wxy"/>

    <bean class="com.alibaba.druid.pool.DruidDataSource" id="dataSource">
        <property name="driverClassName" value="${db.driver}"/>
        <property name="url" value="${db.url}"/>
        <property name="username" value="${db.username}"/>
        <property name="password" value="${db.password}"/>
    </bean>

    <bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" id="entityManagerFactory">
        <property name="dataSource" ref="dataSource"/>
        <property name="jpaVendorAdapter">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/>
        </property>
        <property name="packagesToScan" value="com.wxy.model"/>
        <property name="jpaProperties">
            <props>
                <prop key="hibernate.show_sql">true</prop>
                <prop key="hibernate.format_sql">true</prop>
                <prop key="hibernate.hbm2ddl.auto">update</prop>
                <prop key="hibernate.dialect">org.hibernate.dialect.MySQL57Dialect</prop>
            </props>
        </property>
    </bean>

    <bean class="org.springframework.orm.jpa.JpaTransactionManager" id="transactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory"/>
    </bean>

    <tx:annotation-driven transaction-manager="transactionManager"/>
    <!-- 配置jpa -->
    <jpa:repositories base-package="com.wxy.dao"
                      entity-manager-factory-ref="entityManagerFactory"/>

</beans>

4.配置完成后,就可以在 com.wxy.dao 包下创建相应的 Repository 了,如下:

public interface UserDao extends Repository<User,Integer> {
    //根据 id 去查询 User 对象
    User getUserById(Integer id);

}

5.创建 Service 和 Controller 来调用这个方法,如下:

@Service
@Transactional
public class UserService {
    @Resource
    UserDao userDao;

    public User getUserById(Integer id){

        return userDao.getUserById(id);

    }

    public void test(){
        ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserService userService = ctx.getBean(UserService.class);
        User user = userService.getUserById(1);
        System.out.println(user);
    }
}

由此就可以查到ID为1的用户信息…接下来我们最后再来简单介绍下关于上面的一些关键词或者扩展

什么是 Repository ?

上面自定义的 UserDao 接口实现了 Repository 接口,这个 Repository 有什么作用呢?首先来看 Repository 的一个继承关系图:
在这里插入图片描述

  • Repository 接口是 Spring Data 的一个核心接口,不提供任何方法,开发者需要在自己定义的接口中声明需要的方法 public interface Repository<T, ID extends Serializable> { }
  • 如果定义的接口继承了 Repository, 则该接口会被 IOC 容器识别为一个 Repository Bean,进而纳入到 IOC 容器中,进而可以在该接口中定义满足一定规范的方法
  • Spring Data可以只定义接口,只要遵循 Spring Data 的规范,就无需写实现类。
  • 与继承 Repository 等价的一种方式,就是在持久层接口上使用 @RepositoryDefinition 注解,并为其指定 domainClass 和 idClass 属性,如下:
@RepositoryDefinition(domainClass = User.class, idClass = Integer.class)
public interface UserDao
{
    User findById(Integer id);
    List<User> findAll();
}

简单条件查询

按照 Spring Data 的规范,查询方法以 find | read | get 开头,涉及条件查询时,条件的属性用条件关键字连接,要注意的是:条件属性以首字母大写,如:定义一个 Entity 实体类:

class User{
   private String firstName;
   private String lastName;
}

使用 And 条件连接时,条件的属性名称与个数要与参数的位置与个数一一对应,如下:

findByLastNameAndFirstName(String lastName,String firstName);

查询举例:

按照 id 查询

User getUserById(Integer id);

查询所有年龄小于 XX 岁的人

List<User> findByAgeLessThan(Integer age);

查询所有姓 X 的人

List<User> findByUsernameStartingWith(String u);

查询所有姓 X 的或者年龄大于 XX 岁的

List<User> findByUsernameStartingWithOrAgeGreaterThan(String name, Integer age);

查询所有角色为 1 的用户

List<User> findByRole_Id(Integer id);

注解辅助

1.@Query 注解

如果查询关键字并不能满足查询需求,可以使用 @Query 关键字,来自定义查询 SQL,如下:

@Query("select u from user u where id=(select max(id) from user)")
User getMaxIdUser();

如果查询有参数的话,参数有两种不同的传递方式

利用下标索引传参,索引参数如下所示,索引值从1开始,查询中 ”?X” 个数需要与方法定义的参数个数相一致,并且顺序也要一致:

@Query("select u from t_user u where id>?1 and username like ?2")
List<User> selectUserByParam(Long id, String name);

命名参数这种方式可以定义好参数名,赋值时采用@Param(“参数名”),而不用管顺序:

@Query("select u from t_user u where id>:id and username like :name")
List<User> selectUserByParam2(@Param("name") String name, @Param("id") Long id);

使用原生的 SQL 查询,如下:

@Query(value = "select * from t_user",nativeQuery = true)
List<User> selectAll();

2.@Modifying 注解

涉及到数据修改操作,可以使用 @Modifying 注解,@Query 与 @Modifying 这两个注解一起声明,可定义个性化更新操作,例如涉及某些字段更新时最为常用,示例如下:

@Modifying
@Query("update user set age=:age where id>:id")
int updateUserById(@Param("age") Integer age, @Param("id") Integer id);

结语:到底啦…

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值