Spring Data Jpa(三)

Spring Data Jpa介绍

    A、Spring Data JPA 是 Spring 基于 ORM 框架、JPA 规范的基础上封装的套 JPA 应用框架,
       可使开发者用极简的代码即可实现对数据的访问和操作。它提供了包括增删改查等在内的常用功能,
       且易于扩展!学习并使用 Spring Data JPA 可以极大提高开发效率!
    B、Spring Data JPA 简化了 DAO 层的操作,基本上所有 CRUD 都可以依赖于其实现。

1、入门案例

    A、添加依赖:
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-data-jpa</artifactId>
            </dependency>   
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
            </dependency>

    B、添加配置文件:
            # 配置数据库
            spring.datasource.url=jdbc:mysql://localhost:3306/test
            spring.datasource.username=root
            spring.datasource.password=root
            spring.datasource.driver-class-name=com.mysql.jdbc.Driver           
            # 配置 Jpa 相关参数
            spring.jpa.properties.hibernate.hbm2ddl.auto=update 
            spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect
            spring.jpa.show-sql= true
            
            # hibernate.hbm2ddl.auto 参数的作用主要用于:自动创建 | 更新 | 验证数据库表结构,有四个值:
            #       create:每次加载 hibernate 时都会删除上一次的生成的表,然后根据 model 类再重新来生成新表,
            #               哪怕两次没有任何改变也要这样执行,这就是导致数据库表数据丢失的一个重要原因。
            #       create-drop:每次加载 hibernate 时根据 model 类生成表,但是 sessionFactory 关闭,表就自动删除。
            #       update:最常用的属性,第1次加载 hibernate 时根据 model 类会自动建立起表的结构(前提是先建好
            #               数据库),以后加载 hibernate 时根据 model 类自动更新表结构,即使表结构改变了,但表中的行仍
            #               然存在,不会删除以前的行。要注意的是当部署到服务器后,表结构是不会被马上建立起来的,是要等
            #               应用第一次运行起来后才会。
            #       validate:每次加载 hibernate 时,验证创建数据库表结构,只会和数据库中的表进行比较,不会创建新
            #               表,但是会插入新值。
            # dialect:主要是指定生成表名的存储引擎为 InneoDB。
            # show-sql:是否打印出自动生产的 SQL,方便调试的时候查看。

    C、添加实体类和Dao : Entity 中不映射成列的字段得加 @Transient 注解,不加注解也会映射成列       

            @Entity
            public class User implements Serializable {
                @Id
                @GeneratedValue
                private Long id;            
                @Column(nullable = false,unique = true)
                private String userName;            
                @Column(nullable = false)
                private String passWord;            
                @Column(nullable = false, unique = true)
                private String email;           
                @Column(nullable = false)
                private String regTime;

                //省略 getter settet 方法、构造方法
            }

        Dao:
            public interface UserRepository extends JpaRepository<User, Long> {
                User findByUserName(String userName);
                User findByUserNameOrEmail(String username,String email);
            } 

    D、编写测试类 
            @RunWith(SpringRunner.class)
            @SpringBootTest
            public class UserRepositoryTest {
            
                @Resource
                private UserRepository userRepository;
            
                @Test
                public void findByUserName() throws Exception {
            
                    /**
                     * 数据库造数据
                     *  Date date=new Date();
                     *  DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG);
                     *  String formatDate = dateFormat.format(date);
                     *  userRepository.save(new User("aa", "aa123456","[email protected]",formatDate));
                     *  userRepository.save(new User("bb", "bb123456","[email protected]",formatDate));
                     *  userRepository.save(new User("cc", "cc123456","[email protected]",formatDate));
                     */
            
                    Assert.assertEquals(3,userRepository.findAll().size());
            
                    //userRepository.delete(userRepository.findByUserName("aa"));
                }
            
                @Test
                public void findByUserNameOrEmail() throws Exception {
                    Assert.assertEquals("bb",userRepository.findByUserNameOrEmail("bb","[email protected]").getUserName());
                }
            }

