spring mvc 的jpa JpaRepository數據層 訪問方式匯總
spring mvc 的jpa JpaRepository數據層 訪問方式匯總
博客分類:- spring
- jpa
本文轉載至:http://perfy315.iteye.com/blog/1460226
AppleFramework在數據訪問控制層采用了Spring Data作為這一層的解決方案,下面就對Spring Data相關知識作一個較為詳細的描述。
1.Spring Data所解決的問題
Spring Data :提供了一整套數據訪問層(DAO)的解決方案,致力於減少數據訪問層(DAO)的開發量。它使用一個叫作Repository的接口類為基礎,它被定義為訪問底層數據模型的超級接口。而對於某種具體的數據訪問操作,則在其子接口中定義。
public interface Repository<T, ID extends Serializable> {
}
所有繼承這個接口的interface都被spring所管理,此接口作為標識接口,功能就是用來控制domain模型的。
Spring Data可以讓我們只定義接口,只要遵循spring data的規範,就無需寫實現類。
2.什麽是Repository?
2.1 Repository(資源庫):通過用來訪問領域對象的一個類似集合的接口,在領域與數據映射層之間進行協調。這個叫法就類似於我們通常所說的DAO,在這裏,我們就按照這一習慣把數據訪問層叫Repository
Spring Data給我們提供幾個Repository,基礎的Repository提供了最基本的數據訪問功能,其幾個子接口則擴展了一些功能。它們的繼承關系如下:
Repository: 僅僅是一個標識,表明任何繼承它的均為倉庫接口類,方便Spring自動掃描識別
CrudRepository: 繼承Repository,實現了一組CRUD相關的方法
PagingAndSortingRepository: 繼承CrudRepository,實現了一組分頁排序相關的方法
JpaRepository: 繼承PagingAndSortingRepository,實現一組JPA規範相關的方法
JpaSpecificationExecutor: 比較特殊,不屬於Repository體系,實現一組JPA Criteria查詢相關的方法
我們自己定義的XxxxRepository需要繼承JpaRepository,這樣我們的XxxxRepository接口就具備了通用的數據訪問控制層的能力。
2.2 JpaRepository 所提供的基本功能
2.2.1 CrudRepository<T, ID extends Serializable>:
這個接口提供了最基本的對實體類的添刪改查操作
T save(T entity);//保存單個實體
Iterable<T> save(Iterable<? extends T> entities);//保存集合
T findOne(ID id);//根據id查找實體
boolean exists(ID id);//根據id判斷實體是否存在
Iterable<T> findAll();//查詢所有實體,不用或慎用!
long count();//查詢實體數量
void delete(ID id);//根據Id刪除實體
void delete(T entity);//刪除一個實體
void delete(Iterable<? extends T> entities);//刪除一個實體的集合
void deleteAll();//刪除所有實體,不用或慎用!
2.2.2 PagingAndSortingRepository<T, ID extends Serializable>
這個接口提供了分頁與排序功能
Iterable<T> findAll(Sort sort);//排序
Page<T> findAll(Pageable pageable);//分頁查詢(含排序功能)
2.2.3 JpaRepository<T, ID extends Serializable>
這個接口提供了JPA的相關功能
List<T> findAll();//查找所有實體
List<T> findAll(Sort sort);//排序 查找所有實體
List<T> save(Iterable<? extends T> entities);//保存集合
void flush();//執行緩存與數據庫同步
T saveAndFlush(T entity);//強制執行持久化
void deleteInBatch(Iterable<T> entities);//刪除一個實體集合
3.Spring data 查詢
3.1 簡單條件查詢:查詢某一個實體類或者集合
按照Spring data 定義的規則,查詢方法以find|read|get開頭
涉及條件查詢時,條件的屬性用條件關鍵字連接,要註意的是:條件屬性以首字母大寫其余字母小寫為規定。
例如:定義一個Entity實體類
class User{
private String firstname;
private String lastname;
}
使用And條件連接時,應這樣寫:
findByLastnameAndFirstname(String lastname,String firstname);
條件的屬性名稱與個數要與參數的位置與個數一一對應
3.2 使用JPA NamedQueries (標準規範實現)
這種查詢是標準的JPA規範所定義的,直接聲明在Entity實體類上,調用時采用在接口中定義與命名查詢對應的method,由Spring Data根據方法名自動完成命名查詢的尋找。
(1)在Entity實體類上使用@NamedQuery註解直接聲明命名查詢。
@Entity
@NamedQuery(name = "User.findByEmailAddress",
query = "select u from User u where u.emailAddress = ?1")
public class User {
}
註:定義多個時使用下面的註解
@NamedQueries(value = {
@NamedQuery(name = User.QUERY_FIND_BY_LOGIN,
query = "select u from User u where u." + User.PROP_LOGIN
+ " = :username"),
@NamedQuery(name = "getUsernamePasswordToken",
query = "select new com.aceona.weibo.vo.TokenBO(u.username,u.password) from User u where u." + User.PROP_LOGIN
+ " = :username")})
(2)在interface中定義與(1)對應的方法
public interface UserRepository extends JpaRepository<User, Long> {
List<User> findByLastname(String lastname);
User findByEmailAddress(String emailAddress);
}
3.3 使用@Query自定義查詢(Spring Data提供的)
這種查詢可以聲明在Repository方法中,擺脫像命名查詢那樣的約束,將查詢直接在相應的接口方法中聲明,結構更為清晰,這是Spring data的特有實現。
例如:
public interface UserRepository extends JpaRepository<User, Long> {
@Query("select u from User u where u.emailAddress = ?1")
User findByEmailAddress(String emailAddress);
}
3.4 @Query與 @Modifying 執行更新操作
這兩個annotation一起聲明,可定義個性化更新操作,例如只涉及某些字段更新時最為常用,示例如下:
@Modifying
@Query("update User u set u.firstname = ?1 where u.lastname = ?2")
int setFixedFirstnameFor(String firstname, String lastname);
3.5 索引參數與命名參數
(1)索引參數如下所示,索引值從1開始,查詢中 ”?X” 個數需要與方法定義的參數個數相一致,並且順序也要一致
@Modifying
@Query("update User u set u.firstname = ?1 where u.lastname = ?2")
int setFixedFirstnameFor(String firstname, String lastname);
(2)命名參數(推薦使用這種方式)
可以定義好參數名,賦值時采用@Param("參數名"),而不用管順序。如下所示:
public interface UserRepository extends JpaRepository<User, Long> {
@Query("select u from User u where u.firstname = :firstname or u.lastname = :lastname")
User findByLastnameOrFirstname(@Param("lastname") String lastname,
@Param("firstname") String firstname);
}
4. Transactionality(事務)
4.1 操作單個對象的事務
Spring Data提供了默認的事務處理方式,即所有的查詢均聲明為只讀事務,對於持久化,更新與刪除對象聲明為有事務。
參見org.springframework.data.jpa.repository.support.SimpleJpaRepository<T, ID>
@org.springframework.stereotype.Repository
@Transactional(readOnly = true)
public class SimpleJpaRepository<T, ID extends Serializable> implements JpaRepository<T, ID>,
JpaSpecificationExecutor<T> {
……
@Transactional
public void delete(ID id) {
delete(findOne(id));
}
……
}
對於自定義的方法,如需改變spring data提供的事務默認方式,可以在方法上註解@Transactional聲明
4.2 涉及多個Repository的事務處理
進行多個Repository操作時,也應該使它們在同一個事務中處理,按照分層架構的思想,這部分屬於業務邏輯層,因此,需要在Service層實現對多個Repository的調用,並在相應的方法上聲明事務。
例如:
@Service(“userManagement”)
class UserManagementImpl implements UserManagement {
private final UserRepository userRepository;
private final RoleRepository roleRepository;
@Autowired
public UserManagementImpl(UserRepository userRepository,
RoleRepository roleRepository) {
this.userRepository = userRepository;
this.roleRepository = roleRepository;
}
@Transactional
public void addRoleToAllUsers(String roleName) {
Role role = roleRepository.findByName(roleName);
for (User user : userRepository.readAll()) {
user.addRole(role);
userRepository.save(user);
}
}
5.關於DAO層的規範
5.1對於不需要寫實現類的情況:定義XxxxRepository 接口並繼承JpaRepository接口,如果Spring data所提供的默認接口方法不夠用,可以使用@Query在其中定義個性化的接口方法。
5.2對於需要寫實現類的情況:定義XxxxDao 接口並繼承com.aceona.appleframework.persistent.data.GenericDao
書寫XxxxDaoImpl實現類並繼承com.aceona.appleframework.persistent.data.GenericJpaDao,同時實現XxxxDao接口中的方法
在Service層調用XxxxRepository接口與XxxxDao接口完成相應的業務邏輯
關於配置:
spring.xml
Java代碼- <?xml version="1.0" encoding="UTF-8"?>
- <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-1.3.xsd"
- default-lazy-init="true">
- <description>Spring公共配置</description>
- <context:component-scan base-package="com.scu.book.shop">
- <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller" />
- <context:exclude-filter type="annotation" expression="org.springframework.web.bind.annotation.ControllerAdvice" />
- </context:component-scan>
- <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
- <property name="dataSource" ref="dataSource" />
- <property name="jpaVendorAdapter" ref="hibernateJpaVendorAdapter" />
- <property name="packagesToScan" value="com.scu.book.shop" />
- <property name="jpaProperties">
- <props>
- <prop key="hibernate.dialect">${hibernate.dialect}</prop>
- <prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
- <prop key="hibernate.format_sql">${hibernate.format_sql}</prop>
- <prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop>
- <prop key="hibernate.ejb.naming_strategy">org.hibernate.cfg.ImprovedNamingStrategy</prop>
- </props>
- </property>
- </bean>
- <bean id="hibernateJpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
- <jpa:repositories base-package="com.scu.book.shop" transaction-manager-ref="transactionManager" entity-manager-factory-ref="entityManagerFactory" />
- <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
- <property name="entityManagerFactory" ref="entityManagerFactory" />
- </bean>
- <tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true" />
- <!--
- <bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean" />
- -->
- <context:property-placeholder ignore-unresolvable="true"
- location="classpath*:/property/jdbc.properties,
- classpath*:/property/hibernate.properties,
- classpath*:/property/image.properties" />
- <bean id="dataSource" class="org.apache.tomcat.jdbc.pool.DataSource"
- destroy-method="close">
- <property name="driverClassName" value="${jdbc.driver}" />
- <property name="url" value="${jdbc.url}" />
- <property name="username" value="${jdbc.username}" />
- <property name="password" value="${jdbc.password}" />
- <property name="maxActive" value="${jdbc.pool.maxActive}" />
- <property name="maxIdle" value="${jdbc.pool.maxIdle}" />
- <property name="testWhileIdle" value="true" />
- <property name="testOnBorrow" value="true" />
- <property name="testOnReturn" value="false" />
- <property name="validationQuery" value="select 1" />
- <property name="removeAbandoned" value="true" />
- <property name="timeBetweenEvictionRunsMillis" value="900000" />
- <property name="minEvictableIdleTimeMillis" value="1800000" />
- </bean>
- </beans>
web.xml:
Java代碼- <?xml version="1.0" encoding="UTF-8"?>
- <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
- http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
- <display-name>book shop</display-name>
- <listener>
- <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
- </listener>
- <context-param>
- <param-name>contextConfigLocation</param-name>
- <param-value>classpath:spring/*.xml</param-value>
- </context-param>
- <filter>
- <filter-name>encodingFilter</filter-name>
- <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
- <init-param>
- <param-name>encoding</param-name>
- <param-value>UTF-8</param-value>
- </init-param>
- </filter>
- <filter-mapping>
- <filter-name>encodingFilter</filter-name>
- <url-pattern>/*</url-pattern>
- </filter-mapping>
- <servlet>
- <servlet-name>springServlet</servlet-name>
- <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
- <init-param>
- <param-name>contextConfigLocation</param-name>
- <param-value>classpath:mvc/*.xml</param-value>
- </init-param>
- <load-on-startup>1</load-on-startup>
- </servlet>
- <servlet-mapping>
- <servlet-name>springServlet</servlet-name>
- <url-pattern>/</url-pattern>
- </servlet-mapping>
- <filter>
- <filter-name>openEntityManagerInViewFilter</filter-name>
- <filter-class>org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter</filter-class>
- </filter>
- <filter-mapping>
- <filter-name>openEntityManagerInViewFilter</filter-name>
- <url-pattern>/*</url-pattern>
- </filter-mapping>
- </web-app>
mvc.xml
Java代碼- <?xml version="1.0" encoding="UTF-8"?>
- <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:mvc="http://www.springframework.org/schema/mvc"
- xsi:schemaLocation="http://www.springframework.org/schema/mvc
- http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
- 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"
- default-lazy-init="true">
- <context:component-scan base-package="com.scu.book.shop" use-default-filters="false">
- <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
- <context:include-filter type="annotation" expression="org.springframework.web.bind.annotation.ControllerAdvice"/>
- </context:component-scan>
- <mvc:annotation-driven>
- <mvc:message-converters register-defaults="true">
- <bean class="org.springframework.http.converter.StringHttpMessageConverter">
- <constructor-arg value="UTF-8" />
- </bean>
- <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
- <property name="objectMapper">
- <bean class="com.fasterxml.jackson.databind.ObjectMapper">
- <property name="dateFormat">
- <bean class="java.text.SimpleDateFormat">
- <constructor-arg value="yyyy-MM-dd HH:mm:ss" />
- </bean>
- </property>
- </bean>
- </property>
- </bean>
- </mvc:message-converters>
- </mvc:annotation-driven>
- <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
- <property name="prefix" value="/WEB-INF/views/"/>
- <property name="suffix" value=".jsp"/>
- </bean>
- <mvc:default-servlet-handler/>
- <mvc:view-controller path="/" view-name="redirect:/task/list"/>
- </beans>
這裏只粘配置文件,其他地方參考源碼。
spring mvc 的jpa JpaRepository數據層 訪問方式匯總