美文网首页
SpringDataJPA分析

SpringDataJPA分析

作者: high一马平川 | 来源:发表于2021-03-01 14:57 被阅读0次
    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.创建entityManagerFactory对象交给spring容器管理-->
        <bean id="entityManagerFactoty" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
            <property name="dataSource" ref="dataSource" />
            <!--配置的扫描的包(实体类所在的包) -->
            <property name="packagesToScan" value="cn.itcast.domain" />
            <!-- jpa的实现厂家 -->
            <property name="persistenceProvider">
                <bean class="org.hibernate.jpa.HibernatePersistenceProvider"/>
            </property>
    
            <!--jpa的供应商适配器 -->
            <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.MySQLDialect" />
                    <!--是否显示sql -->
                    <property name="showSql" value="true" />
                </bean>
            </property>
    
            <!--jpa的方言 :高级的特性 -->
            <property name="jpaDialect" >
                <bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
            </property>
    
        </bean>
    
        <!--2.创建数据库连接池 -->
        <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.配置事务管理器 -->
        <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.声明式事务 -->
    
        <!-- 6. 配置包扫描-->
        <context:component-scan base-package="cn.itcast" ></context:component-scan>
    </beans>
    
    

    DAO层封装

    /**
     * 符合SpringDataJpa的dao层接口规范
     *      JpaRepository<操作的实体类类型,实体类中主键属性的类型>
     *          * 封装了基本CRUD操作
     *      JpaSpecificationExecutor<操作的实体类类型>
     *          * 封装了复杂查询(分页)
     */
    public interface CustomerDao extends JpaRepository<Customer,Long> ,JpaSpecificationExecutor<Customer> {
    
        /**
         * 案例:根据客户名称查询客户
         *      使用jpql的形式查询
         *  jpql:from Customer where custName = ?
         *
         *  配置jpql语句,使用的@Query注解
         */
        @Query(value="from Customer where custName = ?")
        public Customer findJpql(String custName);
    
    
        /**
         * 案例:根据客户名称和客户id查询客户
         *      jpql: from Customer where custName = ? and custId = ?
         *
         *  对于多个占位符参数
         *      赋值的时候,默认的情况下,占位符的位置需要和方法参数中的位置保持一致
         *
         *  可以指定占位符参数的位置
         *      ? 索引的方式,指定此占位的取值来源
         */
        @Query(value = "from Customer where custName = ?2 and custId = ?1")
        public Customer findCustNameAndId(Long id,String name);
    
        /**
         * 使用jpql完成更新操作
         *      案例 : 根据id更新,客户的名称
         *          更新4号客户的名称,将名称改为“黑马程序员”
         *
         *  sql  :update cst_customer set cust_name = ? where cust_id = ?
         *  jpql : update Customer set custName = ? where custId = ?
         *
         *  @Query : 代表的是进行查询
         *      * 声明此方法是用来进行更新操作
         *  @Modifying
         *      * 当前执行的是一个更新操作
         *
         */
        @Query(value = " update Customer set custName = ?2 where custId = ?1 ")
        @Modifying
        public void updateCustomer(long custId,String custName);
    
    
        /**
         * 使用sql的形式查询:
         *     查询全部的客户
         *  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
         *            * 默认情况 : 使用 等于的方式查询
         *                  特殊的查询方式
         *
         *  findByCustName   --   根据客户名称查询
         *
         *  再springdataJpa的运行阶段
         *          会根据方法名称进行解析  findBy    from  xxx(实体类)
         *                                      属性名称      where  custName =
         *
         *      1.findBy  + 属性名称 (根据属性名称进行完成匹配的查询=)
         *      2.findBy  + 属性名称 + “查询方式(Like | isnull)”
         *          findByCustNameLike
         *      3.多条件查询
         *          findBy + 属性名 + “查询方式”   + “多条件的连接符(and|or)”  + 属性名 + “查询方式”
         */
        public Customer findByCustName(String custName);
    
    
        public List<Customer> findByCustNameLike(String custName);
    
        //使用客户名称模糊匹配和客户所属行业精准匹配的查询
        public Customer findByCustNameLikeAndCustIndustry(String custName,String custIndustry);
    }
    
    
    

    实体类封装

    /**
     * 1.实体类和表的映射关系
     *      @Eitity
     *      @Table
     * 2.类中属性和表中字段的映射关系
     *      @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提供的单元测试环境
    @ContextConfiguration(locations = "classpath:applicationContext.xml")//指定spring容器的配置信息
    public class CustomerDaoTest {
        @Autowired
        private CustomerDao customerDao;
    
        /**
         * 根据id查询
         */
        @Test
        public void testFindOne() {
            Customer customer = customerDao.findOne(2l);
            System.out.println(customer);
        }
    
        /**
         * save : 保存或者更新
         *      根据传递的对象是否存在主键id,
         *      如果没有id主键属性:保存
         *      存在id主键属性,根据id查询数据,更新数据
         */
        @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);
            }
        }
    
        /**
         * 测试统计查询:查询客户的总数量
         *      count:统计总条数
         */
        @Test
        public void testCount() {
            long count = customerDao.count();//查询全部的客户数量
            System.out.println(count);
        }
    
        /**
         * 测试:判断id为4的客户是否存在
         *      1. 可以查询以下id为4的客户
         *          如果值为空,代表不存在,如果不为空,代表存在
         *      2. 判断数据库中id为4的客户的数量
         *          如果数量为0,代表不存在,如果大于0,代表存在
         */
        @Test
        public void  testExists() {
            boolean exists = customerDao.exists(4l);
            System.out.println("id为4的客户 是否存在:"+exists);
        }
    
    
        /**
         * 根据id从数据库查询
         *      @Transactional : 保证getOne正常运行
         *
         *  findOne:
         *      em.find()           :立即加载
         *  getOne:
         *      em.getReference     :延迟加载
         *      * 返回的是一个客户的动态代理对象
         *      * 什么时候用,什么时候查询
         */
        @Test
        @Transactional
        public void  testGetOne() {
            Customer customer = customerDao.getOne(4l);
            System.out.println(customer);
        }
    
    }
    

    SpringDataJPA原理图片分析

    源码分析

    描述: springDataJpa的运行过程和原理剖析
    1.通过JdkDynamicAopProxy的invoke方法创建了一个动态代理对象
    2.SimpleJpaRepository当中封装了JPA的操作(借助JPA的api完成数据库的CRUD)
    3.通过hibernate完成数据库操作(封装了jdbc)

    i.借助接口中的定义好的方法完成查询
    findOne(id):根据id查询
    ii.jpql的查询方式
    jpql : jpa query language (jpq查询语言)
    特点:语法或关键字和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.方法名称规则查询
        *是对jpql查询,更加深入一层的封装
        *我们只需要按照SpringDataJpa提供的方法名称规则定义方法,不需要再配置jpql语句,完成查询
        *
            findBy开头:   代表查询
                对象中属性名称(首字母大写)
            *含义:根据属性名称进行查询
    

    延迟加载和立即加载

    em.find() :立即加载
    getOne:
    * em.getReference :延迟加载
    * * 返回的是一个客户的动态代理对象
    * * 什么时候用,什么时候查询

    /**
         * 根据id从数据库查询
         *      @Transactional : 保证getOne正常运行
         *
         *  findOne:
         *      em.find()           :立即加载
         *  getOne:
         *      em.getReference     :延迟加载
         *      * 返回的是一个客户的动态代理对象
         *      * 什么时候用,什么时候查询
         */
        @Test
        @Transactional
        public void  testGetOne() {
            Customer customer = customerDao.getOne(4l);
            System.out.println(customer);
        }
    
    
    
    

    注意2:测试jpql的更新操作

    1 需要增加Transactional 添加事务支持
    2 需要 设置自动提交 默认会自动回滚

        /**
         * 测试jpql的更新操作
         *  * springDataJpa中使用jpql完成 更新/删除操作
         *         * 需要手动添加事务的支持
         *         * 默认会执行结束之后,回滚事务
         *   @Rollback : 设置是否自动回滚
         *          false | true
         */
        @Test
        @Transactional //添加事务的支持
        @Rollback(value = false)
        public void testUpdateCustomer() {
            customerDao.updateCustomer(4l,"黑马程序员");
        }
    

    相关文章

      网友评论

          本文标题:SpringDataJPA分析

          本文链接:https://www.haomeiwen.com/subject/bvkufltx.html