天天看點

Spring Data開發手冊|手摸手教你簡化持久層開發工作

Spring Data,是為資料通路提供熟悉且一緻的基于Spring的程式設計模型,同時仍然保留底層資料存儲的特殊特性。

它是對于資料通路技術,關系資料庫和非關系資料庫,map-reduce架構和基于雲的資料服務變得容易。Spring Data是一個總括項目,其中包含很多特定于資料庫相關的子項目。

Spring Data開發手冊|手摸手教你簡化持久層開發工作

首先,先帶大家看一下本篇文章的大緻介紹。

沒目錄怎麼知道這篇到底有多少幹貨呢?

  • Spring Data是什麼
  • Spring Data能幹什麼
  • Spring Data的第一個HelloWorld程式
  • 通過名字來确定方法
  • 通過注解的形式來實作查詢
  • 寫本地的SQL查詢
  • 增删改的玩法
  • 使用架構中提供的增删改查的方法
  • 分頁和排序
  • JpaRepository的使用

是不是很清晰呢,現在開始進入正文,一個一個來:

我們傳統的開發中,我們的整個DAO層的代碼上都是相對來說,都是比較複雜的,在這種情況下,Spring團隊就考慮到一個問題,能不能開發一個架構,這個架構能夠最大限度的減少DAO層的開發呢?

Spring Data就是為了簡化DAO層操作的一個架構

傳統的增删改查在我們的Spring Data中已經實作了,也就是說大部分的DAO層操作部分不用寫了,僅僅隻是需要編寫複雜的業務的調用就可以啦

Spring Data開發手冊|手摸手教你簡化持久層開發工作

寫的這部分的代碼,是需要寫接口的聲明就可以啦,不用寫實作,這個實作是自動實作的

Spring Data能幹什麼

主要用途:

  • 傳統的增删改查
  • 排序
  • 分頁
  • 排序後分頁

即使你需要寫DAO,也隻是寫聲明就可以啦,不用寫實作

Spring Data的第一個HelloWorld程式(JPA、Hibernate、Spring、SpringMVC、Spring Data)

導包

Spring Data開發手冊|手摸手教你簡化持久層開發工作

編寫配置檔案

 <?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:p="http://www.springframework.org/schema/p"
 xmlns:context="http://www.springframework.org/schema/context" 
 xmlns:tx="http://www.springframework.org/schema/tx"
 xmlns:aop="http://www.springframework.org/schema/aop"
 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.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/data/jpa 
        http://www.springframework.org/schema/data/jpa/spring-jpa-1.2.xsd">
        
        <!--引入Properties檔案-->
        <context:property-placeholder location="classpath:config/db.properties"/>
        
        <!--配置c3p0的連接配接池-->
        <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
            <property name="driverClass" value="${driverClass}"></property>
            <property name="jdbcUrl" value="${url}"></property>
            <property name="user" value="${user}"></property>
            <property name="password" value="${password}"></property>
            <property name="acquireIncrement" value="${acquireIncrement}"></property>
            <property name="maxPoolSize" value="${maxPoolSize}"></property>
            <property name="minPoolSize" value="${minPoolSize}"></property>
            <property name="maxStatements" value="${maxStatements}"></property>
        </bean>
        
        <!--配置JPA實作産品的擴充卡-->
        <bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
        </bean>
        
        <!--配置EntityManager對象-->
        
        <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
           <!--注入資料源-->
           <property name="dataSource" ref="dataSource"></property>
           <!--掃描entity包的--> 
           <property name="packagesToScan" value="com.qy.helloworld"></property>
           <!--注入JPA實作産品的擴充卡-->
           <property name="jpaVendorAdapter" ref="jpaVendorAdapter"></property>
           <!--配置的是Hibernate的其他配置  除了連接配接資料庫4大要素之外的其餘配置-->
           <property name="jpaProperties">
              <props>
               <!--是否自動建立表 -->
               <prop key="hibernate.hbm2ddl.auto">update</prop>
               <!--配置是否展示SQL-->
               <prop key="hibernate.show_sql">true</prop>
               <!--是否格式化SQL-->
               <prop key="hibernate.format_sql">true</prop>
               <!--連接配接資料庫的方言-->
               <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
            </props>
           </property>
        </bean>
        
        
        <!--配置事務環境-->
        
        <bean id="jpaTransactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
           <!--注入dataSource-->
           <property name="dataSource" ref="dataSource"></property>
           <!--注入entityManagerFactory對象-->
           <property name="entityManagerFactory" ref="entityManagerFactory"></property>
        </bean>
        
        <!--使用事務-->
        <tx:annotation-driven transaction-manager="jpaTransactionManager"/>
        
        <!--配置AOP的自動代理-->
        <aop:aspectj-autoproxy></aop:aspectj-autoproxy> 
        
        <!--配置Spring的包掃描-->
        <context:component-scan base-package="com.qy.helloworld"></context:component-scan>
        
        <!--Spring data的包的掃描  這裡的掃描掃描的是DAO層所在的位置-->
        <jpa:repositories base-package="com.qy.helloworld" entity-manager-factory-ref="entityManagerFactory" transaction-manager-ref="jpaTransactionManager"></jpa:repositories>

