阿粉之前一直都是使用传统的 SSM 进行开发, 也就我们所说的 Spring,SpringMVC,Mybatis, 即使使用的 SpringBoot, 无非也就是这么集中, 对于持久层框架的选择, 也都是 Mybaits, 但是阿粉无意中发现, 现在使用 SpringDataJPA 的公司也是非常的多的, 所以, 今天阿粉来讲一下这个 SpringDataJPA.
SpringDataJPA 和 Mybaits
什么是 JPA
jpq 是面向对象的思想, 一个对象就是一个表, 强化的是你对这个表的控制. jpa 继承的那么多表约束注解也证明了 jpa 对这个数据库对象控制很注重.
其实, 在阿粉的眼中, JPA 好像就是和 Hibernate 是一样的东西, 区别并不大.
Spring Data JPA 是 Spring Data 的子模块. 使用 Spring Data, 使得基于 "repositories" 概念的 JPA 实现更简单和容易. Spring Data JPA 的目标是大大简化数据访问层代码的编码. 作为使用者, 我们只需要编写自己的 repository 接口, 接口中包含一些个性化的查询方法, Spring Data JPA 将自动实现查询方法.
也就是说是什么呢? 如果我们要写一个根据 ID 查对象的方法比如:
findUserById(String Id) 首先这个方法的名称, 阿粉起名起的还是比较标准的, 如果你在使用 SpringDataJPA 的话, 再 repository 中直接使用这个方法名, 就可以了, 但是如果你使用了 Mybaits 的话, 可能你需要在 xml 文件中, 或者再方法上写 SQL 就比如这个样子,
select * from User where id = "xxxxx";
什么是 Mybaits
mybatis 则是面向 sql, 你的结果完全来源于 sql, 而对象这个东西只是用来接收 sql 带来的结果集. 你的一切操作都是围绕 sql, 包括动态根据条件决定 sql 语句等. mybatis 并不那么注重对象的概念. 只要能接收到数据就好.
而且 MyBatis 对于面向对象的概念强调比较少, 更适用于灵活的对数据进行增, 删, 改, 查, 所以在系统分析和设计过程中, 要最大的发挥 MyBatis 的效用的话, 一般使用步骤则与 hibernate 有所区别:
综合整个系统分析出系统需要存储的数据项目, 并画出 E-R 关系图, 设计表结构
根据上一步设计的表结构, 创建数据库, 表
编写 MyBatis 的 SQL 映射文件, Pojos 以及数据库操作对应的接口方法
而且现在有很多的 Mybaits 的插件, 用于逆向生成 Mybaits 的文件, 比如直接通过你建立的表生成 Dao 文件和 dao.xml 文件.
但是今天阿粉的重点可不是说这个 Mybatis, 而是 SpringDataJPA
接下来阿粉就来详细说说这个 SpringDataJPA
什么是 SpringDataJPA
官方文档先放上
总的来说 JPA 是 ORM 规范, Hibernate 是 JPA 规范的具体实现, 这样的好处是开发者可以面向 JPA 规范进行持久层的开发, 而底层的实现则是可以切换的. Spring Data Jpa 则是在 JPA 之上添加另一层抽象 (Repository 层的实现), 极大地简化持久层开发及 ORM 框架切换的成本.
为什么这么多公司会选择 Mybaits , 而不选择使用 SpringDataJPA 呢?
因为 Spring Data Jpa 的开发难度要大于 Mybatis. 主要是由于 Hibernate 封装了完整的对象关系映射机制, 以至于内部的实现比较复杂, 庞大, 学习周期较长. 这对于现在的快捷式开发显然并不适合, 但是因为某些公司最早的开发, 所以现在很多公司仍然延续使用 Spring Data Jpa 来进行开发, 接下来阿粉就来说说这个 Spring Data Jpa 是如何使用的.
如何使用 SpringDataJPA
我们直接使用 SpringBoot 整合一下 Spring Data Jpa 来进行操作. 来展示如何使用 Spring Data Jpa.
创建一个 SpringBoot 的项目,
然后加入我们的依赖, 或者你在创建的时候就进行选择, 比如选择好我们接下来所需要的所有依赖就像这个样子.
这个时候我们就直接勾选上 lombok, 然后 Springweb, 还有我们的数据库驱动的 Jpa 的依赖.
创建完成, 我们就能看到已经为我们添加好了我们所需要的依赖环境
- org.springframework.boot
- spring-boot-starter-data-jpa
- org.springframework.boot
- spring-boot-starter-Web
- MySQL
- MySQL-connector-java
- runtime
- org.projectlombok
- lombok
- true
- org.springframework.boot
- spring-boot-starter-test
- test
如果不会选依赖的, 各位, 这肯定是一个非常好的方式.
接下来配置一下 YAML 文件
- server:
- port: 8080
- servlet:
- context-path: /
- spring:
- datasource:
- url: jdbc:MySQL://localhost:3306/jpa?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true&useSSL=false
- username: root
- password: 123456
- jpa:
- database: MySQL
- database-platform: org.hibernate.dialect.MySQL5InnoDBDialect
- show-sql: true
- hibernate:
- ddl-auto: update
看, 最后有个 hibernate, 这就是之前阿粉说的, hibernate 提供规范,
ddl-auto
这个参数也是有很多值的, 不同的值代表着不同的内容.
create: 每次运行程序时, 都会重新创建表, 故而数据会丢失
create-drop: 每次运行程序时会先创建表结构, 然后待程序结束时清空表
upadte: 每次运行程序, 没有表时会创建表, 如果对象发生改变会更新表结构, 原有数据不会清空, 只会更新 (推荐使用)
validate: 运行程序会校验数据与数据库的字段类型是否相同, 字段不同会报错
none: 禁用 DDL 处理
然后启动一下, 看看是否成功, 如果出现数据库啥的不合适的, 肯定是帐号和密码写错了, 或者连接的数据库不对, 看着改一下. 有问题就改嘛, 这才是好朋友.
看阿粉启动的还是相对来说很成功的, 接下来我们就得安排一下这个 JPa 的使用方式了.
接下来我们创建好一组内容, Controller,Service,Dao,Entry,
然后是我们实体类的内容和表
- @Data
- @Entity
- @Table(name = "user")
- public class User {
- @Id
- @GenericGenerator(name = "idGenerator", strategy = "uuid")
- @GeneratedValue(generator = "idGenerator")
- private String id;
- @Column(name = "user_name", unique = true, nullable = false, length = 64)
- private String userName;
- @Column(name = "user_password", unique = true, nullable = false, length = 64)
- private String userPassword;
- }
这时候主键阿粉使用的事 uuid 的策略, 但是 Jpa 也是自带主键生成策略的.
TABLE: 使用一个特定的数据库表格来保存主键
SEQUENCE: 根据底层数据库的序列来生成主键, 条件是数据库支持序列. 这个值要与 generator 一起使用, generator 指定生成主键使用的生成器 (可能是 orcale 中自己编写的序列)
IDENTITY: 主键由数据库自动生成 (主要是支持自动增长的数据库, 如 MySQL)
AUTO: 主键由程序控制, 也是 GenerationType 的默认值
这时候 Dao 需要继承一下 Jpa 的接口了.
public interface UserDao extends JpaRepository {}
JpaRepository 里面可是自带了不少方法的,
- List findAll();
- List findAll(Sort sort);
- List findAllById(Iterable ids);
- List saveAll(Iterable entities);
- void flush();
- S saveAndFlush(S entity);
- List saveAllAndFlush(Iterable entities);
- /** @deprecated */
- @Deprecated
- default void deleteInBatch(Iterable entities) {
- this.deleteAllInBatch(entities);
- }
- void deleteAllInBatch(Iterable entities);
- void deleteAllByIdInBatch(Iterable ids);
- void deleteAllInBatch();
- /** @deprecated */
- @Deprecated
- T getOne(ID id);
- T getById(ID id);
- List findAll(Example example);
- List findAll(Example example, Sort sort);
方法是真的不少, 主要还是看你怎么使用,
我们来试试吧.
- @RestController
- @RequestMapping("/users")
- public class UserController {
- @Autowired
- private UserService userService;
- @RequestMapping(value = "/save")
- public User saveUser() {
- User user = new User();
- user.setUserName("zhangSan");
- user.setUserPassword("123456");
- return userService.saveUser(user);
- }
- }
Service 方法直接调用 UserDao 中的保存, 也就是父类中的 save 方法.
- public interface UserService {
- User saveUser(User user);
- }
- @Service
- public class UserServiceImpl implements UserService {
- @Autowired
- private UserDao userDao;
- @Override
- public User saveUser(User user) {
- return userDao.save(user);
- }
- }
然后我们调用方法, 再看看数据库
我们成功插入进去了一条数据, 也就是说, 这个方法是没什么毛病的呀, 那是不是可以把所有的方法都挨着试一遍.
阿粉这里就不再一一的演示了, 毕竟很简单的.
如果你觉得这些方法不能够满足你的使用, 那么你就得继续看了, 毕竟确实不能满足日常需求呀. 就比如说多参数的, 查询, 这时候就有 And 出现, 如果有需要, 你就得专门的再去 官方文档中查看了
Jpa 官方文档
如果你想使用一下 SQL 语句呢?
这时候, 你就得写一个自定义的方法, 然后再 Dao 你自定义方法上面加入 @Query 注解然后在其中写你的 SQL 语句.
- @Query("select * from User where u.user_password = ?1")
- User getByPassword(String password);
?1 这个实际上就是代表的参数, 如果有多个参数, 可以使使用? 2
其实和 Mybaits 的 #{0} 看起来很类似.
Jpa 的简单使用, 你学会了么? 说实在的, 感觉这种方式, 把代码和 SQL 都融合在了一起, 感觉确实不是很好, 至少从观看上面来说, 体验就非常不好.
来源: http://developer.51cto.com/art/202201/699265.htm