SpringDataJPA分析

image.png
文件目錄技巧

配置文件

<?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:aop="http://www.springframework.org/schema/aop"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:jdbc="http://www.springframework.org/schema/jdbc"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:jpa="http://www.springframework.org/schema/data/jpa" xmlns:task="http://www.springframework.org/schema/task"
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
         http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/context
         http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/jdbc
         http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
        http://www.springframework.org/schema/tx
         http://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/data/jpa
        http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">

    <!--spring 和 spring data jpa的配置-->

    <!-- 1.創(chuàng)建entityManagerFactory對象交給spring容器管理-->
    <bean id="entityManagerFactoty" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <!--配置的掃描的包(實(shí)體類所在的包) -->
        <property name="packagesToScan" value="cn.itcast.domain" />
        <!-- jpa的實(shí)現(xiàn)廠家 -->
        <property name="persistenceProvider">
            <bean class="org.hibernate.jpa.HibernatePersistenceProvider"/>
        </property>

        <!--jpa的供應(yīng)商適配器 -->
        <property name="jpaVendorAdapter">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
                <!--配置是否自動(dòng)創(chuàng)建數(shù)據(jù)庫表 -->
                <property name="generateDdl" value="false" />
                <!--指定數(shù)據(jù)庫類型 -->
                <property name="database" value="MYSQL" />
                <!--數(shù)據(jù)庫方言:支持的特有語法 -->
                <property name="databasePlatform" value="org.hibernate.dialect.MySQLDialect" />
                <!--是否顯示sql -->
                <property name="showSql" value="true" />
            </bean>
        </property>

        <!--jpa的方言 :高級的特性 -->
        <property name="jpaDialect" >
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
        </property>

    </bean>

    <!--2.創(chuàng)建數(shù)據(jù)庫連接池 -->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="user" value="root"></property>
        <property name="password" value="root"></property>
        <property name="jdbcUrl" value="jdbc:mysql:///" ></property>
        <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
    </bean>

    <!--3.整合spring dataJpa-->
    <jpa:repositories base-package="cn.itcast.dao" transaction-manager-ref="transactionManager"
                   entity-manager-factory-ref="entityManagerFactoty" ></jpa:repositories>

    <!--4.配置事務(wù)管理器 -->
    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactoty"></property>
    </bean>

    <!-- 4.txAdvice-->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <tx:method name="save*" propagation="REQUIRED"/>
            <tx:method name="insert*" propagation="REQUIRED"/>
            <tx:method name="update*" propagation="REQUIRED"/>
            <tx:method name="delete*" propagation="REQUIRED"/>
            <tx:method name="get*" read-only="true"/>
            <tx:method name="find*" read-only="true"/>
            <tx:method name="*" propagation="REQUIRED"/>
        </tx:attributes>
    </tx:advice>

    <!-- 5.aop-->
    <aop:config>
        <aop:pointcut id="pointcut" expression="execution(* cn.itcast.service.*.*(..))" />
        <aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut" />
    </aop:config>

    <!--5.聲明式事務(wù) -->

    <!-- 6. 配置包掃描-->
    <context:component-scan base-package="cn.itcast" ></context:component-scan>
</beans>

DAO層封裝

/**
 * 符合SpringDataJpa的dao層接口規(guī)范
 *      JpaRepository<操作的實(shí)體類類型利虫,實(shí)體類中主鍵屬性的類型>
 *          * 封裝了基本CRUD操作
 *      JpaSpecificationExecutor<操作的實(shí)體類類型>
 *          * 封裝了復(fù)雜查詢(分頁)
 */
public interface CustomerDao extends JpaRepository<Customer,Long> ,JpaSpecificationExecutor<Customer> {

    /**
     * 案例:根據(jù)客戶名稱查詢客戶
     *      使用jpql的形式查詢
     *  jpql:from Customer where custName = ?
     *
     *  配置jpql語句码泛,使用的@Query注解
     */
    @Query(value="from Customer where custName = ?")
    public Customer findJpql(String custName);


    /**
     * 案例:根據(jù)客戶名稱和客戶id查詢客戶
     *      jpql: from Customer where custName = ? and custId = ?
     *
     *  對于多個(gè)占位符參數(shù)
     *      賦值的時(shí)候忠蝗,默認(rèn)的情況下,占位符的位置需要和方法參數(shù)中的位置保持一致
     *
     *  可以指定占位符參數(shù)的位置
     *      ? 索引的方式,指定此占位的取值來源
     */
    @Query(value = "from Customer where custName = ?2 and custId = ?1")
    public Customer findCustNameAndId(Long id,String name);