</beans>      

編寫實體類和映射

@Entity
@Table(name="t_user")
public class User {

 @Id
 @GeneratedValue(strategy=GenerationType.IDENTITY)
 private int userId;
 
 private String userName;
 
 private String password;
}      

編寫Repository類

public interface UserRepository extends Repository<User,Integer>{
 /**
  * 這個的意思是通過id找使用者
  * @Title: getByUserId   
  * @Description: TODO
  * @param: @param userId
  * @param: @return      
  * @return: User      
  * @throws
  */
 public User getByUserId(int userId);
}      

測試

ClassPathXmlApplicationContext applicationContext=new ClassPathXmlApplicationContext("config/bean-base.xml");
  //擷取DAO的對象
  UserRepository userRepository=applicationContext.getBean(UserRepository.class);
 User users=userRepository.findByUserId(1);
}      

代碼示範:

舉例如下

public interface UserRepository extends Repository<User,Integer>{
 /**
  * 這個的意思是通過id找使用者
  * @Title: getByUserId   
  * @Description: TODO
  * @param: @param userId
  * @param: @return      
  * @return: User      
  * @throws
  */
 public User getByUserId(int userId);
 
 /**
  * 記住查詢的開頭隻能是  get 或者  find 開頭   By:通過什麼查詢
  * @Title: findByUserId   
  * @Description: TODO
  * @param: @param userId
  * @param: @return      
  * @return: User      
  * @throws
  */
 public User findByUserId(int userId);
 
 /**
  * 通過使用者名的模糊查詢
  * @Title: findByUserNameLike   
  * @Description: TODO
  * @param: @param userName
  * @param: @return      
  * @return: List<User>      
  * @throws
  */
 public List<User> findByUserNameLike(String userName);
 
 /**
  * 通過使用者名和密碼的Like來進行查詢
  * @Title: findByUserNameLikeAndPasswordLike   
  * @Description: TODO
  * @param: @param userName
  * @param: @return      
  * @return: List<User>      
  * @throws
  */
 public List<User> findByUserNameLikeAndPasswordLike(String userName,String password);
 /**
  * 使用者名和密碼like 然後id小于一個範圍
  * @Title: findByUserNameLikeAndPasswordLikeAndUserIdLessThan   
  * @Description: TODO
  * @param: @param userName
  * @param: @param password
  * @param: @param userId
  * @param: @return      
  * @return: List<User>      
  * @throws
  */
 public List<User> findByUserNameLikeAndPasswordLikeAndUserIdLessThan(String userName,String password,int userId);
}      

注意:一般情況下不會通過名字直接來寫相應的方法,因為如果條件過多那麼這個時候我們就存在名字特别長的問題

通過注解的模式來實作查詢

