Spring Date JPA
1.Spring Date JPA是什么?
Spring Data是一个用于简化数据库访问,并支持云服务的开源框架。其主要目标是使得对数据的访问变得方便快捷,并支持map-reduce框架和云计算数据服务。
2.Spring Date JPA 开发步聚:
2.1.声明持久层的接口,该接口继承 Repository。Repository 是一个标记型接口,它不包含任何方法,当然如果有需要,Spring Data 也提供了若干 Repository 子接口,其中定义了一些常用的增删改查,以及分页相关的方法。比如:CrudRepository、PagingAndSortingRepository、JpaRepository、JpaSpecificationExecutor、Specification
2.2.在接口中声明需要的业务方法。Spring Data 将根据给定的策略(具体策略稍后讲解)来为其解析生成实现代码。
2.3.在 Spring 配置文件中增加一行声明,让 Spring 为声明的接口创建代理对象。配置了 <jpa:repositories> 后,Spring 初始化容器时将会扫描 base-package 指定的包目录及其子目录,为继承 Repository 或其子接口的接口创建代理对象,并将代理对象注册为 Spring Bean,业务层便可以通过 Spring 自动封装的特性来直接使用该对象。可以在 <jpa:repository> 内部使用 <context:include-filter>、<context:exclude-filter> 来过滤掉一些不希望被扫描到的接口。
3.Repository接口的详解以及子类:
3.1.Repository:顶层接口,空接口。目的是为了统一所有Repository的类型,且能让组件扫描的时候自动识别;
3.2.CrudRepository :是Repository的子接口,提供CRUD的功能;它会自动为域对象创建增删改查方法,供业务层直接使用。开发者只是多写了 "Crud" 四个字母。但是它可能暴露了你不希望暴露给业务层的方法;
3.3.PagingAndSortingRepository:是CrudRepository的子接口,添加分页和排序的功能。但是灵活性不高,开发者可以在继承 Repository 或 CrudRepository 的基础上,在自己声明的方法参数列表最后增加一个 Pageable 或 Sort 类型的参数,用于指定分页或排序信息即可,这比直接使用 PagingAndSortingRepository 提供了更大的灵活性;
3.4.JpaRepository:是PagingAndSortingRepository的子接口,它在父接口的基础上,提供了其他一些方法,比如flush(),saveAndFlush(),deleteInBatch() 等;
3.5.JpaSpecificationExecutor:用来做负责查询的接口;
3.6.Specification:是Spring Data JPA提供的一个查询规范,要做复杂的查询,只需围绕这个规范来设置查询条件即可。
4.简单的JPA实现
4.1.Bean/model类
package com.usc.lilin.model; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.Table; //注解方式声明为实体 @Entity //指定相对应的表的名字 @Table(name = "user") public class User { //指明属性为ID @Id //自增属性 @GeneratedValue private Integer id; private String name; private String address; private String phone; //getXx/setXx方法省去 }
4.2.服务层接口:
package com.usc.lilin.service; import java.util.List; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import com.usc.lilin.model.User; public interface UserService { /** * 添加用户信息 * * @param user * 用户 */ public void addUser(User user); /** * 通过Id获取User对象 * * @param user * 封装了ID数据的对象 * @return 返回数据库的实体User */ public User getUserById(User user) throws Exception; /** * 获取数据库中全部的User实体对象 * * @return 封装了User的队列 */ public List<User> getUsers(); /** * 修改用户的信息 * * @param user * 封装了需要修改数据的User对此昂 * @return 返回修改获得User实体对象 */ public User updateUser(User user) throws Exception; /** * 删除对象 * * @param user * 封装了数据的对象 * @return 返回删除的对象 */ public User deleteUser(User user); /** * 不分页查询 * * @param phone * 电话号码 * @param address * 地址 * @return 返回数据队列 */ public List<User> findByPhoneNoPage(String phone, String address); public List<User> fineUsers(); /** * 分页查询 * * @param phone * 电话号码 * @param address * 地址 * @param pageable * 分页 * @return 结果集 */ public Page<User> findUserByPage(String phone, String address, Pageable pageable); }
4.3.服务层接口实现:
package com.usc.lilin.service; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; import org.springframework.data.domain.Sort.Direction; import org.springframework.stereotype.Service; import com.usc.lilin.model.User; import com.usc.lilin.respository.UserRepository; /** * 服务层实现类 * * @author lilin * @time 2016年6月3日 上午1:38:33 * @email [email protected] * @blog http://gaosililin.iteye.com * @school USC * @team Geowind */ //注解方式 注明服务类 @Service("userService") public class UserServiceImpl implements UserService { //注解方式实现加载 @Autowired private UserRepository userRepository; @Override public void addUser(User user) { userRepository.saveAndFlush(user); } @Override public User getUserById(User user) throws Exception { if (user != null && user.getId() != null) { User getUser = userRepository.findOne(user.getId()); return getUser; } else { throw new Exception("没有该Id的对象数据!"); } } @Override public List<User> getUsers() { List<User> users = userRepository.findAll(); return users; } @Override public User updateUser(User user) throws Exception { if (user != null && user.getId() != null) { User getUser = userRepository.findOne(user.getId()); if (user.getAddress() != null) { getUser.setAddress(user.getAddress()); } if (user.getName() != null) { getUser.setName(user.getName()); } if (user.getPhone() != null) { getUser.setPhone(user.getPhone()); } return getUser; } else { throw new Exception("没有该Id的对象数据!"); } } @Override public User deleteUser(User user) { userRepository.delete(user.getId()); return user; } public UserRepository getUserRepository() { return userRepository; } public void setUserRepository(UserRepository userRepository) { this.userRepository = userRepository; } }
4.4.持久层接口:
package com.usc.lilin.respository; import java.util.List; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; import org.springframework.data.jpa.repository.JpaRepository; import com.usc.lilin.model.User; public interface UserRepository extends JpaRepository<User, Integer> { }
4.5.Spring 的配置文件
4.5.1.定义服务层代码存放的包扫描路径 。即服务层的包路径全名
4.5.2.定义实体的工厂bean
4.5.3.定义事务管理器
4.5.4.定义repository接口的存放目录/定义接口实现的后缀,通常用/定义实体工厂的引 用 /定义事务管理器的引用
4.5.5.声明采用注解的方式申明事务
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jpa="http://www.springframework.org/schema/data/jpa" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.2.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd" default-lazy-init="true"> <!--第一步 --> <!--定义服务层代码存放的包扫描路径 。即服务层的包路径全名 --> <context:component-scan base-package="com.usc.lilin.service"></context:component-scan> <!--第二步 --> <!--定义实体的工厂bean --> <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <!-- hibernate的配置文件路径 --> <property name="persistenceXmlLocation" value="classpath:persistence.xml"></property> <property name="persistenceUnitName" value="userPU"></property> </bean> <!--第三步 --> <!--定义事务管理器 --> <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> <property name="entityManagerFactory" ref="entityManagerFactory" /> </bean> <!--第四步 --> <!--定义repository接口的存放目录 --> <!--定义接口实现的后缀,通常用Impl --> <!--定义实体工厂的引用 --> <!--定义事务管理器的引用 --> <jpa:repositories base-package="com.usc.lilin.respository" repository-impl-postfix="Impl" entity-manager-factory-ref="entityManagerFactory" transaction-manager-ref="transactionManager"></jpa:repositories> <!--第五步 --> <!--声明采用注解的方式申明事务 --> <tx:annotation-driven transaction-manager="transactionManager" /> </beans>
5.通过解析方法名创建查询
在查询时,通常需要同时根据多个属性进行查询,且查询的条件也格式各样(大于某个值、在某个范围等等),Spring Data JPA 为此提供了一些表达条件查询的关键字,大致如下:
And --- 等价于 SQL 中的 and 关键字,比如 findByUsernameAndPassword(String user, Striang pwd); Or --- 等价于 SQL 中的 or 关键字,比如 findByUsernameOrAddress(String user, String addr); 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 user); NotLike --- 等价于 SQL 中的 "not like",比如 findByUsernameNotLike(String user); OrderBy --- 等价于 SQL 中的 "order by",比如 findByUsernameOrderBySalaryAsc(String user); Not --- 等价于 SQL 中的 "! =",比如 findByUsernameNot(String user); In --- 等价于 SQL 中的 "in",比如 findByUsernameIn(Collection<String> userList) ,方法的参数可以是 Collection 类型,也可以是数组或者不定长参数; NotIn --- 等价于 SQL 中的 "not in",比如 findByUsernameNotIn(Collection<String> userList) ,方法的参数可以是 Collection 类型,也可以是数组或者不定长参数;
例子:
package com.usc.lilin.respository; import java.util.List; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; import org.springframework.data.jpa.repository.JpaRepository; import com.usc.lilin.model.User; public interface UserRepository extends JpaRepository<User, Integer> { // select * from user where phone like '136%' and address like '%·%' order by phone desc limit 0,2 List<User> findTop2ByPhoneStartingWithAndAddressContainingOrderByPhoneDesc(String phone, String address); // select * from user where phone like '136%' and address like '%·%' order by phone desc limit 0,2 //Sort 排序 List<User> findTop2ByPhoneStartingWithAndAddressContaining(String phone, String address, Sort sort); //select * from user List<User> findBy(); // select * from user where phone like '136%' and address like '%·%' limit begin pageSize; Page<User> findByPhoneStartingWithAndAddressContaining(String phone, String address, Pageable pageable); }
比较好的资料:Spring Data JPA 开发指南