
前言


基本使用
<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.5.6</version><relativePath/></parent><!-- jpa --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId></dependency><!-- mysql --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency>
spring:datasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/sakila?useUnicode=true&zeroDateTimeBehavior=convertToNull&autoReconnect=true&characterEncoding=utf-8username: rootpassword: root
@Entity@Data lombok注解public class Actor {@IdColumn注解不是必须的,如果满足字段驼峰形式与数据库字段以下划线分隔形式对应即可@Column(name = "actor_id", nullable = false)private Integer actorId;@Column(name = "first_name", nullable = false, length = 45)private String firstName;private String lastName;private Timestamp lastUpdate;}
@Repositorypublic interface ActorRepository extends JpaRepository<Actor, Integer> {}
/*** 示例1* SQL: SELECT * FROM actor WHERE first_name = ?* 参数名的定义不影响程序的运行*/List<Actor> findByFirstName(String name);/*** 示例2* SQL: SELECT * FROM actor WHERE first_name = ? AND last_name = ?* 如果明确知道查询结果返回唯一一条记录时,建议使用单一实体类作为返回类型*/List<Actor> findByFirstNameAndLastName(String name1, String name2);/*** 示例3* SQL: SELECT * FROM actor WHERE actor_id <= ?*/List<Actor> findByActorIdLessThanEqual(Integer id);
List<Film> findByLengthBetween(Integer low, Integer up);List<Film> findByLastUpdateBetween(Date startDate, Date endDate);
List<Film> findByLengthBefore(Integer length)
/*** 示例1* SQL: SELECT * FROM actor WHERE first_name = ?*/@Query("FROM Actor WHERE firstName = ?1")List<Actor> findByFirstName(String name);/*** 示例2* SQL: SELECT * FROM actor WHERE first_name = ? AND last_name = ?*/@Query("FROM Actor WHERE firstName = ?1 AND lastName = ?2")List<Actor> findByFirstNameAndLastName(String name1, String name2);/*** 示例3* SQL: SELECT * FROM actor WHERE actor_id <= ?*/@Query("FROM Actor WHERE actorId <= ?1")List<Actor> findByActorIdLessThanEqual(Integer id);/*** 示例4* SQL: SELECT * FROM actor* 不能写"SELECT *" 要写"SELECT 别名"*/@Query("SELECT a FROM Actor a")List<Actor> findAll()
SELECT 实体别名.属性名, 实体别名.属性名 FROM 实体名 AS 实体别名 WHERE 实体别名.实体属性 op 比较值
@Modifying@Query(value = "UPDATE Film SET description = :description WHERE filmId = :id")void update(@Param("id") Integer filmId, @Param("description") String description);
@Query("SELECT * FROM actor WHERE first_name = ?1", nativeQuery = true)List<Actor> findByFirstName(String name);@Query("SELECT * FROM actor WHERE first_name = ?1 AND last_name = ?2", nativeQuery = true)List<Actor> findByFirstNameAndLastName(String name1, String name2);@Query("SELECT * FROM actor WHERE actor_id <= ?", nativeQuery = true)List<Actor> findByActorIdLessThanEqual(Integer id);@Query("SELECT first_name, last_name FROM actor", nativeQuery = true)List<Map<String, Object>> findAll();// List<String[]> findAll();