舉例如下

 /**
     * 查詢所有  沒有條件直接查詢
     * @Title: findUserAll   
     * @Description: TODO
     * @param: @return      
     * @return: List<User>      
     * @throws
     */
 @Query("from User")
 public List<User> findUserAll();
 
 /**
  * 通過id來查找資料     參數直接拼接到後面
  * @Title: findUserById   
  * @Description: TODO
  * @param: @param userId
  * @param: @return      
  * @return: List<User>      
  * @throws
  */
 @Query("from User u  where u.userId<3")
 public List<User> findUserById();
 /**
  * 通過id查詢存在占位符的情況
  * @Title: findUserById1   
  * @Description: TODO
  * @param: @param userId
  * @param: @return      
  * @return: List<User>      
  * @throws
  */
 @Query("from User u  where u.userId<?")
 public List<User> findUserById1(int userId);
 
 /**
  * 多條件的查詢  可以指定目前的參數映射的這個位置
  * @Title: getUserByNameAndId   
  * @Description: TODO
  * @param: @param userName
  * @param: @param userId
  * @param: @return      
  * @return: User      
  * @throws
  */
 @Query("from User u where u.userId=?2 and u.userName=?1")
 public User getUserByNameAndId(String userName,int userId);
 
 /**
  * 模糊查詢的時候動态拼接上  %的問題
  * @Title: findUserByLike1   
  * @Description: TODO
  * @param: @param userName
  * @param: @return      
  * @return: List<User>      
  * @throws
  */
 @Query("from User u where u.userName like concat ('%',?,'%')")
 public List<User> findUserByLike1(String userName);      

寫本地的SQL 查詢

舉例如下

 /**
  * 通過
  * @Title: findUserAll11   
  * @Description: TODO
  * @param: @return      
  * @return: List<User>      
  * @throws
  */
 @Query(nativeQuery=true,value="select * from t_user")
 public List<User> findUserAll11();      

添加業務邏輯 增加事務環境

 @Service
@Transactional                  //提供一個事務的環境
public class UserService {
 
 @Autowired
 private UserRepository userRepository=null;
 
 /**
  * 資料的更新
  * @Title: update   
  * @Description: TODO
  * @param: @param userName
  * @param: @param password
  * @param: @param userId      
  * @return: void      
  * @throws
  */
 public void update(String userName,String password,int userId){
  userRepository.update(userName, password, userId);
 }
 
 
 public void delete(int userId){
  userRepository.delete(userId);
 }
 
 public void insert(String userName,String password){
  userRepository.insert(userName, password);
 }

}      

編寫repository的對象

 public interface UserRepository extends Repository<User,Integer>{
 /**
  * 實作增删改的方法
  * @Title: add   
  * @Description: TODO
  * @param: @param userName
  * @param: @param password      
  * @return: void      
  * @throws
  */
 @Modifying    //這個注解的作用表示的是更新資料
 @Query("update User u set u.userName=?,u.password=? where u.userId=?")
 public void update(String userName,String password,int userId);
 
 /**
  * 更新資料
  * @Title: delete   
  * @Description: TODO
  * @param: @param userId      
  * @return: void      
  * @throws
  */
 @Modifying    //這個注解的作用表示的是更新資料
 @Query("delete User u where u.userId=?")
 public void delete(int userId);
 /**
  * 添加資料
  * @Title: insert   
  * @Description: TODO
  * @param: @param userName
  * @param: @param password      
  * @return: void      
  * @throws
  */
 @Modifying    //這個注解的作用表示的是更新資料
 @Query(nativeQuery=true,value="insert into t_user(userName,password) values(?,?)")
 public void insert(String userName,String password);
 
}      

測試

 @Test
 public void testHelloWorld() throws Exception {
  
  ClassPathXmlApplicationContext applicationContext=new ClassPathXmlApplicationContext("config/bean-base.xml");
  //擷取DAO的對象
  UserService userService=applicationContext.getBean(UserService.class);

  userService.insert("小羽","做程式的");
 }      

提供的是Repository

 public interface UserRepository extends CrudRepository<User,Integer>{

}      

提供的Repository

 public interface UserRepository extends PagingAndSortingRepository<User,Integer>{

}      