2、基本查询分为两种,① Spring Data 默认已经实现 ② 根据查询的方法来自动解析成 SQL。

    A、Spring Data JPA 默认预先生成一些基本的 CURD 的方法,如增、删、改等。
            继承 JpaRepository:
                public interface UserRepository extends JpaRepository<User, Long> {

                }

            使用默认方法:
                @Test
                public void testBaseQuery() {
                    userRepository.findAll();
                    userRepository.findOne(1l);
                    userRepository.save(user);
                    userRepository.delete(user);
                    userRepository.count();
                    userRepository.exists(1l);
                    // ...
                }
    B、自定义的简单查询就是根据方法名来自动生成 SQL,主要的语法是 findXXBy、readAXXBy、queryXXBy、countXXBy、getXXBy 
        后面跟属性名称:
                    User findByUserName(String userName);
        也可加一些关键字 And、Or:
                    User findByUserNameOrEmail(String username, String email);
        修改、删除、统计类似语法:
                    Long deleteById(Long id);
                    Long countByUserName(String userName)
        基本上 SQL 体系中的关键词都可以使用,如 LIKE、IgnoreCase、OrderBy:
                    List<User> findByEmailLike(String email);
                    User findByUserNameIgnoreCase(String userName);  
                    List<User> findByUserNameOrderByEmailDesc(String email);    

3、复杂查询

在实际的开发中需要用到分页、筛选、连表等查询的时候就需要特殊的方法或者自定义 SQL。

    分页查询:
        分页查询在实际使用中非常普遍,Spring Data JPA 已经帮我们实现了分页的功能,在查询的方法中, 
        需要传入参数 Pageable,当查询中有多个参数的时候, Pageable 建议做为最后一个参数传入

        Pageable 是 Spring 封装的分页实现类,使用的时候需要传入页数、每页条数和排序规则。

        @Query("select u from User u")
        Page<User> findALL(Pageable pageable);
        Page<User> findByUserName(String userName,Pageable pageable);
        
        测试
        @Test
        public void testPageQuery(){
            int page=1,size=2;
            Sort sort=new Sort(Sort.Direction.DESC,"id");
            Pageable pageable=new PageRequest(page,size,sort);
            userRepository.findALL(pageable);
            userRepository.findByUserName("aa",pageable);
        }

4、自定义SQL查询

    A、使用 Spring Data 大部分的 SQL 都可以根据方法名定义的方式来实现,如果我们想使用自定义的 
       SQL 来查询,Spring Data 也可以支持
    B、在 SQL 的查询方法上面使用 @Query 注解,如涉及到删除和修改需要加上 @Modifying,也可以
       根据需要添加 @Transactional 对事物的支持,查询超时的设置等。

        @Transactional(timeout = 10)
        @Modifying
        @Query("update User set userName =?1 where id =?2")
        int modifyById(String userName,Long id);
    
        @Transactional
        @Modifying
        @Query("delete from User where id =?1")
        void deleteById(Long id);
    
        @Query("select u from User u where u.email = ?1")
        User findByEmail(String email);

