zoukankan      html  css  js  c++  java
  • Spring Data JPA

    前言

    spring Data项目的目的是为了简化构建基于 Spring 框架应用的数据访问计数,使数据库访问变得方便快捷。包括非关系数据库Map-Reduce框架、云数据服务等等,另外也包含对关系数据库的访问支持。

    JPA诞生的缘由是为了整合第三方ORM框架,建立一种标准的方式
    SpringDataJPA是一个JPA数据访问抽象,需要第三方实现,有各种实现JPA的提供者。
    
    • Spring Data JPA是Spring提供的持久层的解决方案
    • Spring Data JPA其实就是Spring对JPA操作的封装(entiyManager)
    • 使用Spring Data JPA有两个条件:
      • Spring整合JPA
      • 需要有一个JPA的实现框架

    运行过程与原理剖析

    Spring Data JPA 封装了 JPA 规范操作逻辑,Hibernate实现了JPA规范,并且封装了jdbc操作逻辑,可以进行数据库CRUD。我们使用Spring Data JPA接口就能更加方便的操作数据库。

    1. 我们需要做的是创建一个接口:UserDao(extends JpaRepository<User, Long>, JpaSpecificationExecutor<User>)
    2. Spring 通过 JdkDynamicAopProxy 的 invoke 方法创建了一个动态代理:SimpleJpaRepository
    3. SimpleJpaRepository封装了JPA的操作(借助JPA的api完成数据库的crud)
    4. 通过Hibernate完成数据库操作(封装了jdbc操作)
    

    配置文件(application.xml)

    <?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">
    
        <!--加载配置文件与要扫描的包-->
        <context:property-placeholder location="classpath:properties"></context:property-placeholder>
        <context:component-scan base-package="jpa"></context:component-scan>
    
    
        <!--数据库连接池-->
        <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
            <property name="jdbcUrl" value="${jdbcUrl}"></property>
            <property name="driverClass" value="${driverClass}"></property>
            <property name="user" value="${user}"></property>
            <property name="password" value="${password}"></property>
        </bean>
    
    
        <!-- 创建entityManagerFactory对象交给spring容器管理 -->
        <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
            <!--数据源-->
            <property name="dataSource" ref="dataSource"></property>
    
            <!--配置实体类扫描的包-->
            <property name="packagesToScan" value="jpa.entity"></property>
    
            <!--配置jpa实现-->
            <property name="persistenceProvider">
                <bean class="org.hibernate.jpa.HibernatePersistenceProvider"></bean>
            </property>
    
            <!--jpa的供应商适配器 -->
            <property name="jpaVendorAdapter">
                <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
                    <!--配置是否自动创建数据库表-->
                    <property name="generateDdl" value="true"></property>
    
                    <!--数据库方言:支持的特有语法 -->
                    <property name="databasePlatform" value="org.hibernate.dialect.MySQLDialect"></property>
    
                    <property name="database" value="MYSQL"></property>
                    <property name="showSql" value="true"></property>
                </bean>
            </property>
    
            <!--jpa方言-->
            <property name="jpaDialect">
                <bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect"></bean>
            </property>
    
            <!--注入jpa的配置信息
                加载jpa的基本配置信息和jpa实现方式(hibernate)的配置信息
                hibernate.hbm2ddl.auto : 自动创建数据库表
                                create : 每次都会重新创建数据库表
                                update : 有表不会重新创建,没有表会重新创建表
            -->
            <property name="jpaProperties">
                <props>
                    <prop key="hibernate.hbm2ddl.auto">update</prop>
                </props>
            </property>
    
        </bean>
    
    
        <!--事务管理器-->
        <bean id="tm" class="org.springframework.orm.jpa.JpaTransactionManager">
            <property name="entityManagerFactory" ref="entityManagerFactory"></property>
        </bean>
    
    
        <!--声明式事务-->
        <tx:annotation-driven transaction-manager="tm"></tx:annotation-driven>
    
    
        <!--整合spring data jpa-->
        <jpa:repositories base-package="jpa.dao"
                          transaction-manager-ref="tm"
                          entity-manager-factory-ref="entityManagerFactory">
        </jpa:repositories>
    
    </beans>
    

    基本查询

    UserDao extends JpaRepository<User, Long>
    
        /**
         * 基本CRUD操作
         * save(user) : 保存或者更新
         *        根据传递的对象是否存在主键id,
         *        如果没有id主键属性:保存
         *        存在id主键属性,根据id查询数据,更新数据
         *
         * delete(id)
         *        根据id删除:调用delete(id)方法
         *
         * findOne(id)
         *        根据id查询:调用findOne(id)方法
         *
         * getOne(id)
         *       根据id查询:调用getOne(id)方法  ,延迟加载(需要@Transactional)
         *
         * count()
         *       查询全部客户数量
         */
    

    复杂查询

    /**
     * 符合SpringDataJpa的dao层接口规范:
     * JpaRepository<操作的实体类类型,实体类中主键属性的类型>
     *      封装了基本CRUD操作
     * JpaSpecificationExecutor<操作的实体类类型>
     *      封装了复杂查询(分页)
     */
    public interface UserDao extends JpaRepository<User, Long>, JpaSpecificationExecutor<User> {
    
    
        /**
         * 使用JPQL的方式查询
         */
        @Query(value = "from User  where userId = ? ")
        public User findById(long id);
    
        /**
         * 通过使用 @Query 来执行一个更新操作,
         * 为此,我们需要在使用 @Query 的同时,
         * 用 @Modifying 来将该操作标识为修改查询,这样框架最终会生成一个更新的操作,而非查询
         */
        @Query(value = "update User  set userName = ?2 where userId = ?1 ")
        @Modifying
        public void update(long id,String name);
    
        /**
         * sql语句查询
         */
        @Query(value = "select * from user",nativeQuery = true)
        public List<User> findAll();
    
        /**
         * 方法名查询:findBy + 对象中的属性名称(首字母大写)
         */
        User findByUserName(String userName);
    
        /**
         * 方法名模糊查询查询:findBy + 对象中的属性名称 + Like(传递参数:"ld%")
         */
        List<User> findByUserNameLike(String userName);
    
        /**
         * 多条件连接(And|Or)查询:findBy + 对象中的属性名称 + Like + And + 对象中的属性名称
         */
        List<User> findByUserNameLikeAndUserAge(String a,Integer b );
    }
    

    动态查询

    Specification:动态查询
    
    JpaSpecificationExecutor 接口的方法:
    /**
     * 根据条件查询一个对象
     *  	T findOne(Specification<T> spec);
     * 根据条件查询集合
     *  	List<T> findAll(Specification<T> spec);
     * 根据条件分页查询
     *  	Page<T> findAll(Specification<T> spec, Pageable pageable);
     * 排序查询查询
     *  	List<T> findAll(Specification<T> spec, Sort sort);
     * 统计查询
     *  	long count(Specification<T> spec);
     *
     * Root接口  ,代表查询的根对象,可以通过root获取实体类中的属性
     * query	:代表一个顶层查询对象,用来自定义查询
     * cb		:用来构建查询,此对象里有很多条件方法
     *
     * public Predicate toPredicate(Root<T> root,CriteriaQuery<?> query,CriteriaBuilder cb);
     */
    
    public class SpecificationJpaTest {
    
        @Autowired
        private UserDao dao;
    
        public  void findOne(){
            Specification<User> cu = new Specification<>() {
                public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                    /**
                     * 获取比较的属性:
                     *      1.Path<Object> userName = root.get("userName");
                     *      2.构造查询条件  :
                     *              select * from user where user_name = '传智播客';
                     *
                     *      第一个参数:需要比较的属性(path对象)
                     *      第二个参数:当前需要比较的取值
                     *
                     */
                    return cb.equal(root.<String>get("userName"),"传智播客");
                }
            };
            User one = dao.findOne(cu);
        }
    
        public  void findByPage(){
            PageRequest pageRequest = new PageRequest(0, 2);
            Specification<User> cu = new Specification<User>() {
                public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                    /**
                     * 构造查询
                     *
                     * 1.构造名称的精准匹配查询(第一个参数,path(属性),第二个参数,属性的取值)
                     *     Predicate p1 = cb.equal(userName, "传智播客");
                     *
                     * 2.构造年龄的精准匹配查询
                     *     Predicate p2 = cb.equal(userAge, 12);
                     *
                     * 3.将多个查询条件组合到一起:组合(满足条件一并且满足条件二:与关系cb.and(),满足条件一或满足条件二即可:或关系cb.or())
                     *     Predicate predicate = cb.and(p1, p2);
                     *     return predicate;
                     */
                    return cb.like(root.<String>get("userName"),"传智%");
                }
            };
            Page<User> one =dao.findAll(cu,pageRequest);
        }
    
        /**
         * 添加排序:
         *         创建排序对象,需要调用构造方法实例化sort对象
         *         第一个参数:排序的顺序(倒序,正序)
         *            Sort.Direction.DESC        :倒序
         *            Sort.Direction.ASC         :升序
         *
         *         第二个参数:排序的属性名称
         *              Sort sort = new Sort(Sort.Direction.DESC,"userId");
         *              List<User> users = dao.findAll(spec, sort);
         */
    
    }
    

    对象导航查询(Spring Data JPA )

    查询一个对象的同时,通过此对象查询它的关联对象(默认懒加载)(需要在实体对象中配置外键(多表关系)@OneToMany)

    Boss boss = bossDao.getOne(1l);
    Set<Customer> customers = boss.getCustomers();
    
  • 相关阅读:
    从统计学statistics的观点看概率分布
    JavaScript中getBoundingClientRect()方法详解
    insertRule()与addRule()创建规则
    Canvas 数学、物理、动画学习笔记一
    【超级干货】手机移动端WEB资源整合:转载
    JavaScript性能优化技巧之函数节流
    @font-face的用法
    Modernizr——为HTML5和CSS3而生!
    url、href、src 详解
    认识cookie与session的区别与应用
  • 原文地址:https://www.cnblogs.com/loveer/p/11379814.html
Copyright © 2011-2022 走看看