SpringBoot入坑-持久化操作
前面内容中我们已经了解到了SpringBoot关于参数传递的相关知识,本篇我们一起来学习一下SpringBoot关于数据库持久化操作的知识,这里我们使用JPA进行数据库的持久化操作。
首先由于我们需要进行数据库的操作,所以我们需要引入mysql的驱动包;这里我们介绍两种数据库持久化操作:JdbcTemplate和JpaRepository所以同样需要引入相应的包;这里为例方便进行数据的返回,我们引入阿里的fastjson:
<!-- mysql数据库连接 start --> <!-- MYSQL --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <!-- Spring Boot JDBC --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <!-- Spring Data JPA --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <!-- mysql数据库连接 end --> <!-- https://mvnrepository.com/artifact/com.alibaba/fastjson --> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.44</version> </dependency>
接下来我们需要配置properties文件:
spring.datasource.url=jdbc:mysql://localhost:3306/girl
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.jpa.show-sql:true
spring.jpa.hibernate.ddl-auto:update
这里设置数据库配置,当然我们也可以使用yml进行数据库连接配置。
有了数据库连接,下面我们配置一下数据库表映射:
@Entity @Table(name = "girl") public class Girl implements Serializable{ private static final long serializableUID = 1L; @Id @GeneratedValue private Integer id; @Column(name = "name") private String name; @Column(name = "age") private Integer age; @Column(name = "birthday") private Date birthday; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } }
对于注解的含义,大家如有不懂可以到度娘搜一下,这里不再赘述。
配置好数据库映射,下面我们就可以进行持久化操作了,这里我们使用三层结构:action、service、dao,来实现持久化操作。这里我们首先使用JdbcTemplate进行持久化操作。
编写我们的dao层业务逻辑:
@Repository public class GirlDao { @Autowired private JdbcTemplate jdbcTemplate; public List<Girl> findGirls(){ return jdbcTemplate.query("SELECT * FROM girl", new RowMapper<Girl>(){ @Override public Girl mapRow(ResultSet resultSet, int i) throws SQLException { Girl girl = new Girl(); girl.setId(resultSet.getInt("id")); girl.setName(resultSet.getString("name")); girl.setAge(resultSet.getInt("age")); girl.setBirthday(resultSet.getDate("birthday")); return girl; } }); } }
这里简单说一下注解 @Service用于标注业务层组件、@Controller用于标注控制层组件(如struts中的action)、@Repository用于标注数据访问组件,即DAO组件、@Component泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注。
下面编写我们的service层:
@Service public class GirlService { @Autowired private GirlDao girlDao; public List<Girl> findGirls(){ List<Girl> girls = girlDao.findGirls(); return girls; } }
通过@Autowired注解将Dao层注入
最后是我们的控制层Action:
@RestController public class GirlAction { @Autowired private GirlService girlService; @RequestMapping(value = "/findGirls", method = RequestMethod.GET) public String findGirls(){ List<Girl> girls = girlService.findGirls(); return JSON.toJSONString(girls); } }
到这里我们的第一个例子就完工了,启动项目,输入http://localhost:8080/findGirls
下面我们来看一下如何JpaRepository进行持久化操作,JPA是需要Provider来实现其功能的,Hibernate就是JPA Provider中很强的一个,应该说无人能出其右。从功能上来说,JPA就是Hibernate功能的一个子集。看到这里我想你大概已经猜到JPA的用法了。下面我们简单一起来使用一下。
这里JpaRepository就类似与上面的Dao层,为了方便理解,这里我就将JpaRepository作为Dao层处理:
public interface GirlDaoJpa extends JpaRepository<Girl, Integer> { List<Girl> getGirlsByName(final String name); @Query("select g from Girl g where g.name = ?1") List<Girl> findGirlsByName(String name); }
你没有看错这里的JpaRepository是一个接口,我们不需要进行接口实现,这就是JpaRepository的便利之处。如何进行使用呢?
编写我们的service层:
@Service public class GirlServiceJpa { @Autowired private GirlDaoJpa girlDaoJpa; public Girl saveGirl(Girl girl){ return girlDaoJpa.save(girl); } public List<Girl> getGirlsByName(String name){ return girlDaoJpa.getGirlsByName(name); } public List<Girl> findGirlsByName(String name){ return girlDaoJpa.findGirlsByName(name); } public List<Girl> findGirls(){ return girlDaoJpa.findAll(); } }
不知道你注意到没有,我并没有在接口中添加save、findAll方法,这是因为JpaRepository默认为我们提供了保存和查询方法。
最后是我们的控制层逻辑:
@RestController public class GirlJpaAction { @Autowired private GirlServiceJpa girlServiceJpa; @RequestMapping(value = "/saveGirlJAP", method = RequestMethod.POST) public String saveGirl(){ Girl girl = new Girl(); girl.setName("jap测试1"); girl.setAge(26); girl.setBirthday(new Date()); girl = girlServiceJpa.saveGirl(girl); if(null != girl && null != girl.getId()){ return "添加成功"; }else{ return "添加失败"; } } @RequestMapping(value = "/getGirlByNameJAP", method = RequestMethod.GET) public String getGirlByName(){ List<Girl> girls = girlServiceJpa.getGirlsByName("abc"); return JSON.toJSONString(girls); } @RequestMapping(value = "/findGirlByNameJAP", method = RequestMethod.GET) public String findGirlByName() { List<Girl> girls = girlServiceJpa.findGirlsByName("abc"); return JSON.toJSONString(girls); } @RequestMapping(value = "/findGirlsJPA", method = RequestMethod.GET) public String findGirls(){ List<Girl> girls = girlServiceJpa.findGirls(); return JSON.toJSONString(girls); } }
到这里我么关于JPA的简单实用介绍完毕,最后我再补充三点。
1、@Query通过注解参数使用:
@Query("select g from Girl g where g.name = :name") List<Girl> findGirlsByName(@Param("name") String name);
2、原生sql使用:
@Query(value = "select * from girl g where g.name like %:name%", nativeQuery = true) List<Girl> findGirlsByName(@Param("name") String name);
注意红色字段,两者的区别之处。
最后聊一下JPA分页查询:
@Override
Page<Girl> findAll(@PageableDefault(page = 1, size = 20, sort = {"id"}, direction = Sort.Direction.ASC) Pageable pageable);
这里的@PageableDefault帮助我们个性化的设置pageable的默认配置。例如@PageableDefault(page = 1, size = 20, sort = { "id" }, direction = Sort.Direction.ASC)表示默认情况下我们按照id正序排列,每一页的大小为20,取第一页数据。
Pageable是一个接口,这里我们需要编写一个接口实现:
public class MyPageable implements Pageable { private int pageNumber;//当前请求分页 private int pageSize;//页容量 private Sort sort;//排序 public void setPageNumber(int pageNumber) { this.pageNumber = pageNumber; } public void setPageSize(int pageSize) { this.pageSize = pageSize; } public void setSort(Sort sort) { this.sort = sort; } @Override public int getPageNumber() { return pageNumber; } @Override public int getPageSize() { return pageSize; } @Override public int getOffset() { return (pageNumber-1)*pageSize; } @Override public Sort getSort() { return sort; } @Override public Pageable next() { this.pageNumber = this.pageNumber+1; return this; } @Override public Pageable previousOrFirst() { this.pageNumber = 0 < this.pageNumber ? this.pageNumber-1 : 1; return this; } @Override public Pageable first() { this.pageNumber = 1; return this; } @Override public boolean hasPrevious() { return false; } }
好了配置好分页持久层逻辑,下面就是我们的service层逻辑了:
public List<Girl> findGirlsByPage(Integer stateIndex, Integer maxNum){ MyPageable myPageable = new MyPageable(); myPageable.setPageNumber(stateIndex); myPageable.setPageSize(maxNum); myPageable.setSort(new Sort(Sort.Direction.DESC, new String[]{"id"})); return girlDaoJpa.findAll(myPageable).getContent(); }
这里注意一个默认查询返回的是Page<Girl>,我们通过getContent可以得到我们的List数据。
最后是我们的action层:
@RequestMapping(value = "/findGirlsByPageJPA", method = RequestMethod.GET) public String findGirlsByPage(){ List<Girl> girls = girlServiceJpa.findGirlsByPage(1, 5); return JSON.toJSONString(girls); }
好了到这里关于SpringBoot的相关内容就先和大家探讨到这里,如果您与更好的见解,欢迎留言讨论。