測試

 public class Test001 {

 
 @Test
 public void testPaging() throws Exception {
  ClassPathXmlApplicationContext applicationContext=new ClassPathXmlApplicationContext("config/bean-base.xml");
  //擷取DAO的對象
  UserRepository userRepository=applicationContext.getBean(UserRepository.class);
 /**
  * 第一個參數:目前的頁的頁數是多少  頁數是從0開始的   第二頁:2-1
  * 第二個參數:表示的是每一頁條目數
  */
  Page<User> pages=userRepository.findAll(new PageRequest(2-1,2));
 
  System.out.println("查詢到的資料:"+pages.getContent());
  System.out.println("資料的條目數:"+pages.getSize());
  System.out.println("頁數:"+pages.getNumber());
  System.out.println("資料條目的總數:"+pages.getTotalElements());
  System.out.println("一共的頁數:"+pages.getTotalPages());
  System.out.println("排序的規則:"+pages.getSort());
 
 }
 
 /**
  * 排序
  * @Title: testSort   
  * @Description: TODO
  * @param: @throws Exception      
  * @return: void      
  * @throws
  */
 @Test
 public void testSort() throws Exception {
  ClassPathXmlApplicationContext applicationContext=new ClassPathXmlApplicationContext("config/bean-base.xml");
  //擷取DAO的對象
  UserRepository userRepository=applicationContext.getBean(UserRepository.class);
  /**
   * 排序
   * 第一個參數:升序或者降序  Direction.ASC/DESC
   * 第二個參數: 排序的這個列
   */
  List<User> users=(List<User>) userRepository.findAll(new Sort(Direction.DESC,"userId"));
  
  System.out.println(users);
 }
 
 /**
  * 排序後分頁
  * @Title: testSortAndPaging   
  * @Description: TODO
  * @param: @throws Exception      
  * @return: void      
  * @throws
  */
 @Test
 public void testSortAndPaging() throws Exception {
  ClassPathXmlApplicationContext applicationContext=new ClassPathXmlApplicationContext("config/bean-base.xml");
  //擷取DAO的對象
  UserRepository userRepository=applicationContext.getBean(UserRepository.class);
  
  Page<User> pages=userRepository.findAll(new PageRequest(2-1,2,new Sort(Direction.DESC,"userId")));
  
  System.out.println(pages.getContent());
 }
}      

提供的repository

 public interface UserRepository extends JpaRepository<User,Integer>{

}      

測試

 public class Test001 {
 @Test
 public void testPaging() throws Exception {
  ClassPathXmlApplicationContext applicationContext=new ClassPathXmlApplicationContext("config/bean-base.xml");
  //擷取DAO的對象
  UserRepository userRepository=applicationContext.getBean(UserRepository.class);
    
//  long count=userRepository.count();
  
//  User user=userRepository.findOne(15);
//  user.setUserName("小羽");
  
  //儲存或者更新資料
//  userRepository.saveAndFlush(user);
  
 
  List<User> users=userRepository.findAll();
  
  //批處理
  userRepository.deleteInBatch(users);
   
  //System.out.println("統計:"+count);
 }
}      

結語

Spring Data是我們開發中離不開的經常用到的技術,其涉及的技術和知識面其實遠不止上面列出的這些。

後續淺羽會繼續更新關于Spring Data的開發知識,隻希望能對大家有所幫助,謝謝大家的支援!

寫作秉持初心,緻力于讓每一位網際網路人共同進步。

往期好文

往期推薦

Spring Data開發手冊|Java持久化API(JPA)需要了解到什麼程度呢?

動态資源技術JSP|Java與Html的美好相遇

尚能飯否|技術越來越新,我對老朋友jQuery還是一如既往熱愛

告别祈禱式程式設計|單元測試在項目裡的正确落地姿勢

元件必知必會|那些年我們使用過的輪子—Filter和Proxy

ES開發指南|如何快速上手ElasticSearch

玩轉Redis|學會這10點讓你分分鐘拿下Redis,滿足你的一切疑問

超級詳細|Linux系統下從0到1的玩法大全

如果你覺得淺羽的文章對你有幫助的話,請在微信搜尋并關注「 淺羽的IT小屋 」微信公衆号,我會在這裡分享一下計算機資訊知識、理論技術、工具資源、軟體介紹、後端開發、面試、工作感想以及一些生活随想等一系列文章。所見所領,皆是生活。慢慢來,努力一點,你我共同成長...

繼續閱讀