    /**
     * 使用jpql完成更新操作
     *      案例 : 根據(jù)id更新,客戶的名稱
     *          更新4號客戶的名稱怠堪,將名稱改為“黑馬程序員”
     *
     *  sql  :update cst_customer set cust_name = ? where cust_id = ?
     *  jpql : update Customer set custName = ? where custId = ?
     *
     *  @Query : 代表的是進(jìn)行查詢
     *      * 聲明此方法是用來進(jìn)行更新操作
     *  @Modifying
     *      * 當(dāng)前執(zhí)行的是一個(gè)更新操作
     *
     */
    @Query(value = " update Customer set custName = ?2 where custId = ?1 ")
    @Modifying
    public void updateCustomer(long custId,String custName);


    /**
     * 使用sql的形式查詢:
     *     查詢?nèi)康目蛻?     *  sql : select * from cst_customer;
     *  Query : 配置sql查詢
     *      value : sql語句
     *      nativeQuery : 查詢方式
     *          true : sql查詢
     *          false:jpql查詢
     *
     */
    //@Query(value = " select * from cst_customer" ,nativeQuery = true)
    @Query(value="select * from cst_customer where cust_name like ?1",nativeQuery = true)
    public List<Object [] > findSql(String name);


    /**
     * 方法名的約定:
     *      findBy : 查詢
     *            對象中的屬性名(首字母大寫) : 查詢的條件
     *            CustName
     *            * 默認(rèn)情況 : 使用 等于的方式查詢
     *                  特殊的查詢方式
     *
     *  findByCustName   --   根據(jù)客戶名稱查詢
     *
     *  再springdataJpa的運(yùn)行階段
     *          會根據(jù)方法名稱進(jìn)行解析  findBy    from  xxx(實(shí)體類)
     *                                      屬性名稱      where  custName =
     *
     *      1.findBy  + 屬性名稱 (根據(jù)屬性名稱進(jìn)行完成匹配的查詢=)
     *      2.findBy  + 屬性名稱 + “查詢方式(Like | isnull)”
     *          findByCustNameLike
     *      3.多條件查詢
     *          findBy + 屬性名 + “查詢方式”   + “多條件的連接符(and|or)”  + 屬性名 + “查詢方式”
     */
    public Customer findByCustName(String custName);


    public List<Customer> findByCustNameLike(String custName);

    //使用客戶名稱模糊匹配和客戶所屬行業(yè)精準(zhǔn)匹配的查詢
    public Customer findByCustNameLikeAndCustIndustry(String custName,String custIndustry);
}


實(shí)體類封裝

/**
 * 1.實(shí)體類和表的映射關(guān)系
 *      @Eitity
 *      @Table
 * 2.類中屬性和表中字段的映射關(guān)系
 *      @Id
 *      @GeneratedValue
 *      @Column
 */
@Entity
@Table(name="cst_customer")
public class Customer {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name="cust_id")
    private Long custId;
    @Column(name="cust_address")
    private String custAddress;
    @Column(name="cust_industry")
    private String custIndustry;
    @Column(name="cust_level")
    private String custLevel;
    @Column(name="cust_name")
    private String custName;
    @Column(name="cust_phone")
    private String custPhone;
    @Column(name="cust_source")
    private String custSource;

    public Long getCustId() {
        return custId;
    }

    public void setCustId(Long custId) {
        this.custId = custId;
    }

    public String getCustAddress() {
        return custAddress;
    }

    public void setCustAddress(String custAddress) {
        this.custAddress = custAddress;
    }

    public String getCustIndustry() {
        return custIndustry;
    }

    public void setCustIndustry(String custIndustry) {
        this.custIndustry = custIndustry;
    }

    public String getCustLevel() {
        return custLevel;
    }

    public void setCustLevel(String custLevel) {
        this.custLevel = custLevel;
    }

    public String getCustName() {
        return custName;
    }

    public void setCustName(String custName) {
        this.custName = custName;
    }

    public String getCustPhone() {
        return custPhone;
    }

    public void setCustPhone(String custPhone) {
        this.custPhone = custPhone;
    }

    public String getCustSource() {
        return custSource;
    }

    public void setCustSource(String custSource) {
        this.custSource = custSource;
    }

    @Override
    public String toString() {
        return "Customer{" +
                "custId=" + custId +
                ", custAddress='" + custAddress + '\'' +
                ", custIndustry='" + custIndustry + '\'' +
                ", custLevel='" + custLevel + '\'' +
                ", custName='" + custName + '\'' +
                ", custPhone='" + custPhone + '\'' +
                ", custSource='" + custSource + '\'' +
                '}';
    }
}

