spring操作数据库,不能不提到spring data,它作为spring下一个覆盖甚广的子项目,为各类数据存储结构的存取访问提供了简单且相对统一的访问方式。他不是一个完整的数据库持久化框架,而更像是一种统筹全局的DAO存取标准或规范,无论你使用哪种持久化框架、访问何种类型的数据存储(关系型、NoSQL,还有诸如redis、ES、甚至hadoop相关)。
作为springboot大繁至简运动的重要一环,数据库操作这部分当然由spring data来完成。
spring boot中使用springdata的基本步骤
POM文件中需要引入新依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<version>1.5.10.RELEASE</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
我们今天在springboot项目中使用spring data,配置hibernate的方式来操作数据库。
首先我们在上个项目的springboot配置文件application.yml中加入数据库的配置。注意datasource和jpa两项配置是在spring下profile同一级。
这里值得注意的是jpa下我们配置hibernate,ddl-auto配置成create代表一会儿数据库会自动根据我们配置注解好的类生成一个与之对应的数据表。
spring:
profiles:
active: prod
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/spbdb
username: root
password:
jpa:
hibernate:
ddl-auto: create
show-sql: true
新建一个宠物类,注意哪几个注解,是何意思很明白了无须多言。
package com.happybks.pets;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
@Entity
public class PetEntity {
@Id
@GeneratedValue
private Integer id;
private String breedType;
private Double price;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getBreedType() {
return breedType;
}
public void setBreedType(String breedType) {
this.breedType = breedType;
}
public Double getPrice() {
return price;
}
public void setPrice(Double price) {
this.price = price;
}
}
(本文出自oschina的博主happBKs君的博文:https://my.oschina.net/happyBKs/blog/1623591)
通过启动日志可以看到,框架为我们自动将PetEntity类建立的一个可以与之一一映射的表,名字叫做pet_entity。字段名称也有表换,驼峰命名风格的类属性名称全部变成了小写靠下划线连接的字段名称。
但是请注意,你会发现操作日志是,先删除表,再新建。原因是我们在配置文件里配置了:
jpa: hibernate: ddl-auto: create
所以,不管我们愿不愿意,或者里面是否有表存在,是否有数据存在,都会把表删除然后重建。这显然不大合适。
ddl的模式有好几种:
create的意思是每次都新建,如果存在删除表。
create-drop的意思是每次新建,用完程序结束时就删表。
none就是不进行DDL的任何操作。
update是当必要时才进行DDL,修改表定义。
validate是验证库是否有变化,如有有则报错。
spring data操作数据库异常的简单和方便,简单到你不必谢一句sql、hql等语句,甚至都需要去声明和实现任何DAO方法。只需定义一个继承了JpaRepository接口的DAO接口,并且无须实现任何方法。是的,就一个空接口即可。
package com.happybks.pets;
import org.springframework.data.jpa.repository.JpaRepository;
public interface PetRepository extends JpaRepository<PetEntity,Integer> {
}
你不需要实现任何接口方法,只要定义一个接口继承JpaRepository接口即可。唯一要注意的是,泛型参数需要指定持久化的对象类名和主键Id类型。
之后我们就可以直接使用这个接口来调用其里面的方法来DAO操作了,是的,spring data已经帮我们都实现了,我们直接用即可。
spring data以restful风格增删改查
我们编写一个控制器类,并将增删改查各个操作封装成服务。
package com.happybks.pets;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@Controller
@RequestMapping("/petdata")
public class PetDataController {
@Autowired
PetRepository petRepository;
//查询所有
@GetMapping("/find_all")
@ResponseBody
public List<PetEntity> petList() {
return petRepository.findAll();
}
//添加
@PostMapping("/add")
@ResponseBody
public PetEntity petAdd(@RequestParam("breedType") String breedType, @RequestParam("price") Double price) {
PetEntity petEntity = new PetEntity();
petEntity.setBreedType(breedType);
petEntity.setPrice(price);
return petRepository.save(petEntity);
}
//按照id查询一个
@GetMapping("/find/{id}")
@ResponseBody
public PetEntity petFindOne(@PathVariable("id") int id) {
return petRepository.findOne(id);
}
//更新
@PutMapping("/update/{id}")
@ResponseBody
public PetEntity petUpdate(@PathVariable("id") int id,
@RequestParam("breedType") String breedType, @RequestParam("price") Double price) {
PetEntity petEntity = new PetEntity();
petEntity.setId(id);
petEntity.setBreedType(breedType);
petEntity.setPrice(price);
return petRepository.save(petEntity);
}
//删除
@DeleteMapping("/delete/{id}")
@ResponseBody
public String petDelete(@PathVariable("id") Integer id) {
petRepository.delete(id);
return id + " is deleted!";
}
}
查询所有
我们现在数据表中插入两条记录
INSERT INTO `spbdb`.`pet_entity` (`breed_type`, `price`) VALUES ('秋田犬', '50000');
INSERT INTO `spbdb`.`pet_entity` (`breed_type`, `price`) VALUES ('布偶猫', '20000');
成功插入后,我们开始编写查询方法。
请求运行:http://localhost:8689/happybks/petdata/find_all
插入数据
运行请求,注意这里是Post方法,且Body里表单参数需要x-www-form0-urlencoded内容类型来请求。
http://localhost:8689/happybks/petdata/add
查看数据表,发现二哈已经进去了。
按主键查询一条数据
运行请求 http://localhost:8689/happybks/petdata/find/1
运行请求 http://localhost:8689/happybks/petdata/find/8
无数据返回为空,但是response的状态仍是200
修改数据
运行请求:http://localhost:8689/happybks/petdata/update/3
我们来把哈士奇改成二哈,价钱涨到8888
注意,修改数据我们用的是PUT方法,是的,在restfule风格的接口里,update操作希望以PUT方法来完成。这里需要注意的是因为tomcat版本等原因,默认情况下可能没有吧http协议的put和delete方法开放,需要自行改一下配置,办法网上根据具体服务器中间件自己查查吧。(例如:https://zhidao.baidu.com/question/1757878461182947148.html)
查询数据库,哈士奇变二哈,价钱8888
删除数据
俗话说,二哈拆家。我们现在来看看如何删除它。
注意删除的话,http协议方法用的delete方法。这也是restful风格的规范要求。
好,再看看数据库,二哈已经滚了。
但是请注意:jpaRepository的delete方法如果删除不存在的主键数据是会报错的。
条件查询
前面说了基本的额增删改查,那么如何按照条件进行查询呢?我们是不是无法摆脱必须写sql的命运呢?
spring data已经为我们定制和实现了常见的各类条件查询,当你在你的JapRepository接口中声明定义一个名为findBy开头的方法时,IDE已经为我们建议了如下图所示的方法。这些方法都是关于你某个字段为各类条件的方法名,spring data已经为我们把这些接口方法全部实现,我们只需要按照它的命名规范和IDE的提示建议声明定义一个接口方法即可。是的,只需要声明一下,不需要我们实现。
我们可以看到对于一个字段,它提供了等于、包含、以什么结尾等多种类型的条件,连datetime类型相关的之前和之后都有,真是只有想不到没有spring data做不到。
而且,当条件设计多个字段时,看到下面的提示了吗,它提示And了,接下来怎么操作,聪明的你一定猜得到。
好,我们回到刚才的项目示例,添加一个按照品类名称查询的方法:
声明一个方法。
package com.happybks.pets;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;
public interface PetRepository extends JpaRepository<PetEntity,Integer> {
/**
* 按照种类名称查询
*/
public List<PetEntity> findByBreedType(String breedType);
}
直接使用:
//按照种类名称查询所有
@GetMapping("/findByBreedType")
@ResponseBody
public List<PetEntity> petfindByBreedType(@RequestParam("breedType") String breedType) {
return petRepository.findByBreedType(breedType);
}
运行请求:http://localhost:8689/happybks/petdata/findByBreedType?breedType=布偶猫