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();
    
  • 相关阅读:
    URAL 1998 The old Padawan 二分
    URAL 1997 Those are not the droids you're looking for 二分图最大匹配
    URAL 1995 Illegal spices 贪心构造
    URAL 1993 This cheeseburger you don't need 模拟题
    URAL 1992 CVS
    URAL 1991 The battle near the swamp 水题
    Codeforces Beta Round #92 (Div. 1 Only) A. Prime Permutation 暴力
    Codeforces Beta Round #7 D. Palindrome Degree hash
    Codeforces Beta Round #7 C. Line Exgcd
    Codeforces Beta Round #7 B. Memory Manager 模拟题
  • 原文地址:https://www.cnblogs.com/loveer/p/11379814.html
Copyright © 2011-2022 走看看