5、多数据源的支持(重点)

    项目开发中,常需要在一个项目中使用多个数据源,因此需要配置 Spring Data JPA 对多数据源的使用,一般分为以下三步:
        a、配置多数据源
        b、不同源的 repository 放入不同包路径
        c、声明不同的包路径下使用不同的数据源、事务支持

    0、实体类所在包 com.kid.domain
        @Entity
        public class User implements Serializable {
        
            @Id
            @GeneratedValue
            private Long id;
            @Column(nullable = false, unique = true)
            private String userName;
            @Column(nullable = false)
            private String passWord;
            @Column(nullable = false, unique = true)
            private String email;
            @Column(nullable = true, unique = true)
            private String nickName;
            @Column(nullable = false)
            private String regTime;
            
            //getter、setter、构造方法省略...
        }

    A、配置两个数据源:
        #primary
        spring.primary.datasource.url=jdbc:mysql://localhost:3306/test1 
        spring.primary.datasource.username=root  
        spring.primary.datasource.password=root  
        spring.primary.datasource.driver-class-name=com.mysql.jdbc.Driver  
        #secondary
        spring.secondary.datasource.url=jdbc:mysql://localhost:3306/test2  
        spring.secondary.datasource.username=root  
        spring.secondary.datasource.password=root  
        spring.secondary.datasource.driver-class-name=com.mysql.jdbc.Driver 
    
    B、读取两个配置源,构建两个数据源:
        com.kid.config 包下:

            @Configuration
            public class DataSourceConfig {
            
                @Bean(name = "primaryDataSource")
                @Qualifier("primaryDataSource")
                @ConfigurationProperties(prefix="spring.primary.datasource")
                public DataSource primaryDataSource() {
                    return DataSourceBuilder.create().build();
                }
            
                @Bean(name = "secondaryDataSource")
                @Qualifier("secondaryDataSource")
                @Primary
                @ConfigurationProperties(prefix="spring.secondary.datasource")
                public DataSource secondaryDataSource() {
                    return DataSourceBuilder.create().build();
                }
            }

    C、将数据源注入到 Factory,配置 repository、domian 的位置,需要设置一个默认的数据源:
        com.kid.config 包下:
            PrimaryConfig:
                @Configuration
                @EnableTransactionManagement
                @EnableJpaRepositories(
                        entityManagerFactoryRef="entityManagerFactoryPrimary",
                        transactionManagerRef="transactionManagerPrimary",
                        basePackages= { "com.kid.repository.test1" })//设置dao(repo)所在位置
                public class PrimaryConfig {
                    
                    @Autowired
                    private JpaProperties jpaProperties;
                
                    @Autowired
                    @Qualifier("primaryDataSource")
                    private DataSource primaryDataSource;
                
                    @Bean(name = "entityManagerPrimary")
                    @Primary
                    public EntityManager entityManager(EntityManagerFactoryBuilder builder) {
                        return entityManagerFactoryPrimary(builder).getObject().createEntityManager();
                    }
                
                
                    @Bean(name = "entityManagerFactoryPrimary")
                    @Primary
                    public LocalContainerEntityManagerFactoryBean entityManagerFactoryPrimary (EntityManagerFactoryBuilder builder) {
                        return builder
                                .dataSource(primaryDataSource)
                                .packages("com.kid.domain") //设置实体类所在位置
                                .persistenceUnit("primaryPersistenceUnit")
                                .properties(getVendorProperties())
                                .build();
                    }
                
                    private Map<String, Object> getVendorProperties() {
                        return jpaProperties.getHibernateProperties(new HibernateSettings() );
                    }
                
                
                    @Bean(name = "transactionManagerPrimary")
                    @Primary
                    PlatformTransactionManager transactionManagerPrimary(EntityManagerFactoryBuilder builder) {
                        return new JpaTransactionManager(entityManagerFactoryPrimary(builder).getObject());
                    }
                }

        SecondaryConfig:
            @Configuration
            @EnableTransactionManagement
            @EnableJpaRepositories(
                    entityManagerFactoryRef="entityManagerFactorySecondary",
                    transactionManagerRef="transactionManagerSecondary",
                    basePackages= { "com.kid.repository.test2" })
            public class SecondaryConfig {
                @Autowired
                private JpaProperties jpaProperties;
            
                @Autowired
                @Qualifier("secondaryDataSource")
                private DataSource secondaryDataSource;
            
                @Bean(name = "entityManagerSecondary")
                public EntityManager entityManager(EntityManagerFactoryBuilder builder) {
                    return entityManagerFactorySecondary(builder).getObject().createEntityManager();
                }
            
                @Bean(name = "entityManagerFactorySecondary")
                public LocalContainerEntityManagerFactoryBean entityManagerFactorySecondary (EntityManagerFactoryBuilder builder) {
                    return builder
                            .dataSource(secondaryDataSource)
                            .properties(getVendorProperties())
                            .packages("com.kid.domain")
                            .persistenceUnit("secondaryPersistenceUnit")
                            .build();
                }
            
                private Map<String, Object> getVendorProperties() {
                    return jpaProperties.getHibernateProperties(new HibernateSettings());
                }
            
                @Bean(name = "transactionManagerSecondary")
                PlatformTransactionManager transactionManagerSecondary(EntityManagerFactoryBuilder builder) {
                    return new JpaTransactionManager(entityManagerFactorySecondary(builder).getObject());
                }
            }


    D、配置Dao
    
        com.kid.repository.test1
            public interface UserTest1Repository extends JpaRepository<User, Long> {
                User findByUserName(String userName);
                User findByUserNameOrEmail(String username, String email);
            }

        com.kid.repository.test2
            public interface UserTest2Repository extends JpaRepository<User, Long> {
                User findByUserName(String userName);
                User findByUserNameOrEmail(String username, String email);
            }
    
    E:测试类编写

        @Resource
        private UserTest1Repository userTest1Repository;
        @Resource
        private UserTest2Repository userTest2Repository;

        @Test
        public void testSave() throws Exception {
            Date date = new Date();
            DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG);
            String formattedDate = dateFormat.format(date);
            userTest1Repository.save(new User("aa", "aa123456","[email protected]", "aa",  formattedDate));
            userTest1Repository.save(new User("bb", "bb123456","[email protected]", "bb",  formattedDate));
            userTest2Repository.save(new User("cc", "cc123456","[email protected]", "cc",  formattedDate));
        }
    
        查看数据库会发现 test1 会有两条数据,test2 有一条。在实际使用中需要哪个数据源使用 @Resource 注入即可。

猜你喜欢

转载自www.cnblogs.com/miantiao312/p/9807843.html
今日推荐