一、maven配置檔案加入依賴
Spring Data JPA 依賴,最新穩定的版本為1.10.1.RELEASE,這裡需要說明下的是,其依然依賴hibernate JPA相關JAR,hibernate-core之類的是不需要的。hibernate是JPA規範的一種實作,是以需要加入其依賴。ehcache是hibernate二級緩存的配置,不是必須的。
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>1.10.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-ehcache</artifactId>
<version>5.1.0.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.2.4.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>5.1.0.Final</version>
</dependency>
二、聲明持久層接口
這裡給大家說說幾個常見的很重要的核心類檔案,源碼下面也貼上了。
大家可以看到這個類的繼承結構,這裡值得說的是,Spring Data JPA的持久層的借口命名是有一套規範的,後面你加入的自定義方法滿足其規範之後,你的實作類都是可以不需要寫的,而且事務管理也幫你做好了。是不是覺得很神奇呢!
JpaRepository繼承了PagingAndSortingRepository、QueryByExampleExecutor,PagingAndSortingRepository又繼承了CrudRepository,CrudRepository 大家通過看名字也應該是幹啥的,其就是CRUD的,PagingAndSortingRepository裡面加了分頁的相關方法。
CrudRepository.java
package org.springframework.data.repository;
import java.io.Serializable;
@NoRepositoryBean
public interface CrudRepository<T, ID extends Serializable> extends Repository<T, ID> {
<S extends T> S save(S entity);
<S extends T> Iterable<S> save(Iterable<S> entities);
T findOne(ID id);
boolean exists(ID id);
Iterable<T> findAll();
Iterable<T> findAll(Iterable<ID> ids);
long count();
void delete(ID id);
void delete(T entity);
void delete(Iterable<? extends T> entities);
void deleteAll();
}
Repository.java 是一個空的接口
package org.springframework.data.repository;
import java.io.Serializable;
public interface Repository<T, ID extends Serializable> {
}
大夥可以看看其源碼,源碼裡面的注釋我就不貼出來了,大家看方法名應該就知道其具體的意思了。
package org.springframework.data.jpa.repository;
import java.io.Serializable;
import java.util.List;
import javax.persistence.EntityManager;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.Sort;
import org.springframework.data.repository.NoRepositoryBean;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.data.repository.query.QueryByExampleExecutor;
@NoRepositoryBean
public interface JpaRepository<T, ID extends Serializable>
extends PagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T> {
List<T> findAll();
List<T> findAll(Sort sort);
List<T> findAll(Iterable<ID> ids);
<S extends T> List<S> save(Iterable<S> entities);
void flush();
<S extends T> S saveAndFlush(S entity);
void deleteInBatch(Iterable<T> entities);
void deleteAllInBatch();
T getOne(ID id);
@Override
<S extends T> List<S> findAll(Example<S> example);
@Override
<S extends T> List<S> findAll(Example<S> example, Sort sort);
}
大家用maven的時候,可以将源碼順便下下來,myeclipse裡面設定一下即可,如圖所示:
我這裡的接口如下:
package com.example.dao;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import com.example.entity.UserInfo;
public interface UserDaoSpringJpa extends JpaRepository<UserInfo,String>{
public List<UserInfo> findByUsername(String username);//注意這個命名,Spring會自動根據這個username去資料庫裡面取值,可以看到後面生成的sql語句,where條件裡面就加了 where user_name =?,這就是Spring Data JPA查詢命名的友善之處,隻要按規則命名,他會采取一定的政策,通過解析方法名稱建立查詢,來生成sql語句。
}
JpaRepository<UserInfo,String> 這裡是泛型接口,UserInfo是我們的實體類,String是主鍵類型,也稱為id,大家以前寫hibernatebasedao的時候可能是見過了的。這叫 泛型限定式依賴注入,也是Spring4的一大特性。之前有篇博文也提到了 http://enetq.blog.51cto.com/479739/1783339
三、在接口中聲明自定義業務方法
Spring Data JPA将會根據指定的政策(後續會有文章說明,本此隻是簡單的介紹下,能跑起來。)為該方法生成實作代碼,使用者不需要實作該接口,這樣就隻需要寫接口就行了。
四、Spring配置檔案相關配置
配置檔案中加入 jpa:repositories,啟用掃描并自動建立代理 Spring 初始化容器時将會掃描 base-package 指定的包目錄及其子目錄,為繼承 Repository 或其子接口的接口建立代理對象,并将代理對象注冊為 Spring Bean,業務層便可以通過 Spring autowired來直接使用該對象。
此需要jpa命名空間:
xmlns:jpa="
xsi:schemaLocation="
http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd
"
具體的配置參加如下:各參數的含義配置檔案裡面已經給出了詳細的解釋,同時給出了相關配置類的源碼。
一些配置的屬性,大家在源碼裡面也是可以找到的。
<!-- 啟用掃描并自動建立代理 Spring 初始化容器時将會掃描 base-package 指定的包目錄及其子目錄,
為繼承 Repository 或其子接口的接口建立代理對象,并将代理對象注冊為 Spring Bean,
業務層便可以通過 Spring autowired來直接使用該對象。 -->
<jpa:repositories base-package="com.example.service"
entity-manager-factory-ref="entityManagerFactory"
transaction-manager-ref="transactionManager"/>
<!-- 通過entityManagerFactory的createEntityManager()方法擷取EntityManager -->
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<!-- 指定資料源 -->
<property name="dataSource" ref="dataSource"/>
<property name="packagesToScan" value="com.example"/>
<!-- 用于指定持久化實作廠商類 -->
<property name="persistenceProvider">
<bean class="org.hibernate.jpa.HibernatePersistenceProvider"/><!-- 替換 org.hibernate.ejb.HibernatePersistence -->
</property>
<!-- jpaVendorAdapter :用于設定實作廠商JPA實作的特定屬性,
目前Spring提供了HibernateJpaVendorAdapter、OpenJpaVendorAdapter、EclipseLinkJpaVendorAdapter、
三個實作。 TopLinkJpaVendorAdapter在Spring4裡面已經删除了,
目前支援的資料庫如下: DB2, DERBY, H2, HSQL, INFORMIX, MYSQL, ORACLE, POSTGRESQL, SQL_SERVER, SYBASE,
這個類型在Spring提供的枚舉類型 Database 裡面有詳細定義-->
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="generateDdl" value="false"/>
<property name="database" value="MYSQL"/>
<property name="databasePlatform" value="org.hibernate.dialect.MySQL5InnoDBDialect"/>
<property name="showSql" value="true"/>
</bean>
</property>
<!-- jpaDialect:用于指定一些進階特性,如事務管理,擷取具有事務功能的連接配接對象等,
目前Spring提供HibernateJpaDialect、OpenJpaDialect 、EclipseLinkJpaDialect -->
<property name="jpaDialect">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect"/>
</property>
<!-- 用于指定JPA屬性,跟之前hibernateProperties是一緻的 -->
<property name="jpaPropertyMap">
<map>
<entry key="hibernate.dialect" value="${hibernate.dialect}"/>
<entry key="hibernate.show_sql" value="${hibernate.show_sql}"/>
<entry key="hibernate.format_sql" value="false"/>
<entry key="hibernate.query.substitutions" value="${hibernate.query.substitutions}"/>
<entry key="hibernate.default_batch_fetch_size" value="${hibernate.default_batch_fetch_size}"/>
<entry key="hibernate.max_fetch_depth" value="${hibernate.max_fetch_depth}"/>
<entry key="hibernate.generate_statistics" value="${hibernate.generate_statistics}"/>
<entry key="hibernate.bytecode.use_reflection_optimizer" value="${hibernate.bytecode.use_reflection_optimizer}"/>
<!-- 緩存Cache配置 -->
<entry key="hibernate.cache.provider_class" value="${hibernate.cache.provider_class}"/>
<entry key="hibernate.cache.use_second_level_cache" value="${hibernate.cache.use_second_level_cache}"/>
<entry key="hibernate.cache.use_query_cache" value="${hibernate.cache.use_query_cache}"/>
<entry key="hibernate.cache.region.factory_class" value="${hibernate.cache.region.factory_class}"/>
<entry key="net.sf.ehcache.configurationResourceName" value="${net.sf.ehcache.configurationResourceName}"/>
<entry key="hibernate.cache.use_structured_entries" value="${hibernate.cache.use_structured_entries}"/>
</map>
</property>
</bean>
<!--指定事務管理器-->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
jpaVendorAdapter 相關參數的設定AbstractJpaVendorAdapter 類裡面有詳細說明:如下圖所示:
package com.example.action;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import com.example.entity.UserInfo;
import com.example.service.impl.UserInfoService;
import com.google.gson.Gson;
@Controller
public class UserInfoAction {
@Autowired
private UserInfoService userInfoService;
private Logger log = Logger.getLogger(this.getClass());
@RequestMapping("findByUserName.do")
public void findByUserName(HttpServletRequest request,
HttpServletResponse response, ModelMap map) throws IOException{
List<UserInfo> listUserInfo = userInfoService.findByUsername("wj");
for(UserInfo userInfo:listUserInfo){
log.info(userInfo.getUsername()+":"+userInfo.getEmail());
}
Gson gson = new Gson();
String jsonStr = gson.toJson(listUserInfo);
response.getWriter().println(jsonStr);
}
@RequestMapping("saveUser.do")
public void saveUser(HttpServletRequest request,
HttpServletResponse response, ModelMap map) throws IOException{
List<UserInfo> listUserInfo = new ArrayList<UserInfo>();
for(int i=0;i<10;i++){
UserInfo userInfo = new UserInfo();
userInfo.setId(UUID.randomUUID().toString());
userInfo.setUsername(Math.random()+"wj"+i);
userInfo.setPassword(Math.random()+"ss"+i);
listUserInfo.add(userInfo);
}
listUserInfo = userInfoService.save(listUserInfo);//可以直接儲存一個list集合,當然這裡隻是測試,實際的批量新增,批量更新的時候,是需要到一定的條數之後,flush一下的,比如20條,這根hibernate是類似的。
userInfoService.delete("21");//删除
UserInfo userInfo = userInfoService.findOne("2eab2884-e0e9-419c-8871-1d198b399813");
userInfo.setUsername("zhangsan");
userInfoService.saveAndFlush(userInfo);//更新
Gson gson = new Gson();
String jsonStr = gson.toJson(listUserInfo);
response.getWriter().println(jsonStr);
}
}
Hibernate: select userinfo0_.id as id1_4_, userinfo0_.birthday as birthday2_4_, userinfo0_.contact as contact3_4_, userinfo0_.create_time as create_t4_4_, userinfo0_.create_user as create_u5_4_, userinfo0_.delete_flag as delete_f6_4_, userinfo0_.email as email7_4_, userinfo0_.last_login_ip as last_log8_4_, userinfo0_.last_login_time as last_log9_4_, userinfo0_.last_logout_time as last_lo10_4_, userinfo0_.modify_time as modify_11_4_, userinfo0_.online_state as online_12_4_, userinfo0_.password as passwor13_4_, userinfo0_.register_time as registe14_4_, userinfo0_.sex as sex15_4_, userinfo0_.user_state as user_st16_4_, userinfo0_.username as usernam17_4_ from rbac.user_info userinfo0_ where userinfo0_.username=?
Hibernate: insert into rbac.user_info (birthday, contact, create_time, create_user, delete_flag, email, last_login_ip, last_login_time, last_logout_time, modify_time, online_state, password, register_time, sex, user_state, username, id) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
insert 語句列印了10條,
delete from rbac.user_info where id=?
Hibernate: update rbac.user_info set birthday=?, contact=?, create_time=?, create_user=?, delete_flag=?, email=?, last_login_ip=?, last_login_time=?, last_logout_time=?, modify_time=?, online_state=?, password=?, register_time=?, sex=?, user_state=?, username=? where id=?