JPA的原理浅析
package org.springframework.boot.autoconfigure;@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Inherited@SpringBootConfiguration@EnableAutoConfiguration@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })public @interface SpringBootApplication {@AliasFor(annotation = EnableAutoConfiguration.class)Class<?>[] exclude() default {};@AliasFor(annotation = EnableAutoConfiguration.class)String[] excludeName() default {};@AliasFor(annotation = ComponentScan.class, attribute = "basePackages")String[] scanBasePackages() default {};@AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses")Class<?>[] scanBasePackageClasses() default {};@AliasFor(annotation = ComponentScan.class, attribute = "nameGenerator")Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;@AliasFor(annotation = Configuration.class)boolean proxyBeanMethods() default true;}
package org.springframework.boot.autoconfigure;@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Inherited@AutoConfigurationPackage@Import(AutoConfigurationImportSelector.class)public @interface EnableAutoConfiguration {String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";Class<?>[] exclude() default {};String[] excludeName() default {};}

@Repository@Transactional(readOnly = true)public class SimpleJpaRepository<T, ID> implements JpaRepositoryImplementation<T, ID> {}
@Configuration(proxyBeanMethods = false)@ConditionalOnBean(DataSource.class)@ConditionalOnClass(JpaRepository.class)@ConditionalOnMissingBean({ JpaRepositoryFactoryBean.class, JpaRepositoryConfigExtension.class })@ConditionalOnProperty(prefix = "spring.data.jpa.repositories", name = "enabled", havingValue = "true",matchIfMissing = true)@Import(JpaRepositoriesRegistrar.class)@AutoConfigureAfter({ HibernateJpaAutoConfiguration.class, TaskExecutionAutoConfiguration.class })public class JpaRepositoriesAutoConfiguration {}
class JpaRepositoriesRegistrar extends AbstractRepositoryConfigurationSourceSupport {}public abstract class AbstractRepositoryConfigurationSourceSupportimplements ImportBeanDefinitionRegistrar, BeanFactoryAware, ResourceLoaderAware, EnvironmentAware {private ResourceLoader resourceLoader;private BeanFactory beanFactory;private Environment environment;@Overridepublic void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry,BeanNameGenerator importBeanNameGenerator) {RepositoryConfigurationDelegate delegate = new RepositoryConfigurationDelegate(getConfigurationSource(registry, importBeanNameGenerator), this.resourceLoader, this.environment);delegate.registerRepositoriesIn(registry, getRepositoryConfigurationExtension());}@Overridepublic void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {registerBeanDefinitions(importingClassMetadata, registry, null);}其他源码...}




@Nonnullpublic T getObject() {return this.repository.get();}
@Overridepublic void afterPropertiesSet() {Assert.state(entityManager != null, "EntityManager must not be null!");super.afterPropertiesSet();}
// 以下代码实现在org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport中public void afterPropertiesSet() {this.factory = createRepositoryFactory();this.factory.setQueryLookupStrategyKey(queryLookupStrategyKey);this.factory.setNamedQueries(namedQueries);this.factory.setEvaluationContextProvider(evaluationContextProvider.orElseGet(() -> QueryMethodEvaluationContextProvider.DEFAULT));this.factory.setBeanClassLoader(classLoader);this.factory.setBeanFactory(beanFactory);if (publisher != null) {this.factory.addRepositoryProxyPostProcessor(new EventPublishingRepositoryProxyPostProcessor(publisher));}repositoryBaseClass.ifPresent(this.factory::setRepositoryBaseClass);this.repositoryFactoryCustomizers.forEach(customizer -> customizer.customize(this.factory));RepositoryFragments customImplementationFragment = customImplementation.map(RepositoryFragments::just).orElseGet(RepositoryFragments::empty);RepositoryFragments repositoryFragmentsToUse = this.repositoryFragments.orElseGet(RepositoryFragments::empty).append(customImplementationFragment);this.repositoryMetadata = this.factory.getRepositoryMetadata(repositoryInterface);this.repository = Lazy.of(() -> this.factory.getRepository(repositoryInterface, repositoryFragmentsToUse));Make sure the aggregate root type is present in the MappingContext (e.g. for auditing)this.mappingContext.ifPresent(it -> it.getPersistentEntity(repositoryMetadata.getDomainType()));if (!lazyInit) {this.repository.get();}}
this.repository = Lazy.of(() -> this.factory.getRepository(repositoryInterface, repositoryFragmentsToUse));
this.factory = createRepositoryFactory();
protected final RepositoryFactorySupport createRepositoryFactory() {RepositoryFactorySupport factory = doCreateRepositoryFactory();RepositoryProxyPostProcessor exceptionPostProcessor = this.exceptionPostProcessor;if (exceptionPostProcessor != null) {factory.addRepositoryProxyPostProcessor(exceptionPostProcessor);}RepositoryProxyPostProcessor txPostProcessor = this.txPostProcessor;if (txPostProcessor != null) {factory.addRepositoryProxyPostProcessor(txPostProcessor);}return factory;}
protected RepositoryFactorySupport doCreateRepositoryFactory() {Assert.state(entityManager != null, "EntityManager must not be null!");return createRepositoryFactory(entityManager);}/*** Returns a {@link RepositoryFactorySupport}.*/protected RepositoryFactorySupport createRepositoryFactory(EntityManager entityManager) {JpaRepositoryFactory jpaRepositoryFactory = new JpaRepositoryFactory(entityManager);jpaRepositoryFactory.setEntityPathResolver(entityPathResolver);jpaRepositoryFactory.setEscapeCharacter(escapeCharacter);if (queryMethodFactory != null) {jpaRepositoryFactory.setQueryMethodFactory(queryMethodFactory);}return jpaRepositoryFactory;}

public <T> T getRepository(Class<T> repositoryInterface, RepositoryFragments fragments) {...RepositoryInformation information = getRepositoryInformation(metadata, composition);...Object target = getTargetRepository(information);...ProxyFactory result = new ProxyFactory();result.setTarget(target);result.setInterfaces(repositoryInterface, Repository.class, TransactionalProxy.class);...T repository = (T) result.getProxy(classLoader);...return repository;}
private RepositoryInformation getRepositoryInformation(RepositoryMetadata metadata,RepositoryComposition composition) {RepositoryInformationCacheKey cacheKey = new RepositoryInformationCacheKey(metadata, composition);return repositoryInformationCache.computeIfAbsent(cacheKey, key -> {Class<?> baseClass = repositoryBaseClass.orElse(getRepositoryBaseClass(metadata));return new DefaultRepositoryInformation(metadata, baseClass, composition);});}
protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) {return SimpleJpaRepository.class;}
@EnableJpaRepositories(basePackages = "ai.advance.jpademo.repository")@SpringBootApplicationpublic class JpaDemoApplication {public static void main(String[] args) {SpringApplication.run(JpaDemoApplication.class, args);}}
public <T> T getRepository(Class<T> repositoryInterface, RepositoryFragments fragments) {...ProxyFactory result = new ProxyFactory();...Optional<QueryLookupStrategy> queryLookupStrategy = getQueryLookupStrategy(queryLookupStrategyKey,evaluationContextProvider);result.addAdvice(new QueryExecutorMethodInterceptor(information, projectionFactory, queryLookupStrategy,namedQueries, queryPostProcessors, methodInvocationListeners));result.addAdvice(new ImplementationMethodExecutionInterceptor(information, compositionToUse, methodInvocationListeners));T repository = (T) result.getProxy(classLoader);...return repository;}


