Spring-Data-JPA尝鲜:快速搭建CRUD+分页后台实例
前言:由于之前没有接触过hibernate框架,但是最近看一些博客深深被它的“效率”所吸引,所以这就来跟大家一起就着一个简单的例子来尝尝spring全家桶里自带的jpa的鲜
spring-data-jpa 简介
jpa(java persistence api)是sun官方提出的java持久化规范。它为java开发人员提供了一种对象/关联映射工具来管理java应用中的关系数据。他的出现主要是为了简化现有的持久化开发工作和整合orm技术,结束现在hibernate,toplink,jdo等orm框架各自为营的局面。值得注意的是,jpa是在充分吸收了现有hibernate,toplink,jdo等orm框架的基础上发展而来的,具有易于使用,伸缩性强等优点。从目前的开发社区的反应上看,jpa受到了极大的支持和赞扬,其中就包括了spring与ejb3.0的开发团队。
注意:jpa是一套规范,不是一套产品,那么像hibernate,toplink,jdo他们是一套产品,如果说这些产品实现了这个jpa规范,那么我们就可以叫他们为jpa的实现产品。
spring data jpa 是 spring 基于 orm 框架、jpa 规范的基础上封装的一套jpa应用框架,可使开发者用极简的代码即可实现对数据的访问和操作。它提供了包括增删改查等在内的常用功能,且易于扩展!学习并使用 spring data jpa 可以极大提高开发效率!(spring data jpa让我们解脱了dao层的操作,基本上所有crud都可以依赖于它来实现)
摘自:
hibernate 和 mybatis 简单对比
由于jpa底层干活的仍然是hibernate框架,而我们之前学习的只有mybatis相关的东西,所以在尝鲜之前还是有必要简单了解一下两者的区别:
hibernate的优势:
- hibernate的dao层开发比mybatis简单,mybatis需要维护sql和结果映射。
- hibernate对对象的维护和缓存要比mybatis好,对增删改查的对象的维护要方便。
- hibernate数据库移植性很好,mybatis的数据库移植性不好,不同的数据库需要写不同sql。
- hibernate有更好的二级缓存机制,可以使用第三方缓存。mybatis本身提供的缓存机制不佳。
mybatis的优势:
- mybatis可以进行更为细致的sql优化,可以减少查询字段。
- mybatis容易掌握,而hibernate门槛较高。
简单总结:
- mybatis:小巧、方便、高效、简单、直接、半自动化
- hibernate:强大、方便、高效、复杂、间接、全自动化
crud + 分页后台实例
下面我们来快速搭建一个使用spring-data-jpa的crud+分页后台实例,并且我们会直接使用到restful api(不熟悉的同学)
第一步:新建springboot项目
打开idea新建一个springboot项目,不熟悉springboot的同学请右转:,然后在pom.xml中添加以下依赖:
<!-- mysql--> <dependency> <groupid>mysql</groupid> <artifactid>mysql-connector-java</artifactid> <version>5.1.21</version> </dependency> <!-- jpa--> <dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-data-jpa</artifactid> </dependency>
然后把application.properties弄成这个样子:
#数据库 spring.datasource.url=jdbc:mysql://127.0.0.1:3306/testdb?useunicode=true&characterencoding=utf-8 spring.datasource.username=root spring.datasource.password=123456 spring.datasource.driver-class-name=com.mysql.jdbc.driver spring.jpa.properties.hibernate.hbm2ddl.auto=update #显示sql语句 spring.jpa.show-sql=true #不加下面这句则默认创建myisam引擎的数据库 spring.jpa.database-platform=org.hibernate.dialect.mysql5innodbdialect #自己重写的配置类,默认使用utf8编码 spring.jpa.properties.hibernate.dialect=com.wmyskxz.demo.config.mysqlconfig
spring.jpa.properties.hibernate.hbm2ddl.auto
是hibernate的配置属性,其主要作用是:自动创建、更新、验证数据库表结构。该参数的几种配置如下:
- create:每次加载hibernate时都会删除上一次的生成的表,然后根据你的model类再重新来生成新表,哪怕两次没有任何改变也要这样执行,这就是导致数据库表数据丢失的一个重要原因。
- create-drop:每次加载hibernate时根据model类生成表,但是sessionfactory一关闭,表就自动删除。
- update:最常用的属性,第一次加载hibernate时根据model类会自动建立起表的结构(前提是先建立好数据库),以后加载hibernate时根据model类自动更新表结构,即使表结构改变了但表中的行仍然存在不会删除以前的行。要注意的是当部署到服务器后,表结构是不会被马上建立起来的,是要等应用第一次运行起来后才会。
- validate:每次加载hibernate时,验证创建数据库表结构,只会和数据库中的表进行比较,不会创建新表,但是会插入新值。
然后新建一个【config】包,创建一个【mysqlconfig】类(上面的spring.jpa.properties.hibernate.dialect
属性就要配置这里的类全路径):
package com.wmyskxz.demo.config; import org.hibernate.dialect.mysql5innodbdialect; public class mysqlconfig extends mysql5innodbdialect { @override public string gettabletypestring() { return "engine=innodb default charset=utf8"; } }
第二步:创建好需要的数据库
打开sql服务,建表语句也很简单啦:
create database testdb;
第三步:创建实体类
实体类映射的实际上是数据库表的结构,在适当的包目录下(例如【entity】)下创建好实体类:
package com.wmyskxz.demo.entity; import javax.persistence.column; import javax.persistence.entity; import javax.persistence.generatedvalue; import javax.persistence.id; @entity // 表明这是个实体类 public class user { @id // 表明这个属性是主键 @generatedvalue // 自增长 private long id; @column(nullable = false, unique = true) // 不允许为空,属性唯一 private string username; @column(nullable = false) // 不允许为空 private string password; // getter and setter }
第四步:dao层
新建一个【repository】包,然后新建一个【userrepository】接口,并继承jparepository类:
package com.wmyskxz.demo.repository; import com.wmyskxz.demo.entity.user; import org.springframework.data.jpa.repository.jparepository; public interface userrepository extends jparepository<user, long> { }
继承jparepository需要传入两个参数,一个是实体类user一个是主键的类型long,而凡是继承了jparepository类的就会自动实现很多内置的方法,包括增删改查,以及使用默认支持的pageable对象来进行分页,默认的方法大致如下:
public interface jparepository<t, id> extends pagingandsortingrepository<t, id>, querybyexampleexecutor<t> { list<t> findall(); list<t> findall(sort var1); list<t> findallbyid(iterable<id> var1); <s extends t> list<s> saveall(iterable<s> var1); void flush(); <s extends t> s saveandflush(s var1); void deleteinbatch(iterable<t> var1); void deleteallinbatch(); t getone(id var1); <s extends t> list<s> findall(example<s> var1); <s extends t> list<s> findall(example<s> var1, sort var2); }
第五步:controller层
新建【controller】包,新建一个【usercontroller】类,编写简单的增删改查代码:
package com.wmyskxz.demo.controoler; import com.wmyskxz.demo.entity.user; import com.wmyskxz.demo.repository.userrepository; import org.springframework.beans.factory.annotation.autowired; import org.springframework.data.domain.pagerequest; import org.springframework.data.domain.sort; import org.springframework.web.bind.annotation.*; import java.util.optional; @restcontroller // 表明这是一个controller并返回json格式 public class usercontroller { @autowired private userrepository userrepository; @getmapping("/getone") public optional<user> getoneuserbyid(@requestparam long id) { return userrepository.findbyid(id); } @getmapping("/all") public iterable<user> getallusers(@requestparam(value = "page", defaultvalue = "0") int page, @requestparam(value = "size", defaultvalue = "5") int size) { page = page < 0 ? 0 : page;// 如果page为负数则修改为0,防止在首页点击上一页发生错误 sort sort = new sort(sort.direction.desc, "id");// 按id倒叙排列 return userrepository.findall(new pagerequest(page, size, sort)); } @postmapping("/add") public string adduser(@requestparam string username, @requestparam string password) { user user = new user(); user.setusername(username); user.setpassword(password); userrepository.save(user);// 注意这里是save return "saved"; } @deletemapping("/delete") public string deleteuserbyid(@requestparam long id) { userrepository.deletebyid(id); return "deleted"; } @putmapping("/update") public string updateuser(user user) { // user user = new user(); // user.setid(id); // user.setusername(username); // user.setpassword(password); userrepository.save(user); return "updated"; } }
上面就直接使用@autowired
自动引入了继承了jparepository的userrepository接口,我们使用它默认的方法已经足够完成我们的基础功能了,值得一提的是我们的getallusers(...)
方法,它往findall()
方法里传入了一个pageable对象,这是spring data库中定义的一个接口,是所有分页相关信息的一个抽象,通过该接口,我们可以得到和分页相关的所有信息(例如pagenumber
、pagesize
等),这样jpa就能够通过pageable参数来得到一个带分页信息的sql语句。
当然上面我们是通过自己创建了一个pageable对象,spring也支持直接获取pageable对象,可以把上面的getallusers(...)
方法改写成下面这样:
@getmapping("/all") public iterable<user> getallusers(@pageabledefault(value = 5, sort = {"id"}, direction = sort.direction.desc) pageable pageable) { return userrepository.findall(pageable); }
默认从第0页开始,也可以自己传入一个page参数,跟上面的是一样的。
第六步:运行项目
上面我们就快速搭建起来了一个基于spring boot和jpa的rest风格的后台增删改查实例,我们把项目跑起来,可以看到数据库自动创建了一些表:
jpa帮我们创建的user表的创建sql如下:
create table `user` ( `id` bigint(20) not null, `password` varchar(255) not null, `username` varchar(255) not null, primary key (`id`), unique key `uk_sb8bbouer5wak8vyiiy4pf2bx` (`username`) ) engine=innodb default charset=utf8;
使用rest测试工具测试
完全符合我们的要求,然后我们使用一些rest的测试工具,来测试上面的功能是否都能正确运行,比如我这里使用的【restlet client】,在chrome商店就可以下载到。
/all
地址测试:
首先先来测试一下http://localhost:8080/all
地址,由于现在数据库还是空的,所以可以看到返回如下:
{ "content": [ ], "pageable": { "sort": { "sorted": true, "unsorted": false, "empty": false }, "offset": 0, "pagenumber": 0, "pagesize": 5, "unpaged": false, "paged": true }, "totalelements": 0, "last": true, "totalpages": 0, "number": 0, "size": 5, "sort": { "sorted": true, "unsorted": false, "empty": false }, "numberofelements": 0, "first": true, "empty": true }
添加用户测试:
然后我们使用http://localhost:8080/add?username=wmyskxz&password=123
地址,添加几个类似的用户信息:
可以看到返回正确的saved
信息:
/getone
地址测试:
我们就直接使用http://localhost:8080/getone?id=1
来获取刚才添加的用户,可以看到返回正确的数据:
{ "id": 1, "username": "wmyskxz", "password": "123" }
修改用户测试:
然后我们使用http://localhost:8080/update?id=1&username=wmyskxz&password=123456
来模拟进行用户密码的修改:
可以看到正确的更新信息updated
,再次查询用户,也能看到正确的数据:
{ "id": 1, "username": "wmyskxz", "password": "123456" }
分页测试:
我们使用添加功能为数据库添加5条以上的数据,然后进行一次查询/all
,可以看到能够按照id
倒叙排列后返回5条数据:
返回的json数据如下:
{ "content": [ { "id": 10, "username": "wmyskxz8", "password": "123" }, { "id": 9, "username": "wmyskxz7", "password": "123" }, { "id": 8, "username": "wmyskxz6", "password": "123" }, { "id": 7, "username": "wmyskxz5", "password": "123" }, { "id": 6, "username": "wmyskxz4", "password": "123" } ], "pageable": { "sort": { "sorted": true, "unsorted": false, "empty": false }, "offset": 0, "pagenumber": 0, "pagesize": 5, "unpaged": false, "paged": true }, "totalelements": 9, "last": false, "totalpages": 2, "number": 0, "size": 5, "sort": { "sorted": true, "unsorted": false, "empty": false }, "numberofelements": 5, "first": true, "empty": false }
删除用户测试:
使用地址http://localhost:8080/delete?id=1
来删除id为1的用户:
能正确看到deleted
信息,并查看数据能够看到数据已经被删除了。
以上,我们就快速搭建好了一个crud+分页的后台实例,还用了比较流行的restful风格,粗略的感受了一下jpa的方便,还是挺爽的..没有复杂的mapper文件,不用自动生成实体,甚至不用管sql,只需要专注在逻辑上就行了,其实简单使用的话以上的东西也能应付一些常见的场景了,后期再深入了解了解吧!
参考资料:
spring boot中使用spring-data-jpa让数据访问更简单、更优雅——程序猿dd
欢迎转载,转载请注明出处!
简书id:
github:
欢迎关注公众微信号:wmyskxz
分享自己的学习 & 学习资料 & 生活
想要交流的朋友也可以加qq群:3382693