測試類完成

@RunWith(SpringJUnit4ClassRunner.class) //聲明spring提供的單元測試環(huán)境
@ContextConfiguration(locations = "classpath:applicationContext.xml")//指定spring容器的配置信息
public class CustomerDaoTest {
    @Autowired
    private CustomerDao customerDao;

    /**
     * 根據(jù)id查詢
     */
    @Test
    public void testFindOne() {
        Customer customer = customerDao.findOne(2l);
        System.out.println(customer);
    }

    /**
     * save : 保存或者更新
     *      根據(jù)傳遞的對象是否存在主鍵id,
     *      如果沒有id主鍵屬性:保存
     *      存在id主鍵屬性名眉,根據(jù)id查詢數(shù)據(jù)粟矿,更新數(shù)據(jù)
     */
    @Test
    public void testSave() {
        Customer customer  = new Customer();
        customer.setCustName("黑馬程序員");
        customer.setCustLevel("vip");
        customer.setCustIndustry("it教育");
        customerDao.save(customer);

    }

    @Test
    public void testUpdate() {
        Customer customer  = new Customer();
        customer.setCustId(4l);
        customer.setCustName("黑馬程序員很厲害");
        customerDao.save(customer);
    }

    @Test
    public void testDelete () {
        customerDao.delete(3l);
    }


    /**
     * 查詢所有
     */
    @Test
    public void testFindAll() {
        List<Customer> list = customerDao.findAll();
        for(Customer customer : list) {
            System.out.println(customer);
        }
    }

    /**
     * 測試統(tǒng)計(jì)查詢:查詢客戶的總數(shù)量
     *      count:統(tǒng)計(jì)總條數(shù)
     */
    @Test
    public void testCount() {
        long count = customerDao.count();//查詢?nèi)康目蛻魯?shù)量
        System.out.println(count);
    }

    /**
     * 測試:判斷id為4的客戶是否存在
     *      1. 可以查詢以下id為4的客戶
     *          如果值為空,代表不存在损拢,如果不為空陌粹,代表存在
     *      2. 判斷數(shù)據(jù)庫中id為4的客戶的數(shù)量
     *          如果數(shù)量為0,代表不存在福压,如果大于0掏秩,代表存在
     */
    @Test
    public void  testExists() {
        boolean exists = customerDao.exists(4l);
        System.out.println("id為4的客戶 是否存在:"+exists);
    }


    /**
     * 根據(jù)id從數(shù)據(jù)庫查詢
     *      @Transactional : 保證getOne正常運(yùn)行
     *
     *  findOne:
     *      em.find()           :立即加載
     *  getOne:
     *      em.getReference     :延遲加載
     *      * 返回的是一個(gè)客戶的動(dòng)態(tài)代理對象
     *      * 什么時(shí)候用或舞,什么時(shí)候查詢
     */
    @Test
    @Transactional
    public void  testGetOne() {
        Customer customer = customerDao.getOne(4l);
        System.out.println(customer);
    }

}

SpringDataJPA原理圖片分析

源碼分析

描述: springDataJpa的運(yùn)行過程和原理剖析
1.通過JdkDynamicAopProxy的invoke方法創(chuàng)建了一個(gè)動(dòng)態(tài)代理對象
2.SimpleJpaRepository當(dāng)中封裝了JPA的操作(借助JPA的api完成數(shù)據(jù)庫的CRUD)
3.通過hibernate完成數(shù)據(jù)庫操作(封裝了jdbc)

i.借助接口中的定義好的方法完成查詢
findOne(id):根據(jù)id查詢
ii.jpql的查詢方式
jpql : jpa query language (jpq查詢語言)
特點(diǎn):語法或關(guān)鍵字和sql語句類似
查詢的是類和類中的屬性

    * 需要將JPQL語句配置到接口方法上
        1.特有的查詢:需要在dao接口上配置方法
        2.在新添加的方法上,使用注解的形式配置jpql查詢語句
        3.注解 : @Query

iii.sql語句的查詢
        1.特有的查詢:需要在dao接口上配置方法
        2.在新添加的方法上蒙幻,使用注解的形式配置sql查詢語句
        3.注解 : @Query
            value :jpql語句 | sql語句
            nativeQuery :false(使用jpql查詢) | true(使用本地查詢:sql查詢)
                是否使用本地查詢
                