方法头上@Query注解的nativeQuery属性缺省值为false,也就是使用JPQL,此时会创建SimpleJpaQuery实例,并通过两个StringQuery类实例分别持有query JPQL语句和根据query JPQL计算拼接出来的countQuery JPQL语句
方法头上@Query注解的nativeQuery属性如果显式的设置为nativeQuery=true,也就是使用原生SQL的时候
方法头上未进行@Query注解,将使用spring-data-jpa独创的方法名识别的方式进行sql语句拼接
使用javax.persistence.NamedQuery注解访问数据库的形式的时候
在Repository接口的方法头上使用org.springframework.data.jpa.repository.query.Procedure注解,也就是调用存储过程的方式访问数据库的时候
private Object doInvoke(MethodInvocation invocation) throws Throwable {Method method = invocation.getMethod();if (hasQueryFor(method)) {RepositoryMethodInvoker invocationMetadata = invocationMetadataCache.get(method);if (invocationMetadata == null) {invocationMetadata = RepositoryMethodInvoker.forRepositoryQuery(method, queries.get(method));invocationMetadataCache.put(method, invocationMetadata);}return invocationMetadata.invoke(repositoryInformation.getRepositoryInterface(), invocationMulticaster,invocation.getArguments());}return invocation.proceed();}

public Object invoke(@SuppressWarnings("null") MethodInvocation invocation) throws Throwable {Method method = invocation.getMethod();Object[] arguments = invocation.getArguments();try {return composition.invoke(invocationMulticaster, method, arguments);} catch (Exception e) {org.springframework.data.repository.util.ClassUtils.unwrapReflectionException(e);}throw new IllegalStateException("Should not occur!");}


总结


关于领创集团

文章转载自领创集团Advance Group,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。






