概念:
JPA顾名思义就是Java Persistence API的意思,是JDK 5.0注解或XML描述对象-关系表的映射关系,并将运行期的实体对象持久化到数据库中。
优势:
JPA本身就是一套标准,就和jdbc一样,不同的上场都是可以来进行实现。目前使用的比较多的都是hibernate的实现。 然而在SpringBoot中我们可以无缝的集成Spring-data-jpa, 简答介绍一个Spring-data. 他也是属于Spring家族的一个产品,主要就是用来封装各种中间件的操作,比如Spring-data-jdbc,就是我们浅浅讲到的jdbcTemplate, 还有spring-data-jpa用来实现JPA, Spring-data-redis封装操作redis的api, 还有spring-data-mongodb, spring-data-elasticsearch,等等。
SpringData所包含的项目如下:
由于产品本身都是spring的,所以和spring的集成有着得天独厚的优势。并且也直接为springBoot提供了相应的starter,我们引入后就可以直接操作,非常方便。
JPA仅仅是一种规范,也就是说它仅仅定义了一些接口,而接口是需要实现才能工作的。所以底层需要某种实现,而Hibernate就是实现了JPA接口的ORM框架。
SpringDataJpa是Spring提供的一套简化JPA开发的框架,按照约定好的方法命名规则来创建DAO层接口,就可以在不写接口实现的情况下,实现对数据库的访问和操作。并且提供了一些常用的增删改查等方法的直接操作。 SpringDataJpa可以理解为JPA规范的再次封装抽象,底层还是使用了Hibernate的Jpa技术实现。
我们还是先拉取一个feature/jpa的分支,防止和前面的mybatis冲突。这个分支里只负责集成JPA的操作。
xml复制代码<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- MySQL连接 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
通过观察依赖包,我们也能够发现其实他还是使用了hibernate:
在spring的配置文件application.yml中配置数据库相关信息:
yml复制代码spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/springboot_learning?serverTimezone=Asia/Shanghai&characterEncoding=utf-8
username: root
password: root
jpa:
show-sql: true # 默认false,在日志里显示执行的sql语句
database: mysql
database-platform: org.hibernate.dialect.MySQL5Dialect
hibernate:
ddl-auto: update #指定为update,每次启动项目检测表结构有变化的时候会新增字段,表不存在时会 新建,如果指定create,则每次启动项目都会清空数据并删除表,再新建
naming:
#指定jpa的自动表生成策略,驼峰自动映射为下划线格式7
implicit-strategy: org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyJpaImpl
#physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
在Jpa中,有自己独立风格的实体,一般来讲就是有一些独特的注解来定义实体。 Jpa是一个比较完全式的ORM框架,就是可以完全通过实体映射数据库,甚至我们可以根据实体去生成数据库。
我们先来看实体的案例,还是以User为例。
java复制代码/**
* @className: User
* @description:
* @author: sh.Liu
* @date: 2022-01-14 16:35
*/
@Data
@Entity
@Table(name = "t_user")
public class User {
/**
* 主键生成策略: 自增
*/
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String name;
private Integer age;
private String address;
private Date createTime;
private Date updateTime;
}
这里有这么几个特殊的注解。
@Entity: 标识这是一个实体类
@Table: 标识与之映射的表名
@Id: 标识数据库主键
@GeneratedValue: 标识主键生成策略,这里是自增。
Dao层主要处理和数据库的交互,这里我们可以使用JPA为我们提供的基类:JpaRepository,里面包含了大部分常用操作。只需集成即可。
java复制代码package com.lsqingfeng.springboot.dao;
import com.lsqingfeng.springboot.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;
import java.io.Serializable;
public interface UserDao extends JpaRepository<User,Integer>, Serializable {
}
接下来就可以在Service中直接调用Dao层,完成常用功能的开发,然后在Controller层中调用Service,将整个流程串起来。
java复制代码package com.lsqingfeng.springboot.service.impl;
import com.lsqingfeng.springboot.dao.UserDao;
import com.lsqingfeng.springboot.entity.User;
import com.lsqingfeng.springboot.service.UserService;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* @className: UserServiceImpl
* @description:
* @author: sh.Liu
* @date: 2022-01-17 13:56
*/
@Service
public class UserServiceImpl implements UserService {
private final UserDao userDao;
public UserServiceImpl(UserDao userDao) {
this.userDao = userDao;
}
@Override
public User getUserById(Integer id) {
return userDao.getById(id);
}
@Override
public List<User> listUser() {
return userDao.findAll();
}
@Override
public int save(User user) {
userDao.save(user);
return user.getId();
}
@Override
public int update(Integer id, User user) {
// 有id则更新,无id则新增
user.setId(id);
userDao.save(user);
return id;
}
@Override
public int delete(Integer id) {
User user = new User();
user.setId(id);
userDao.delete(user);
return id;
}
}
通过postman调用相关接口进行测试。
查看数据库:
时间值没有,因为我们没有在新增的时候设置当前时间。
再试试修改和查询
新增。
现在我们的DAO层用的是JPA自带的通过继承一个基类的常用操作来实现的。那如果说我们有一个需求需要我们自己写一些sql应该如何实现呢。我们来实现一个根据名字查询的接口。
首先在DAO层定义一个接口。
java复制代码public interface UserDao extends JpaRepository<User,Integer>, Serializable {
/**
*
* @param name
* @return
*/
@Query("select u from User u where u.name = ?1")
User getByName(String name);
}
然后在Service层和Controller层调用这个方法。查看效果。
java复制代码 @GetMapping("getByName")
public Result getByName(String name){
return Result.success(userService.getByName(name));
}
修改下数据库数据。
查询结果:
这里要注意的是: 我们在Query注解上写的是HQL语句,也就是默认操作的是对象。所以是from User, 也就是用对象去操作数据库,如果我们想要写原生sql,那么写法如下:
java复制代码@Query("select u from t_user u where u.name = ?1",nativeQuery = true)
User getByName(String name);
关于JPA的简单集成大概就介绍这么多,JPA的思想主要是通过对象操作数据库,相比于mybatis更加ORM, 所以相比之下,也有人把mybatis比作是一个半ORM的框架,主要原因就是sql和HQL的区别,这个如果使用的hibernate的同学应该更有感触。
关于JPA和Mybatis的选择问题,这个之一在网络上争论不断,这个其实也没有什么好坏之分,是要能实现我们的目的,选择那种框架只不过是其中的一种手段罢了。而像我确实还是用mybatis-Plus比较多。可能用的多了,也就感觉它更方便一些,下一篇文章咱们讲讲mybatis的升级版,mybatisPlus的用法。
另: 配套项目代码已托管中gitCode: gitcode.net/lsqingfeng/…