zoukankan      html  css  js  c++  java
  • SpringData

    Spring  Data概述

    它是spring的一个子项目,用户简化数据库访问,支持NOSQL和关系型数据库,其主要目标是帮助数据库访问变的简单

    Spring Data支持的NoSQL存储:

    MongoDB(文档数据库)

    Redis(键值存储)

    HBase(列族数据库)

    Spring Data项目支持的关系数据存储技术

    JDBC

    JPA

     

    JPA  Spring Data概述

    其致力于减少数据访问层(DAO)的开发量,唯一需要做的就是声明持久层的接口,其他的都由Spring Data完成,根据符合规范的名字来确定方法需要怎样的逻辑实现

     

    入门程序

    1、在spring中整合JPA

     

        <!-- 配置自动扫描的包 -->
        <context:component-scan base-package="springdata"></context:component-scan>
    
        <!-- 1. 配置数据源 -->
        <context:property-placeholder location="classpath:db.properties"/>
    
        <bean id="dataSource"
            class="com.mchange.v2.c3p0.ComboPooledDataSource">
            <property name="user" value="${jdbc.user}"></property>
            <property name="password" value="${jdbc.password}"></property>    
            <property name="driverClass" value="${jdbc.driverClass}"></property>
            <property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property>
            
            <!-- 配置其他属性 -->
        </bean>
    
        <!-- 2. 配置 JPA 的 EntityManagerFactory -->
        <bean id="entityManagerFactory" 
            class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
            <property name="dataSource" ref="dataSource"></property>
            <property name="jpaVendorAdapter">
                <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"></bean>
            </property>
            <property name="packagesToScan" value="springdata"></property>
            <property name="jpaProperties">
                <props>
                    <!-- 二级缓存相关 -->
                    <!--  
                    <prop key="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</prop>
                    <prop key="net.sf.ehcache.configurationResourceName">ehcache-hibernate.xml</prop>
                    -->
                    <!-- 生成的数据表的列的映射策略 -->
                    <prop key="hibernate.ejb.naming_strategy">org.hibernate.cfg.ImprovedNamingStrategy</prop>
                    <!-- hibernate 基本属性 -->
                    <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</prop>
                    <prop key="hibernate.show_sql">true</prop>
                    <prop key="hibernate.format_sql">true</prop>
                    <prop key="hibernate.hbm2ddl.auto">update</prop>
                </props>
            </property>
        </bean>
    
        <!-- 3. 配置事务管理器 -->
        <bean id="transactionManager"
            class="org.springframework.orm.jpa.JpaTransactionManager">
            <property name="entityManagerFactory" ref="entityManagerFactory"></property>    
        </bean>
    
        <!-- 4. 配置支持注解的事务 -->
        <tx:annotation-driven transaction-manager="transactionManager"/>

    2、在Spring中配置Spring Data

    <!-- 5. 配置 SpringData -->
        <!-- 加入  jpa 的命名空间 -->
        <!-- base-package: 扫描 Repository Bean 所在的 package -->
        <jpa:repositories base-package="springdata"
            entity-manager-factory-ref="entityManagerFactory"></jpa:repositories>

    3、声明持久层的接口,该接口继承Repsoitory接口

    public interface PersonRepository extends Repository<Person, Integer> {
    
        public List<Person> getByLastName(String name);
    }

    4、在接口中声明需要的方法

    private ApplicationContext ac = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");   
        
        @Test
        public void findByName() {
            PersonRepository repository = ac.getBean(PersonRepository.class);
            List<Person> list = repository.getByLastName("AA");
            System.out.println(list);
        }
    /**
     * 1. Repository 是一个空接口. 即是一个标记接口
     * 2. 若我们定义的接口继承了 Repository, 则该接口会被 IOC 容器识别为一个 Repository Bean.
     * 纳入到 IOC 容器中. 进而可以在该接口中定义满足一定规范的方法. 
     * 
     * 3. 实际上, 也可以通过 @RepositoryDefinition 注解来替代继承 Repository 接口
     @RepositoryDefinition(domainClass=Person.class,idClass=Integer.class)
     */
    /**
     * 在 Repository 子接口中声明方法
     * 1. 不是随便声明的. 而需要符合一定的规范
     * 2. 查询方法以 find | read | get 开头
     * 3. 涉及条件查询时,条件的属性用条件关键字连接
     * 4. 要注意的是:条件属性以首字母大写。
     * 5. 支持属性的级联查询. 若当前类有符合条件的属性, 则优先使用, 而不使用级联属性. 
     * 若需要使用级联属性, 则属性之间使用 _ 进行连接. 
     */

     

     

    //根据 lastName 来获取对应的 Person
        Person getByLastName(String lastName);
        
        //WHERE lastName LIKE ?% AND id < ?
        List<Person> getByLastNameStartingWithAndIdLessThan(String lastName, Integer id);
        
        //WHERE lastName LIKE %? AND id < ?
        List<Person> getByLastNameEndingWithAndIdLessThan(String lastName, Integer id);
        
        //WHERE email IN (?, ?, ?) OR birth < ?
        List<Person> getByEmailInAndBirthLessThan(List<String> emails, Date birth);
        
        //WHERE a.id > ?
        List<Person> getByAddress_IdGreaterThan(Integer id);

    使用Query注解自定义查询语句可以更加灵活

    //使用 @Query 注解可以自定义 JPQL 语句以实现更灵活的查询
        @Query("SELECT p FROM Person p WHERE p.id = (SELECT max(p2.id) FROM Person p2)")
        Person getMaxIdPerson();
    
    
    //为 @Query 注解传递参数的方式1: 使用占位符. 
        @Query("SELECT p FROM Person p WHERE p.lastName = ?1 AND p.email = ?2")
        List<Person> testQueryAnnotationParams1(String lastName, String email);
        
        //为 @Query 注解传递参数的方式1: 命名参数的方式. 
        @Query("SELECT p FROM Person p WHERE p.lastName = :lastName AND p.email = :email")
        List<Person> testQueryAnnotationParams2(@Param("email") String email, @Param("lastName") String lastName);
    
    //SpringData 允许在占位符上添加 %%. 
        @Query("SELECT p FROM Person p WHERE p.lastName LIKE %?1% OR p.email LIKE %?2%")
        List<Person> testQueryAnnotationLikeParam(String lastName, String email);
        
        //SpringData 允许在占位符上添加 %%. 
        @Query("SELECT p FROM Person p WHERE p.lastName LIKE %:lastName% OR p.email LIKE %:email%")
        List<Person> testQueryAnnotationLikeParam2(@Param("email") String email, @Param("lastName") String lastName);
        
        //设置 nativeQuery=true 即可以使用原生的 SQL 查询
        @Query(value="SELECT count(id) FROM jpa_persons", nativeQuery=true)
        long getTotalCount();
        
        //可以通过自定义的 JPQL 完成 UPDATE 和 DELETE 操作. 注意: JPQL 不支持使用 INSERT
        //在 @Query 注解中编写 JPQL 语句, 但必须使用 @Modifying 进行修饰. 以通知 SpringData, 这是一个 UPDATE 或 DELETE 操作
        //UPDATE 或 DELETE 操作需要使用事务, 此时需要定义 Service 层. 在 Service 层的方法上添加事务操作. 
        //默认情况下, SpringData 的每个方法上有事务, 但都是一个只读事务. 他们不能完成修改操作!
        @Modifying
        @Query("UPDATE Person p SET p.email = :email WHERE id = :id")
        void updatePersonEmail(@Param("id") Integer id, @Param("email") String email);
    @Test
        public void crudReposiory(){
            List<Person> persons = new ArrayList<>();
            
            for(int i = 'a'; i <= 'z'; i++){
                Person person = new Person();
                person.setAddressId(i + 1);
                person.setBirth(new Date());
                person.setEmail((char)i + "" + (char)i + "@atguigu.com");
                person.setLastName((char)i + "" + (char)i);
                
                persons.add(person);
            }
            
            personService.savePersons(persons);
        }
    @Test
        public void pagingAndSortingRespository(){
            //pageNo 从 0 开始. 
            int pageNo = 6 - 1;
            int pageSize = 5;
            //Pageable 接口通常使用的其 PageRequest 实现类. 其中封装了需要分页的信息
            //排序相关的. Sort 封装了排序的信息
            //Order 是具体针对于某一个属性进行升序还是降序. 
            Order order1 = new Order(Direction.DESC, "id");
            Order order2 = new Order(Direction.ASC, "email");
            Sort sort = new Sort(order1, order2);
            
            PageRequest pageable = new PageRequest(pageNo, pageSize, sort);
            Page<Person> page = personRepsotory.findAll(pageable);
            
            System.out.println("总记录数: " + page.getTotalElements());
            System.out.println("当前第几页: " + (page.getNumber() + 1));
            System.out.println("总页数: " + page.getTotalPages());
            System.out.println("当前页面的 List: " + page.getContent());
            System.out.println("当前页面的记录数: " + page.getNumberOfElements());
        }
    @Test
        public void jpaRepository(){
            Person person = new Person();
            person.setBirth(new Date());
            person.setEmail("xy@atguigu.com");
            person.setLastName("xyz");
            person.setId(28);
            
            Person person2 = personRepsotory.saveAndFlush(person);
            
            System.out.println(person == person2);   //false
        }
    /**
         * 目标: 实现带查询条件的分页. id > 5 的条件
         * 
         * 调用 JpaSpecificationExecutor 的 Page<T> findAll(Specification<T> spec, Pageable pageable);
         * Specification: 封装了 JPA Criteria 查询的查询条件
         * Pageable: 封装了请求分页的信息: 例如 pageNo, pageSize, Sort
         */
        @Test
        public void jpaSpecificationExecutor(){
            int pageNo = 3 - 1;
            int pageSize = 5;
            PageRequest pageable = new PageRequest(pageNo, pageSize);
            
            //通常使用 Specification 的匿名内部类
            Specification<Person> specification = new Specification<Person>() {
                /**
                 * @param *root: 代表查询的实体类. 
                 * @param query: 可以从中可到 Root 对象, 即告知 JPA Criteria 查询要查询哪一个实体类. 还可以
                 * 来添加查询条件, 还可以结合 EntityManager 对象得到最终查询的 TypedQuery 对象. 
                 * @param *cb: CriteriaBuilder 对象. 用于创建 Criteria 相关对象的工厂. 当然可以从中获取到 Predicate 对象
                 * @return: *Predicate 类型, 代表一个查询条件. 
                 */
                @Override
                public Predicate toPredicate(Root<Person> root,
                        CriteriaQuery<?> query, CriteriaBuilder cb) {
                    Path path = root.get("id");
                    Predicate predicate = cb.gt(path, 5);
                    return predicate;
                }
            };
            
            Page<Person> page = personRepsotory.findAll(specification, pageable);
            
            System.out.println("总记录数: " + page.getTotalElements());
            System.out.println("当前第几页: " + (page.getNumber() + 1));
            System.out.println("总页数: " + page.getTotalPages());
            System.out.println("当前页面的 List: " + page.getContent());
            System.out.println("当前页面的记录数: " + page.getNumberOfElements());
        }
    public class PersonRepsotoryImpl implements PersonDao {
        
        @PersistenceContext
        private EntityManager entityManager;
        
        @Override
        public void test() {
            Person person = entityManager.find(Person.class, 11);
            System.out.println("-->" + person);
        }
    
    }

           

     

     

  • 相关阅读:
    jmeter压测,json提取器的使用
    pycharm安装
    安装numpy+mkl
    Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX AVX2
    windows上安装tensorflow时报错,“DLL load failed: 找不到指定的模块”的解决方式
    mapreduce 设置递归读取输入文件
    设置reduce Task数量
    kafka.common.FailedToSendMessageException: Failed to send messages after 3 tries.
    mahout RecommenderJob 参数含义
    idea 配置日志输出等级debug
  • 原文地址:https://www.cnblogs.com/lzb0803/p/8970796.html
Copyright © 2011-2022 走看看