一、spring-data-jpa
1.jpa
JPA(Java Persistence API)是Sun官方提出的Java持久化规范。它为Java开发人员提供了一种对象/关联映射工具来管理Java应用中的关系数据。他的出现主要是为了简化现有的持久化开发工作和整合ORM技术,结束现在Hibernate,TopLink,JDO等ORM框架各自为营的局面。JPA是在充分吸收了现有Hibernate,TopLink,JDO等ORM框架的基础上发展而来的,具有易于使用,伸缩性强等优点。
注意:JPA是一套规范,不是一套产品,那么像Hibernate,TopLink,JDO他们是一套产品,如果说这些产品实现了这个JPA规范,那么我们就可以叫他们为JPA的实现产品。
2.spring-data-jpa
Spring Data JPA 是 Spring 基于 ORM 框架、JPA 规范的基础上封装的一套JPA应用框架,可使开发者用极简的代码即可实现对数据的访问和操作。它提供了包括增删改查等在内的常用功能,且易于扩展!学习并使用 Spring Data JPA 可以极大提高开发效率!
注意:spring data jpa让我们解脱了DAO层的操作,基本上所有CRUD都可以依赖于它来实现
3.基本查询
基本查询也分为两种,一种是spring data默认已经实现,一种是根据查询的方法来自动解析成SQL。
3.1默认基本查询(预先生成方法)
spring data jpa 默认预先生成了一些基本的CURD的方法,如增、删、改等方法。
其操作步骤:
1).继承JpaRepository(即相当于开发Dao接口)
public interface UserRepository extends JpaRepository<User, Long> {
}
2).使用默认方法(即相当于service层调用dao的方法)
@Test
public void testBaseQuery() throws Exception {
User user=new User();
userRepository.findAll();
userRepository.findOne(1l);
userRepository.save(user);
userRepository.delete(user);
userRepository.count();
userRepository.exists(1l);
// ...
}
3.2自定义基础查询
自定义的简单查询就是根据方法名来自动生成SQL,主要的语法是findXXBy
,readAXXBy
,queryXXBy
,countXXBy
, getXXBy
后面跟属性名称:
User findByUserName(String userName);
也使用一些加一些关键字And
、 Or
User findByUserNameOrEmail(String username, String email);
具体的关键字,使用方法和生产成SQL如下表所示
Keyword | Sample | JPQL snippet |
---|---|---|
And | findByLastnameAndFirstname | … where x.lastname = ?1 and x.firstname = ?2 |
Or | findByLastnameOrFirstname | … where x.lastname = ?1 or x.firstname = ?2 |
Is,Equals | findByFirstnameIs,findByFirstnameEquals | … where x.firstname = ?1 |
Between | findByStartDateBetween | … where x.startDate between ?1 and ?2 |
LessThan | findByAgeLessThan | … where x.age < ?1 |
LessThanEqual | findByAgeLessThanEqual | … where x.age ⇐ ?1 |
GreaterThan | findByAgeGreaterThan | … where x.age > ?1 |
GreaterThanEqual | findByAgeGreaterThanEqual | … where x.age >= ?1 |
After | findByStartDateAfter | … where x.startDate > ?1 |
Before | findByStartDateBefore | … where x.startDate < ?1 |
IsNull | findByAgeIsNull | … where x.age is null |
IsNotNull,NotNull | findByAge(Is)NotNull | … where x.age not null |
Like | findByFirstnameLike | … where x.firstname like ?1 |
NotLike | findByFirstnameNotLike | … where x.firstname not like ?1 |
StartingWith | findByFirstnameStartingWith | … where x.firstname like ?1 (parameter bound with appended %) |
EndingWith | findByFirstnameEndingWith | … where x.firstname like ?1 (parameter bound with prepended %) |
Containing | findByFirstnameContaining | … where x.firstname like ?1 (parameter bound wrapped in %) |
OrderBy | findByAgeOrderByLastnameDesc | … where x.age = ?1 order by x.lastname desc |
Not | findByLastnameNot | … where x.lastname <> ?1 |
In | findByAgeIn(Collection ages) | … where x.age in ?1 |
NotIn | findByAgeNotIn(Collection age) | … where x.age not in ?1 |
TRUE | findByActiveTrue() | … where x.active = true |
FALSE | findByActiveFalse() | … where x.active = false |
IgnoreCase | findByFirstnameIgnoreCase | … where UPPER(x.firstame) = UPPER(?1) |
4.复杂查询
在实际的开发中我们需要用到分页、删选、连表等查询的时候就需要特殊的方法或者自定义SQL
4.1分页查询
spring data jpa已经帮我们实现了分页的功能,在查询的方法中,需要传入参数Pageable
,当查询中有多个参数的时候Pageable
建议做为最后一个参数传入
Page<User> findALL(Pageable pageable);
Page<User> findByUserName(String userName,Pageable pageable);
Pageable
是spring封装的分页实现类,使用的时候需要传入页数、每页条数和排序规则
@Test
public void testPageQuery() throws Exception {
int page=1,size=10;
Sort sort = new Sort(Direction.DESC, "id");
Pageable pageable = new PageRequest(page, size, sort);
userRepository.findALL(pageable);
userRepository.findByUserName("testName", pageable);
}
限制查询:有时候我们只需要查询前N个元素,或者支取第一个实体
User findFirstByOrderByLastnameAsc();
User findTopByOrderByAgeDesc();
Page<User> queryFirst10ByLastname(String lastname, Pageable pageable);
List<User> findFirst10ByLastname(String lastname, Sort sort);
List<User> findTop10ByLastname(String lastname, Pageable pageable);
4.2自定义SQL查询
其实Spring data 觉大部分的SQL都可以根据方法名定义的方式来实现,但是由于某些原因我们想使用自定义的SQL来查询,spring data也是完美支持的;在SQL的查询方法上面使用@Query
注解,如涉及到删除和修改在需要加上@Modifying
.也可以根据需要添加 @Transactional
对事物的支持,查询超时的设置等
@Modifying
@Query("update User u set u.userName = ?1 where u.id = ?2")
int modifyByIdAndUserId(String userName, Long id);
@Transactional
@Modifying
@Query("delete from User where id = ?1")
void deleteByUserId(Long id);
@Transactional(timeout = 10)
@Query("select u from User u where u.emailAddress = ?1")
User findByEmailAddress(String emailAddress);
4.3多表查询
多表查询在spring data jpa中有两种实现方式,第一种是利用hibernate的级联查询来实现,第二种是创建一个结果集的接口来接收连表查询后的结果。
具体此处省略,见http://www.ityouknow.com/springboot/2016/08/20/spring-boo-jpa.html
二、springboot集成spring-data-jpa
1.集成项目结构
2.添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
需要注意的是,spring-data-jpa是在hibernate的基础上封装的,导入该依赖,也引入了hibernate的jar。
此处说明一下spring-data-jpa和hibernate的关系:
- ①JPA首先得介绍一下,他只是一套规范和标准,也就是一堆堆的接口,并未实现;
- ②hibernate是对JPA的一种实现,就是你具体执行持久化操作调用的方法内具体干了什么,都是Hibernate实现的;
- ③spring-data-jpa则是对hibernate实行了再封装,大大的简化了原本DAO层的实现,也就是现在的repository层。因为本章就是用的spring-data-jpa。
- ④spring spring-boot官方对hibernate是一直都有支持的,而对mybatis则没有,但并不代表它不能与mybatis集成。
3.在application.properties中添加配置
##配置数据源
spring.datasource.url=jdbc:mysql://localhost:3306/db_shiro02?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8
spring.datasource.username = root
spring.datasource.password = 123456
spring.datasource.driver-class-name = com.mysql.cj.jdbc.Driver
##可不添加
spring.jpa.properties.hibernate.hbm2ddl.auto=update
spring.jpa.show-sql= true
说明:spring.jpa.properties.hibernate.hbm2ddl.auto
是hibernate的配置属性,其主要作用是:自动创建、更新、验证数据库表结构。
4.代码
实体类
@Entity
@Table(name="sys_user")
public class JpaUser {
@Id
@GeneratedValue
private String id;
private String usercode;
private String username;
private String password;
private String salt;
private String locked;
//省略get、set方法和toString方法
}
controller类
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
private Logger logger = LoggerFactory.getLogger(this.getClass());
@RequestMapping("/jpalist")
public String jpalist(){
logger.info("-------------list start-------------");
List<JpaUser> list = userService.getAllUsers2();
logger.info("-------------list end-------------");
return list.toString();
}
}
service层(接口省略,实现类如下)
@Service("userService")
public class UserServiceImpl implements UserService{
@Autowired
private UserRepository userRepository;
private Logger logger = LoggerFactory.getLogger(this.getClass());
@Override
public List<JpaUser> getAllUsers2(){
logger.info("-------------jpa UserServiceImpl getAllUsers2 start-------------");
List<JpaUser> list = userRepository.findAll();
logger.info("-------------jpa UserServiceImpl getAllUsers2 start-------------");
return list;
}
}
repository(即dao接口)
public interface UserRepository extends JpaRepository<JpaUser, String> {
}