一、什么是JPA
JPA(Java Persistence API)定义了一系列对象持久化的标准,目前实现这一规范的产品有Hibernate、TopLink等。
二、Mysql数据库示例
1、在application.yml文件中增加数据库访问的配置
ddl-auto:可选属性有以下几种。
create 每次创建一个新表,那么之前表中的数据都会丢掉
update 表不存在的时候才会建立新表,如果存在则不会新建,所以原有数据不会丢
create-drop 每次新建一个表,而且服务停掉,那么所建立的表会随之删除
none 见名知意,就是什么都不做,不会给帮你建表,只能使用现有的表
validate 会将实体类和表进行一个验证,如果不一致会报错
2、新建实体类
package com.zmfx.jpa;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
@Entity
public class Dog {
/*
如果这些注解所在的包,javax.persistence不能导入。可能是缺少依赖
可以在pom中加入Javax Persistence API 的依赖
*/
@Id
@GeneratedValue
private Integer id;//编号
private Integer age;//年龄
private String name;//名字
public Dog() {
}
public Dog(Integer id, Integer age, String name) {
this.id = id;
this.age = age;
this.name = name;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
3、编写Repository接口类
这里需要继承JpaRepository这个类,这样我们就可以使用底层帮我们实现好的一些代码
相当于我们之前了解到的持久层(数据访问层),用于获取数据库中的数据。
4、编写Serivce层
按照策略模式,我们应当一个接口,然后对应实现类。由于这里业务比较简单,我们就不那么费事了。可能这层我在下面都不写。
5、编写Controller层
根据访问信息,进行相应的业务处理,页面展示。
三、RestFul API
1、查询所有,findAll()方法的使用。GET请求
Repository接口类
package com.zmfx.jpa;
import org.springframework.data.jpa.repository.JpaRepository;
/**
* 这个接口需要继承一个接口JpaRepository
* 这样就可以使用底层为我们编写好的一些通用方法
*/
public interface DogRepository extends JpaRepository<Dog,Integer> {
}
Controller层
package com.zmfx.jpa;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* 控制层
*/
@RestController
public class DogController {
//因为业务太简单,所有我们省略service层,直接调用数据访问层的代码
@Autowired
private DogRepository dogRepository;
/**
* 查询所有女生列表
* @return
*/
@GetMapping(value="/dogs")
public List<Dog> dogList(){
return dogRepository.findAll();//findAll()方法是底层帮我没实现好的
}
}
这里推荐一个软件PostMan,可以模拟前端的http访问,可以不用编写页面
2、根据id查询一条记录,findById()的使用,GET请求
在controller中新加以下代码
/**
* 根据id查询指定的Dog
* @param id
* @return
*/
@GetMapping(value = "/dog/{id}")
public Optional<Dog> findDogById(@PathVariable("id") Integer id){
return dogRepository.findById(id);//注意这个方法的返回值
}
然后,使用PostMan进行访问,展示如下:
3、添加一个Dog,save()方法的使用,POST请求
controller层中新加以下代码
/**
* 添加一个Dog
* @param age
* @param name
* @return
*/
@PostMapping(value = "/addDog")
public Dog addDog(@RequestParam("age") Integer age,
@RequestParam("name") String name){
Dog dog=new Dog();
dog.setAge(age);
dog.setName(name);
return dogRepository.save(dog);
}
然后用PostMan进行访问,展示效果如下:
4、更新dog的信息,save()方法的使用,Put请求
在controller增加下面代码
/**
* 更新Dog信息
* @param id
* @param age
* @param name
* @return
*/
@PutMapping(value = "updateDog/{id}")
public Dog updateDog(@PathVariable("id") Integer id,
@RequestParam("age") Integer age,
@RequestParam("name") String name){
Dog dog=new Dog();
dog.setId(id);
dog.setName(name);
dog.setAge(age);
System.out.println(dog);
return dogRepository.save(dog);//注意这里使用save()方法,根据主键,所以主键不能更改
}
这里使用PostMan的PUT请求,注意使用x-www-form-urlencoded进行传参
访问后的效果应当如下:
5、删除一条记录,deleteById()方法,DELETE请求
controller中加入以下代码:
/**
* 删除一条记录
* @param id
*/
@DeleteMapping(value = "/del/{id}")
public void delDogById(@PathVariable("id") Integer id){
dogRepository.deleteById(id);
}
PostMan中使用DELETTE请求,因为没有返回值,所以需要到数据库中查看效果
6、根据年龄来查询,自己在Repository中定义
DogRepository中变为
package com.zmfx.jpa;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;
/**
* 这个接口需要继承一个接口JpaRepository
* 这样就可以使用底层为我们编写好的一些通用方法
*/
public interface DogRepository extends JpaRepository<Dog,Integer> {
//通过年龄来查询
List<Dog> findByAge(Integer age);//注意方法名的格式,findBy+属性名。
}
Controller中新增代码
/**
* 根据年龄来查询
*/
@GetMapping(value = "/dogs/{age}")
public List<Dog> dogList(@PathVariable("age")Integer age){
return dogRepository.findByAge(age);
}
然后使用PostMan进行访问,展示如下:
四、事务管理
1、加入事务之前
controller层加入代码
//这里涉及到事务,所以我们加入service的依赖
@Autowired
private DogService dogService;
/**
* 事务测试的方法
*/
@GetMapping(value = "/dogs/tx")
public void txTest(){
System.out.println("进入了controller");
dogService.addTwoDog();
}
service层代码,这里用到了事务,所以要新建一个DogService类
package com.zmfx.jpa;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class DogService {
@Autowired
private DogRepository dogRepository;
/**
* 同时添加两条记录
*/
public void addTwoDog(){
//模拟两条数据
Dog dog1=new Dog();
dog1.setAge(2);
dog1.setName("小黑1");
//模拟第二条数据
Dog dog2=new Dog();
dog2.setAge(2);
dog2.setName("小黑2");
System.out.println("进入了service");
//将数据插入到数据库
dogRepository.save(dog1);
System.out.println(5/0);//模拟异常
dogRepository.save(dog2);
}
}
然后使用 http://127.0.0.1:8083/dev/dogs/tx 进行访问,我们发现后台抛出异常,但是数据库还是添加了第一条的记录。
2、加入事务之后
我们就能够让小黑1 和 小黑2 同生共死了。
其它的都不变,然后再需要添加事务的方法上,添加一个@Transactional注解。也就是service的 public void addTwoDog()上加入注解
package com.zmfx.jpa;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class DogService {
@Autowired
private DogRepository dogRepository;
/**
* 同时添加两条记录
*/
@Transactional //加入事务控制
public void addTwoDog(){
//模拟两条数据
Dog dog1=new Dog();
dog1.setAge(2);
dog1.setName("小黑1");
//模拟第二条数据
Dog dog2=new Dog();
dog2.setAge(2);
dog2.setName("小黑2");
System.out.println("进入了service");
//将数据插入到数据库
dogRepository.save(dog1);
System.out.println(5/0);//模拟异常
dogRepository.save(dog2);
}
}
然后删除数据库中,小黑1这条记录,重启springboot服务,再次访问 http://127.0.0.1:8083/dev/dogs/tx 。
还是那个异常,然后去看数据库,发现两条记录都没有添加进来。事务控制添加成功。