概述

Jpa是什么?他是一套规范,类似restful风格一样,都是一套规范。使用Jpa必须按照它的规范来操作数据访问。

SpringDataJpa==Jpa规范+Hibernate底层

为什么要用jpa

Jpa适合什么样的项目呢?我觉得适合非互联网项目,或者说中小型项目,或者说对sql优化不高的项目,或者说需求变更不是太频繁的项目。我们可以一个项目中mybatis+jpa混合使用,对于不需要sql优化的表,jpa使用更加方便。

综合来说,jpa在开发效率上讲绝对是比mybatis方便的。我们可以根据自己的需求,来界定是否使用jpa。

Jpa用起来有多简单呢?只需要写一个接口,然后继承JpaRepository,就可以使用了。

比如我要操作User表,新增一个接口IUserDao继承JpaRepository。

public interface IUserDao extends JpaRepository<User,Integer>,JpaSpecificationExecutor<User> {}

在调用的地方初始化IUserDao

@Autowired
private IUserDao userDao;

最后就是调用的地方写代码即可,增删改查如下,根本不用自己定义一边。

userDao.save(user);增
userDao.delete(1);删
userDao.save(user);改
userDao.findById(1);查

相比mybatis,每个方法都要声明一边,然后写对应的sql,是不是简单了许多?

可能有人会说上边这几个方法使用起来太单一,不能满足我的需求,比如根据用户名查找,根据用户名修改等操作。

别急,我上边只是介绍最基本的操作,你想的这些,Jpa作者都想到了。

比如说根据用户名查找,我们只需要在IUserDao接口中,声明如下方法即可:

public User findByUserName(String userName);

然后在调用的地方,加上如下代码即可。

userDao.findByUserName("zhangsan");

我们也可以这样写:

@Query("from User where userName=?1")
public User findBySql(String userName);

也可以通过条件修改:

@Transactional
@Modifying
@Query("update User set userName=?1 where id=?2")
public int updateBySql(String userName,Integer id);

使用详解

SpringBoot集成Jpa

使用SpringBoot继承Jpa是最简单的。

操作步骤如下:

打开Idea工具;
选择Spring Initializr,下一步;
定义好工程相关信息,下一步;
选择左侧菜单中的SQL,勾选右边的Spring Data JPA ,MySql Driver,JDBC API。下一步;
finish;
初始化后pom.xml文件如下,也可以新建空的maven工程,倒入下边的依赖。

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.7.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.ming</groupId>
<artifactId>springbootjpatest</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springbootjpatest</name>
<description>Demo project for Spring Boot</description>

<properties>
<java.version>1.8</java.version>
</properties>

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>

<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

</project>

工程初始化完毕后,首先新增实体类User。具体注意点,参见代码注释。一定要注意细节,哪个位置没注意,工程就会报错。代码如下:

package com.ming.springbootjpatest.entity;

import javax.annotation.Generated;
import javax.persistence.*;

@Entity
@Table(name = "t_userinfo")//数据库表明
public class User {
@Id//声明id为主键
@GeneratedValue(strategy = GenerationType.IDENTITY)//声明自动增长
@Column(name = "id")//声明数据库对应的字段
private Integer id;
@Column(name = "user_name")//声明数据库对应的字段
//定义字段也是有讲究的,比如首字母小写,后边的驼峰,对应的数据库字段,遇到驼峰用下划线断开
//比如实体类定义的userName,则数据库字段为user_name,
//比如实体类定义的username,则数据库字段也为username
private String userName;
@Column(name = "password")
private String password;

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 getPassword() {
return password;
}

public void setPassword(String password) {
this.password = password;
}

@Override
public String toString() {
return "User{" +
"id=" + id +
", userName='" + userName + '\'' +
", password='" + password + '\'' +
'}';
}
}

然后新增dao层接口IUserDao,代码如下:

public interface IUserDao extends JpaRepository<User,Integer>,JpaSpecificationExecutor<User> {}

