首先了解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 Data JPA 是 Spring 基于 ORM 框架、JPA 规范的基础上封装的一套JPA应用框架,可使开发者用极简的代码即可实现对数据的访问和操作。它提供了包括增删改查等在内的常用功能,且易于扩展!学习并使用 Spring Data JPA 可以极大提高开发效率!
spring data jpa让我们解脱了DAO层的操作,基本上所有CRUD都可以依赖于它来实现
了解了JPA以及Spring data JPA相关的依赖,详见pom文件如下
<!-- Spring-data-jpa依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- Mysql支持 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
yml属性配置文件需要配置数据库的链接属性,我采用的是mysql数据库
server:
port: 8080
spring:
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql:///库名?useUnicode=true&characterEncoding=utf-8
username: root
password: root
jpa:
hibernate:
ddl-auto: update
show-sql: true
其实这个hibernate.hbm2ddl.auto参数的作用主要用于:自动创建|更新|验证数据库表结构。如果不是此方面的需求建议set value="none"。
create:
每次加载hibernate时都会删除上一次的生成的表,然后根据你的model类再重新来生成新表,哪怕两次没有任何改变也要这样执行,这就是导致数据库表数据丢失的一个重要原因。
create-drop :
每次加载hibernate时根据model类生成表,但是sessionFactory一关闭,表就自动删除。
update:
最常用的属性,第一次加载hibernate时根据model类会自动建立起表的结构(前提是先建立好数据库),以后加载hibernate时根据 model类自动更新表结构,即使表结构改变了但表中的行仍然存在不会删除以前的行。要注意的是当部署到服务器后,表结构是不会被马上建立起来的,是要等 应用第一次运行起来后才会。
validate :
每次加载hibernate时,验证创建数据库表结构,只会和数据库中的表进行比较,不会创建新表,但是会插入新值。
创建一个简单的entity,代码如下,值得注意的地方是这里必须要有一个无参构造方法,否则JPA启动会报错
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import java.io.Serializable;
@Entity
public class User{
@Id
@Column(name="id",nullable = false)
@GeneratedValue
private Integer id;
@Column
private String username;
@Column
private String name;
@Column
private String password;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public User(String username,String name,String password){
super();
this.username=username;
this.name=name;
this.password=password;
}
//必须有一个无参构造方法,否则会报错
public User(){
}
@Override
public String toString() {
return getId()+","+getUsername()+","+getName();
}
}
创建简单的查询
创建一个自己的Repository,官网上介绍的是其需要集成Repository或者CurdRepository,而此处采用的是继承JpaRepository
import org.springframework.data.jpa.repository.JpaRepository;
public interface UserRepository extends JpaRepository<User, Long> {
}
使用默认方法
@Autowired
private UserRepository userRepository;
@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);
// ...
}
简单的自定义查询
所谓简单的自定义查询就是根据方法名自动生成SQL,当然方法名是有命令规则的,主要语法是findXXBy,readAXXBy,queryXXBy,countXXBy, getXXBy后面跟属性名称,以及可以使用一些And、Or等关键字,还可以加上OrderBy进行排序,详见如下表格:
关键字 | 方法命名 | sql where字句 |
And | findByNameAndPwd | where name= ? and pwd =? |
Or | findByNameOrSex | where name= ? or sex=? |
Is,Equals | findById,findByIdEquals | where id= ? |
Between | findByIdBetween | where id between ? and ? |
LessThan | findByIdLessThan | where id < ? |
LessThanEqual | findByIdLessThanEquals | where id <= ? |
GreaterThan | findByIdGreaterThan | where id > ? |
GreaterThanEqual | findByIdGreaterThanEquals | where id > = ? |
After | findByIdAfter | where id > ? |
Before | findByIdBefore | where id < ? |
IsNull | findByNameIsNull | where name is null |
isNotNull,NotNull | findByNameNotNull | where name is not null |
Like | findByNameLike | where name like ? |
NotLike | findByNameNotLike | where name not like ? |
StartingWith | findByNameStartingWith | where name like '?%' |
EndingWith | findByNameEndingWith | where name like '%?' |
Containing | findByNameContaining | where name like '%?%' |
OrderBy | findByIdOrderByXDesc | where id=? order by x desc |
Not | findByNameNot | where name <> ? |
In | findByIdIn(Collection<?> c) | where id in (?) |
NotIn | findByIdNotIn(Collection<?> c) | where id not in (?) |
True | findByAaaTue | where aaa = true |
False | findByAaaFalse | where aaa = false |
IgnoreCase | findByNameIgnoreCase | where UPPER(name)=UPPER(?) |
使用情况的代码如下:
import com.zxl.examples.entity.User;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import java.util.List;
/**
* Created by Administrator on 2017/7/21.
*/
public interface UserRepository extends JpaRepository {
//方法名要规则,sql会根据方法名自动生成sql进行操作
public List findByUsername(String username);
List findByNameAndPassword(String name,String password);
List findByNameOrPassword(String name,String password);
List findByPasswordLessThan(String password);
List findByNameAndPasswordLessThan(String name,String password);
List findByIdLessThanAndPasswordLessThan(Integer id,String password);
List findByIdLessThanAndPasswordLessThanEqual(Integer id,String password);
List findByIdLessThanEqual(Integer id);
List findByPasswordBetween(String password1,String password2);
List findByUsernameIn(List usernames);
List findByNameLike(String name);
List findByNameContaining(String name);
}
2. 带有分页的自定义查询
在实际的开发中是免不了遇到有分页的情况的,而Spring data jpa已经帮我们实现了分页的功能,我们只需要在方法中传入Pageable参数即可,如要实现自定排序在方法中还可传入Sort参数,具体使用情况见如下代码,UserRepository类中的代码如下:
import com.zxl.examples.entity.User;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import java.util.List;
/**
* Created by Administrator on 2017/7/21.
*/
public interface UserRepository extends JpaRepository {
//方法名要规则,sql会根据方法名自动生成sql进行操作
public Slice findByNameOrderByIdDesc(String name, Pageable pageable);
public Page findByNameOrderByPasswordAscIdDesc(String name, Pageable pageable);
List findByNameOrderByIdDesc(String name,Sort sort);
List findByNameOrPassword(String name,String password, 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);
}
3自定义sql查询
其实Spring data 觉大部分的SQL都可以根据方法名定义的方式来实现,但是由于某些原因我们想使用自定义的SQL来查询,spring data也是完美支持的;在SQL的
查询方法上面使用@Query注解,如涉及到删除和修改在需要加上@Modifying.也可以根据需要添加 @Transactional 对事物的支持,查询超时的设置等
代码详见如下:
import com.zxl.examples.entity.User;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import java.util.List;
/**
* Created by Administrator on 2017/7/21.
*/
public interface UserRepository extends JpaRepository {
//SpEL (Spring Expression Language)
@Query("select u from User u where u.username = :#{#user.username}")
List findByUsername(@Param("user") User user);
@Query("select u from User u where u.username = :username")
List findByUsername2(@Param("username") String username);
@Query("select u from User u where u.username=?2 AND u.id=?1")
List findByIdAndUsername(Integer id,String username);
@Query("select u from User u")
List findAll2(Pageable pageable);
@Query(value="select * from user limit 0,6",nativeQuery = true)//使用原生的sql,此处连的是mysql
List findAll3();
}
多表查询
多表查询在spring data jpa中有两种实现方式,第一种是利用hibernate的级联查询来实现,第二种是创建一个结果集的接口来接收连表查询后的结果,这里主要第二种方式。
首先需要定义一个结果集的接口类。
public interface HotelSummary {
City getCity();
String getName();
Double getAverageRating();
default Integer getAverageRatingRounded() {
return getAverageRating() == null ? null : (int) Math.round(getAverageRating());
}
}
查询的方法返回类型设置为新创建的接口
@Query("select h.city as city, h.name as name, avg(r.rating) as averageRating "
- "from Hotel h left outer join h.reviews r where h.city = ?1 group by h")
Page<HotelSummary> findByCity(City city, Pageable pageable);
@Query("select h.name as name, avg(r.rating) as averageRating "
- "from Hotel h left outer join h.reviews r group by h")
Page<HotelSummary> findByCity(Pageable pageable);
使用
Page<HotelSummary> hotels = this.hotelRepository.findByCity(new PageRequest(0, 10, Direction.ASC, "name"));
for(HotelSummary summay:hotels){
System.out.println("Name" +summay.getName());
}
在运行中Spring会给接口(HotelSummary)自动生产一个代理类来接收返回的结果,代码汇总使用
getXX
的形式来获取