SpringDataJPA學(xué)習(xí)記錄(二)--增刪改查

SpringDataJPA學(xué)習(xí)記錄(二)--增刪改查

標(biāo)簽(空格分隔): springJPA


環(huán)境配置后,開始增刪改查,查是用的最多的,放在最后.

1.增加

增加可以使用JpaRepository接口里面的save方法.查看源碼可以發(fā)現(xiàn)實(shí)際上是使用了em.persist(entity)來(lái)使對(duì)象進(jìn)入持久化狀態(tài),最后提交事務(wù)的時(shí)候再一起更新到數(shù)據(jù)庫(kù).

        User user = new User();
        user.setId(99);
        user.setAddress("上海");
        user.setName("張三");
        user.setPhone("110");

        //保存單個(gè)
        userRepository.save(user);
        //保存或更新
        userRepository.saveAndFlush(user);

        List<User> users = new ArrayList<>();
        users.add(user);
        //保存多個(gè)
        userRepository.save(users);

這里還可以批量插入,對(duì)于mysql支持INSERT user VALUES (20,'王二','111','111'),(21,'王二','111','111');類似這樣的sql語(yǔ)句,具體實(shí)現(xiàn)就需要自己去寫實(shí)現(xiàn)了,這樣可以一次插入多條記錄,效率很高.至于一次插入多少條就可以根據(jù)你的業(yè)務(wù)量來(lái)自己制定.


2.刪除

刪除都是根據(jù)主鍵來(lái)刪除的,區(qū)別就是多條sql和單條sql

        User user = new User();
        user.setId(21);
        user.setName("王二");

        /**
         * 刪除都是根據(jù)主鍵刪除
         */
        //刪除單條,根據(jù)主鍵值
        userRepository.delete(20);
        //刪除全部,先f(wàn)indALL查找出來(lái),再一條一條刪除,最后提交事務(wù)
        userRepository.deleteAll();
        //刪除全部,一條sql
        userRepository.deleteAllInBatch();

        List<User> users = new ArrayList<>();
        users.add(user);
        //刪除集合,一條一條刪除
        userRepository.delete(users);
        //刪除集合,一條sql,拼接or語(yǔ)句  如 id=1 or id=2
        userRepository.deleteInBatch(users);

3.修改

修改也是根據(jù)主鍵來(lái)更新的

        User user = new User();
        user.setId(1);
        user.setName("張三");
        /**
         * 更新也是根據(jù)主鍵來(lái)更新  update XX  xx where id=1
         */
        userRepository.saveAndFlush(user);

批量更新的話,就調(diào)用entityManager的merge函數(shù)來(lái)更新.

首先在service層獲取持久化管理器:

    @PersistenceContext
    private EntityManager em;

批量更新方法,同理插入,刪除也都可以如此做.

    @Transactional
    public void batchUpateCustom(List<User> users) {
        // TODO Auto-generated method stub
        for(int i = 0; i < users.size(); i++) {  
            em.merge(users.get(i));  
            if(i % 30== 0) {  
                em.flush();  
                em.clear();  
            }  
        }
    }

4.查詢

單表查詢,大部分都可以使用下面三種方法解決,多表聯(lián)合查詢的話,下面方法就不是很實(shí)用,下一節(jié)分析多表查詢.

1.使用JpaRepository方法

        //查找全部
        userRepository.findAll();
        //分頁(yè)查詢?nèi)?返回封裝了分頁(yè)信息
        Page<User> pageInfo = userRepository.findAll(new PageRequest(1, 3, Sort.Direction.ASC,"id"));
        //查找全部,并排序
        userRepository.findAll(new Sort(new Sort.Order(Sort.Direction.ASC,"id")));

        User user = new User();
        user.setName("小紅");
        //條件查詢,可以聯(lián)合分頁(yè),排序
        userRepository.findAll(Example.of(user));
        //查詢單個(gè)
        userRepository.findOne(1);

