欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Spring Data Jpa(三)

程序员文章站 2022-04-25 20:01:30
...

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 注入即可。
相关标签: springboot

上一篇: 你生日

下一篇: 201712-2 游戏