Spring Data JPA目前来说是属于一个比较方便的持久层框架了,不仅内部提供了一些简易的增删改查,而且针对一些相对复杂查询也可以通过规范方法的名字来自动实现一些业务逻辑,大大减少了开发周期和代码量。即便是在面对更加复杂的查询,也可以使用@Query注解手写JP QL查询语句进行增删改查。接下来几篇的文章将会集中记录我的Spring Data JPA从入门到删库。
前期准备:spring boot,maven,mysql
1. 创建Spring boot工程:
关于创建工程,没什么可说的,推荐使用Spring boot的官方IDE——STS。当然,如果你是Intellij IDEA党,推荐安装Spring Assistant插件进行创建。
2. 配置Maven依赖,引入所需要的包:
<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency>
3. 配置application.yml,将数据源信息配置进去:
配置示例:
############# # 数据源配置 ############# spring: datasource: url: jdbc:mysql://localhost:3306/spring_data?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8 driver-class-name: com.mysql.cj.jdbc.Driver username: root password: root jpa: database: mysql # 打印sql语句 show-sql: true format-sql: true # 自动更新sql语句 hibernate: ddl-auto: update # mysql5.5以上版本的事务控制 database-platform: org.hibernate.dialect.MySQL5InnoDBDialect
如果数据库还没有创建,注意先创建数据库:
CREATE DATABASE spring_data DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
4. 创建包:
com.createdpro.entity com.createdpro.reposiotry com.createdpro.service
5. 创建实体类:
首先在entity包下创建一个实体类:
User.java
package com.createdpro.entity; import javax.persistence.*; @Entity @Table(name = "user") public class User { @Id @GeneratedValue @Column(name = "user_id") private Integer id; @Column(name = "user_name") private String name; @Column(name = "user_age") private Integer age; 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; } @Override public String toString() { return "User{" + "id=" + id + ", name='" + name + '\'' + ", age=" + age + '}'; } }
接下来在repository包下建立一个持久层类:
UserRepository.java
package com.createdpro.repository; import com.createdpro.entity.User; import org.springframework.data.repository.Repository; import java.util.List; public interface UserRepository extends Repository<User, Integer> { List<User> findAll(); User findByName(String name); void save(User user); void deleteById(Integer id); }
接下来在service包下建立业务层类:
UserService.java
package com.createdpro.service; import com.createdpro.entity.User; import com.createdpro.repository.UserRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.List; @Service public class UserService { @Autowired private UserRepository userRepository; public List<User> findAllUser(){ List<User> users = userRepository.findAll(); return users; } public User findUserByName(String name){ User user = userRepository.findByName(name); return user; } public void save(User user){ userRepository.save(user); } public void deleteUser(Integer id){ userRepository.deleteById(id); } }
建立测试类(src/test/ java),测试效果:
UserTest.java
package com.imooc; import com.imooc.entity.User; import com.imooc.service.UserService; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.context.web.WebAppConfiguration; import java.util.List; @RunWith(SpringRunner.class) @SpringBootTest @WebAppConfiguration public class UserJpaTest { @Autowired private UserService userService; @Before public void init() { System.out.println("开始测试-----------------"); } @After public void after() { System.out.println("测试结束-----------------"); } // 测试查询所有数据 @Test public void findAllTest(){ List<User> allUser = userService.findAllUser(); System.out.println(allUser); } // 测试根据名称查询 @Test public void findByNameTest(){ User user = userService.findUserByName("createdpro"); System.out.println(user); } // 测试保存一个User @Test public void saveTest(){ User user = new User(); user.setId(2); user.setName("alibaba"); user.setAge(16); userService.save(user); } // 测试根据id删除一个用户 @Test public void deleteByIdTest(){ userService.deleteUser(13); } }
说在后面:
解释一下repository中的持久层,为什么我们没有编写sql语句,而是只是凭借一个方法名 findAll() 或者 findByName() 就可以实现对数据库的操作呢?
实际上Spring Data JPA已经在内部帮我们实现了具体的Sql操作,这样可以是我们更加的集中于业务的处理,这也是Spring Data JPA的特点之一。
当然,我们也可以尝试修改一下repository内的方法名。你会发现在对方法名进行随意的修改后,这个查询方法会失效甚至会报错,原因就是如果希望使用repository自动生成SQL操作数据库的话,就必须要遵循Spring Data JPA的一套方法名的命名规则。
首先的命名必须以驼峰式命名法(详见百度),其次以下将会列出部分命名关键字:
And 等价于 SQL 中的 and 关键字,比如 findByUsernameAndPassword(String username, String password); Or 等价于 SQL 中的 or 关键字,比如 findByUsernameOrAddress(String username, String address); Between 等价于 SQL 中的 between 关键字,比如 findBySalaryBetween(int max, int min); LessThan 等价于 SQL 中的 " < ",比如 findBySalaryLessThan(int max); GreaterThan 等价于 SQL 中的" > ",比如 findBySalaryGreaterThan(int min); IsNull 等价于 SQL 中的 " is null ",比如 findByUsernameIsNull(); IsNotNull 等价于 SQL 中的 " is not null ",比如 findByUsernameIsNotNull(); NotNull 与 IsNotNull 等价; Like 等价于 SQL 中的 " like ",比如 findByUsernameLike(String username); NotLike 等价于 SQL 中的 " not like ",比如 findByUsernameNotLike(String username); StartingWith 参数从头开始匹配当前字段的数据,比如 findByFirstnameStartingWith(String firstName); EndingWith 参数从尾部开始匹配当前字段的数据,比如 findByFirstnameEndingWith(String firstName); OrderBy 等价于 SQL 中的 "order by",比如 findByUsernameOrderBySalaryAsc(String username); Not 等价于 SQL 中的 " != ",比如 findByUsernameNot(String username); In 等价于 SQL 中的 " in ",比如 findByUsernameIn(Collection<String> userList) ,方法的参数可以是 Collection 类型,也可以是数组或者不定长参数; NotIn 等价于 SQL 中的 " not in ",比如 findByUsernameNotIn(Collection<String> userList) ,方法的参数可以是 Collection 类型,也可以是数组或者不定长参数; False 匹配当前字段为 false,比如 findByActiveFalse(boolean active); True 匹配当前字段为 true,比如 findByActiveTrue(boolean active); Is,Equals 匹配参数与当前字段是否相等或者相同,比如 findByFirstnameIs(String firstName);
说在最后:
细心地人肯定会发现我放在repository包下的接口都继承了父接口repository<T, ID>,但其实这并没有完全发挥出Spring Data JPA的功能。
如果我们进入接口repository接口中我们会发现这个接口还有很多其他的子接口,比如CrudRepository,PagingAndSortingRepository,JpaRepository等接口天生就自带了一些特殊的方法,比如简单的CRUD的方法封装,比如分页的方法封装等等等,包括使用@Query注解进行手写JP QL甚至手写SQL语句,这些内容我们将放到后面呈现。