iiii.方法名稱規(guī)則查詢
    *是對jpql查詢映凳,更加深入一層的封裝
    *我們只需要按照SpringDataJpa提供的方法名稱規(guī)則定義方法,不需要再配置jpql語句邮破,完成查詢
    *
        findBy開頭:   代表查詢
            對象中屬性名稱(首字母大寫)
        *含義:根據(jù)屬性名稱進(jìn)行查詢

延遲加載和立即加載

em.find() :立即加載
getOne:
* em.getReference :延遲加載
* * 返回的是一個(gè)客戶的動(dòng)態(tài)代理對象
* * 什么時(shí)候用诈豌,什么時(shí)候查詢

/**
     * 根據(jù)id從數(shù)據(jù)庫查詢
     *      @Transactional : 保證getOne正常運(yùn)行
     *
     *  findOne:
     *      em.find()           :立即加載
     *  getOne:
     *      em.getReference     :延遲加載
     *      * 返回的是一個(gè)客戶的動(dòng)態(tài)代理對象
     *      * 什么時(shí)候用,什么時(shí)候查詢
     */
    @Test
    @Transactional
    public void  testGetOne() {
        Customer customer = customerDao.getOne(4l);
        System.out.println(customer);
    }



注意2:測試jpql的更新操作

1 需要增加Transactional 添加事務(wù)支持
2 需要 設(shè)置自動(dòng)提交 默認(rèn)會自動(dòng)回滾

    /**
     * 測試jpql的更新操作
     *  * springDataJpa中使用jpql完成 更新/刪除操作
     *         * 需要手動(dòng)添加事務(wù)的支持
     *         * 默認(rèn)會執(zhí)行結(jié)束之后抒和,回滾事務(wù)
     *   @Rollback : 設(shè)置是否自動(dòng)回滾
     *          false | true
     */
    @Test
    @Transactional //添加事務(wù)的支持
    @Rollback(value = false)
    public void testUpdateCustomer() {
        customerDao.updateCustomer(4l,"黑馬程序員");
    }
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末矫渔,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子摧莽,更是在濱河造成了極大的恐慌庙洼,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,907評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件镊辕,死亡現(xiàn)場離奇詭異油够,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)征懈,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,987評論 3 395
  • 文/潘曉璐 我一進(jìn)店門石咬,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人受裹,你說我怎么就攤上這事碌补÷彩” “怎么了棉饶?”我有些...
    開封第一講書人閱讀 164,298評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長镇匀。 經(jīng)常有香客問我照藻,道長,這世上最難降的妖魔是什么汗侵? 我笑而不...
    開封第一講書人閱讀 58,586評論 1 293
  • 正文 為了忘掉前任幸缕,我火速辦了婚禮,結(jié)果婚禮上晰韵,老公的妹妹穿的比我還像新娘发乔。我一直安慰自己,他們只是感情好雪猪,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,633評論 6 392
  • 文/花漫 我一把揭開白布栏尚。 她就那樣靜靜地躺著,像睡著了一般只恨。 火紅的嫁衣襯著肌膚如雪译仗。 梳的紋絲不亂的頭發(fā)上抬虽,一...
    開封第一講書人閱讀 51,488評論 1 302
  • 那天,我揣著相機(jī)與錄音纵菌,去河邊找鬼阐污。 笑死,一個(gè)胖子當(dāng)著我的面吹牛咱圆,可吹牛的內(nèi)容都是我干的笛辟。 我是一名探鬼主播,決...
    沈念sama閱讀 40,275評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼闷堡,長吁一口氣:“原來是場噩夢啊……” “哼隘膘!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起杠览,我...
    開封第一講書人閱讀 39,176評論 0 276
  • 序言:老撾萬榮一對情侶失蹤弯菊,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后踱阿,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體管钳,經(jīng)...
    沈念sama閱讀 45,619評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,819評論 3 336
  • 正文 我和宋清朗相戀三年软舌,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了才漆。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,932評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡佛点,死狀恐怖醇滥,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情超营,我是刑警寧澤鸳玩,帶...
    沈念sama閱讀 35,655評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站演闭,受9級特大地震影響不跟,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜米碰,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,265評論 3 329
  • 文/蒙蒙 一窝革、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧吕座,春花似錦虐译、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,871評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春拴泌,著一層夾襖步出監(jiān)牢的瞬間魏身,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,994評論 1 269
  • 我被黑心中介騙來泰國打工蚪腐, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留箭昵,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,095評論 3 370
  • 正文 我出身青樓回季,卻偏偏與公主長得像家制,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子泡一,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,884評論 2 354

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