然后定义配置文件,在resources目录下新增application.yml,将之前的application.properties文件删掉。配置如下:

server:
port: 8080
servlet:
context-path: /
spring:
datasource:
url: jdbc:mysql://localhost:3306/jpatest?serverTimezone=UTC
username: root
password: 123456
jpa:
database: MySQL
database-platform: org.hibernate.dialect.MySQL5InnoDBDialect #mysql数据库固定配置
show-sql: true #控制台打印sql
hibernate:
ddl-auto: update #update代表数据库没有表的话,会先创建表,有表的话就不创建了。

以上就基本完成了,我们可以在测试类中做各种数据操作了。

有人说数据库表还没有呢啊!这里要告诉大家,程序运行后,Jpa会去数据库查看,如没有表的话,会先创建表,有表的话就不创建了。所以我们不用创建表,jpa帮我们做了。具体配置参见上边ddl-auto字段。

下边就可以在测试类中写一些测试了啦,代码如下:

package com.ming.springbootjpatest;

import com.ming.springbootjpatest.dao.IUserDao;
import com.ming.springbootjpatest.entity.User;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.test.context.junit4.SpringRunner;

import javax.persistence.criteria.*;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Optional;

@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringbootjpatestApplicationTests {
@Autowired
private IUserDao userDao;

/**
* 增加方法
*/
@Test
public void testAdd(){
User user=new User();
user.setUserName("zhangsan1");
user.setPassword("12345");
userDao.save(user);
}

/**
* 批量增加
*/
@Test
public void testAddList(){
List<User> userList=new ArrayList<>();
for(int i=0;i<10;i++){
User user=new User();
user.setUserName("zhangsan_"+i);
user.setPassword("12345_"+i);
userList.add(user);
}
userDao.saveAll(userList);
}
/**
* 通过主键查找
*/
@Test
public void testFindById(){
Optional<User> optionalUser = userDao.findById(1);
User user = optionalUser.get();
System.out.println(user);
}

/**
* 通用查找方法,基本上按照哪个字段查都可以,写起来稍微麻烦一点点。
* 下边是按照userName="zhangsan"去查,如果不用=换作like,就将下边的criteriaBuilder.equal
* 换成criteriaBuilder.like。
*/
@Test
public void testCommonFind(){
Specification<User> specification=new Specification<User>() {
@Override
public Predicate toPredicate(Root<User> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
Path<Object> userName = root.get("userName");
Predicate predicate = criteriaBuilder.equal(userName, "zhangsan");
return predicate;
}
};
Optional<User> optionalUser = userDao.findOne(specification);
User user = optionalUser.get();
System.out.println(user);
}

/**
* 查询所有,如果想通过条件查询,可以根据上边的方式查询。
*/
@Test
public void testFindAll(){
List<User> userList = userDao.findAll();
for(User item:userList){
System.out.println(item);
}
}
@Test
public void testPage(){
//排序
Sort sort=new Sort(Sort.Direction.DESC,"id");
//分页
Pageable pageable=PageRequest.of(0,2,sort);
Page<User> page = userDao.findAll(pageable);
//当前页结果,(0)页
List<User> userList = page.getContent();
//按照每页2条数据,一共有的页数
int totalPages = page.getTotalPages();
//总共有多少条数据
long totalElements = page.getTotalElements();
}

/**
* 通用修改方法,先根据主键查找,然后在修改提交
* 也可以通过sql直接修改.需要在IUserDao接口中定义,这里不再演示。
*/
@Test
public void testUpdate(){
Optional<User> userOptional = userDao.findById(1);
User user = userOptional.get();
user.setUserName("张三");
//主键存在为修改,不存在为新增
userDao.save(user);
}

/**
* 通过主键删除
* 也可以通过sql直接删除.需要在IUserDao接口中定义,这里不再演示
*/
@Test
public void testDelete(){
userDao.deleteById(1);
}
}