2.解析方法名創(chuàng)建查詢

規(guī)則:
find+全局修飾+By+實(shí)體的屬性名稱+限定詞+連接詞+ ...(其它實(shí)體屬性)+OrderBy+排序?qū)傩?排序方向

例如:

    //分頁(yè)查詢出符合姓名的記錄,同理Sort也可以直接加上
    public List<User> findByName(String name, Pageable pageable);

全局修飾: Distinct, Top, First
關(guān)鍵詞: IsNull, IsNotNull, Like, NotLike, Containing, In, NotIn,
IgnoreCase, Between, Equals, LessThan, GreaterThan, After, Before...
排序方向: Asc, Desc
連接詞: And, Or

And --- 等價(jià)于 SQL 中的 and 關(guān)鍵字,比如 findByUsernameAndPassword(String user, Striang pwd);
Or --- 等價(jià)于 SQL 中的 or 關(guān)鍵字,比如 findByUsernameOrAddress(String user, String addr);
Between --- 等價(jià)于 SQL 中的 between 關(guān)鍵字,比如 findBySalaryBetween(int max, int min);
LessThan --- 等價(jià)于 SQL 中的 "<",比如 findBySalaryLessThan(int max);
GreaterThan --- 等價(jià)于 SQL 中的">",比如 findBySalaryGreaterThan(int min);
IsNull --- 等價(jià)于 SQL 中的 "is null",比如 findByUsernameIsNull();
IsNotNull --- 等價(jià)于 SQL 中的 "is not null",比如 findByUsernameIsNotNull();
NotNull --- 與 IsNotNull 等價(jià);
Like --- 等價(jià)于 SQL 中的 "like",比如 findByUsernameLike(String user);
NotLike --- 等價(jià)于 SQL 中的 "not like",比如 findByUsernameNotLike(String user);
OrderBy --- 等價(jià)于 SQL 中的 "order by",比如 findByUsernameOrderBySalaryAsc(String user);
Not --- 等價(jià)于 SQL 中的 "! =",比如 findByUsernameNot(String user);
In --- 等價(jià)于 SQL 中的 "in",比如 findByUsernameIn(Collection<String> userList) ,方法的參數(shù)可以是 Collection 類型,也可以是數(shù)組或者不定長(zhǎng)參數(shù);
NotIn --- 等價(jià)于 SQL 中的 "not in",比如 findByUsernameNotIn(Collection<String> userList) ,方法的參數(shù)可以是 Collection 類型,也可以是數(shù)組或者不定長(zhǎng)參數(shù);

嵌套實(shí)體:

主實(shí)體中子實(shí)體的名稱+ _ +子實(shí)體的屬性名稱
List<Person> findByAddress_ZipCode(ZipCode zipCode)
表示查詢所有 Address(地址)的zipCode(郵編)為指定值的所有Person(人員)


3.JPQL查詢

一個(gè)類似HQL的語(yǔ)法,在接口上使用@Query標(biāo)識(shí)

 @Query("select a from user a where a.id = ?1") 
 public User findById(Long id); 

使用@Modifying標(biāo)識(shí)修改

 @Modifying 
 @Query("update User a set a.name = ?1 where a.id < ?2") 
 public int updateName(String name, Long id);

攜帶分頁(yè)信息:

    @Query("select u from User u where u.name=?1")
    public List<User> findByName(String name, Pageable pageable);

除此之外也可以使用原生sql,只需要@Query(nativeQuery=true)標(biāo)識(shí)即可.

創(chuàng)建查詢順序:

創(chuàng)建查詢的順序
Spring Data JPA 在為接口創(chuàng)建代理對(duì)象時(shí),如果發(fā)現(xiàn)同時(shí)存在多種上述情況可用,它該優(yōu)先采用哪種策略呢?為此,<jpa:repositories> 提供了 query-lookup-strategy 屬性,用以指定查找的順序。它有如下三個(gè)取值:
create --- 通過解析方法名字來(lái)創(chuàng)建查詢。即使有符合的命名查詢,或者方法通過 @Query 指定的查詢語(yǔ)句,都將會(huì)被忽略。
create-if-not-found --- 如果方法通過 @Query 指定了查詢語(yǔ)句,則使用該語(yǔ)句實(shí)現(xiàn)查詢;如果沒有,則查找是否定義了符合條件的命名查詢,如果找到,則使用該命名查詢;如果兩者都沒有找到,則通過解析方法名字來(lái)創(chuàng)建查詢。這是 query-lookup-strategy 屬性的默認(rèn)值。
use-declared-query --- 如果方法通過 @Query 指定了查詢語(yǔ)句,則使用該語(yǔ)句實(shí)現(xiàn)查詢;如果沒有,則查找是否定義了符合條件的命名查詢,如果找到,則使用該命名查詢;如果兩者都沒有找到,則拋出異常。

5.計(jì)數(shù)

計(jì)數(shù)就直接使用JpaRepository的count方法

        //查找總數(shù)量
        userRepository.count();

        User user = new User();
        user.setName("小紅");
        //條件計(jì)數(shù)
        userRepository.count(Example.of(user));

6.判斷是否存在

計(jì)數(shù)就直接使用JpaRepository的exists方法

        //根據(jù)主鍵判斷是否存在
        userRepository.exists(1);

        User user = new User();
        user.setName("小紅");
        //根據(jù)條件判斷是否存在
        userRepository.exists(Example.of(user));

7.自定義查詢

首先自定義一個(gè)接口,用于定義自定義方法,如UserRepositoryCustom

然后讓UserRepository實(shí)現(xiàn)該接口,這樣的話就可以使用其中的方法.

然后寫UserRepositoryImpl實(shí)現(xiàn)UserRepositoryCustom接口

最后設(shè)置jpa:repositoriesrepository-impl-postfix="Impl",這樣的話JPA會(huì)查找自定義實(shí)現(xiàn)類命名規(guī)則,這樣的話JPA在相應(yīng)UserRepository包下面查找實(shí)現(xiàn)類,找到則會(huì)使用其中的實(shí)現(xiàn)方法,而不去自己實(shí)現(xiàn).

具體可以看項(xiàng)目demo,或者下一節(jié)的復(fù)雜查詢

8.備注

1.盡量避免getSingleResult

下面是該方法的部分源碼,可以看出,如果查詢出來(lái)的個(gè)數(shù)為0或者大于1都拋出異常,一般來(lái)說(shuō)我們希望查找不到就返回null,而拋異常則是不想看到的,如果要使用,則需要try一下該代碼塊,在catch里面返回null.

        try {
            List he = this.query.list();
            if(he.size() == 0) {
                NoResultException uniqueResult1 = new NoResultException("No entity found for query");
                this.getEntityManager().handlePersistenceException(uniqueResult1);
                throw uniqueResult1;
            } else if(he.size() > 1) {
                HashSet uniqueResult = new HashSet(he);
                if(uniqueResult.size() > 1) {
                    NonUniqueResultException nure = new NonUniqueResultException("result returns more than one elements");
                    this.getEntityManager().handlePersistenceException(nure);
                    throw nure;
                } else {
                    return uniqueResult.iterator().next();
                }
            } else {
                return he.get(0);
            }
        } catch (QueryExecutionRequestException var4) {
            throw new IllegalStateException(var4);
        } catch (TypeMismatchException var5) {
            throw new IllegalArgumentException(var5);
        } catch (HibernateException var6) {
            throw this.getEntityManager().convert(var6);
        }

基本增刪改查就是以上這些,都很容易上手,個(gè)人感覺比mybatis方便多了.初學(xué)該框架,借鑒了很多博客,更多使用技巧還要在實(shí)戰(zhàn)中發(fā)現(xiàn),如果問題,請(qǐng)留言交流.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容