日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

10.SpringBoot学习(十)——JDBC之 Spring Boot Jpa

發(fā)布時(shí)間:2023/12/18 javascript 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 10.SpringBoot学习(十)——JDBC之 Spring Boot Jpa 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

1.簡介

1.1 概述

The Java Persistence API is a standard technology that lets you “map” objects to relational databases. The spring-boot-starter-data-jpa POM provides a quick way to get started. It provides the following key dependencies:

  • Hibernate: One of the most popular JPA implementations.
  • Spring Data JPA: Makes it easy to implement JPA-based repositories.
  • Spring ORMs: Core ORM support from the Spring Framework.

Java Persistence API 是一種標(biāo)準(zhǔn)技術(shù),可讓您將對(duì)象“映射”到關(guān)系數(shù)據(jù)庫。 spring-boot-starter-data-jpa POM提供了一種快速入門的方法。它提供以下關(guān)鍵依賴性:

  • Hibernate:最流行的JPA實(shí)現(xiàn)之一。
  • Spring Data JPA:使基于JPA的存儲(chǔ)庫的實(shí)現(xiàn)變得容易。
  • Spring ORMs:Spring 框架對(duì)Core ORM的支持。

1.2 特點(diǎn)

  • 基于Spring和JPA構(gòu)建存儲(chǔ)庫的先進(jìn)支持
  • 支持 Querydsl 謂詞,從而支持類型安全的JPA查詢
  • 實(shí)體類的透明審核
  • 分頁支持,動(dòng)態(tài)查詢執(zhí)行,集成自定義數(shù)據(jù)訪問代碼的能力
  • 在啟動(dòng)時(shí)驗(yàn)證 @Query 帶注釋的查詢
  • 支持基于XML的實(shí)體映射
  • 通過引入 @EnableJpaRepositories,支持基于 JavaConfig 的存儲(chǔ)庫配置

2.演示環(huán)境

  • JDK 1.8.0_201
  • Spring Boot 2.2.0.RELEASE
  • 構(gòu)建工具(apache maven 3.6.3)
  • 開發(fā)工具(IntelliJ IDEA )
  • 3.演示代碼

    3.1 代碼說明

    演示基于 spring-boot-starter-data-jpa 來操作數(shù)據(jù)庫的簡單 web mvc 項(xiàng)目。包括以下常用場景:

    • 單表的增、刪、改、查
    • 多表關(guān)聯(lián)查詢(這里使用2張表)
    • 復(fù)雜條件混合查詢
    • 分頁查詢

    3.2 代碼結(jié)構(gòu)

    3.3 maven 依賴

    <dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId></dependency> </dependencies>

    3.4 配置文件

    application.properties

    spring.datasource.url=jdbc:mysql://172.16.11.125:3306/test?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=true spring.datasource.username=root spring.datasource.password=123456 spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver# 打印sql spring.jpa.show-sql=true # 自動(dòng)建表 spring.jpa.hibernate.ddl-auto=create # 方言;innodb存儲(chǔ)引擎 spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect # 格式化sql spring.jpa.properties.hibernate.format_sql=true # 打印sql中參數(shù) logging.level.org.hibernate.type.descriptor.sql.BasicBinder=tracespring.data.web.pageable.default-page-size=3 spring.data.web.pageable.page-parameter=pageNum spring.data.web.pageable.size-parameter=pageSize spring.data.web.sort.sort-parameter=orderBy

    3.5 java代碼

    Order.java

    @Entity @Table(name = "t_order") public class Order {@Id@GeneratedValue(strategy = GenerationType.SEQUENCE)private Long id;@Column(nullable = false)private Long userId;@Column(nullable = false, unique = true)private String orderCode;@Column(nullable = false)private BigDecimal totalMoney;@Column(nullable = false)private String orderDate;public Order() {}public Order(Long userId, String orderCode, BigDecimal totalMoney, String orderDate) {this.userId = userId;this.orderCode = orderCode;this.totalMoney = totalMoney;this.orderDate = orderDate;}// get&set&toString }

    User.java

    @Entity @Table(name = "t_user") public class User {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Long id;@Column(nullable = false, unique = true, length = 32)private String name;@Column(nullable = false)private Integer age;private String birthday;private String address;@Column(nullable = false, length = 16)private String phone;public User() {}public User(String name, Integer age, String birthday, String address, String phone) {this.name = name;this.age = age;this.birthday = birthday;this.address = address;this.phone = phone;}// get&set&toString }

    OrderRepository.java

    @Repository public interface OrderRepository extends JpaRepository<Order, Long>, JpaSpecificationExecutor<Order> {@Query(value = "select "+ "o.id as orderId, o.orderCode as orderCode, o.orderDate as orderDate, o.userId as userId, "+ "u.address as address, u.phone as phone, u.age as age from Order o inner join User u on o.userId = u.id where o.orderCode = ?1")OrderInfo selectOrderByCode(String orderCode); }

    UserRepository.java

    @Repository public interface UserRepository extends JpaRepository<User, Long> {@Query("select u from User u where u.name = ?1")User findUserByName(String name);@Query("select u from User u")Page<User> findByPage(Pageable pageable);@Query("select u from User u where u.phone = :phone")List<User> findUserByPhone(@Param("phone") String phone);@Modifying@Transactional@Query("update User set phone = ?1 where name = ?2")int updateByName(String phone, String name);@Modifying@Transactional@Query("delete from User where name = :name")int deleteByName(@Param("name") String name); }

    OrderService.java

    public interface OrderService {/*** 查詢所有user* @return order*/List<Order> selectList();/*** 根據(jù)訂單號(hào)關(guān)聯(lián)查詢* @param orderCode 訂單號(hào)* @return OrderInfo*/OrderInfo selectOrderByCode(String orderCode);/*** 使用example查詢* @param order 查詢參數(shù)* @return Order*/List<Order> selectByExample(Order order);/*** 多條件組合查詢* @param orderParam 查詢參數(shù)* @return Order*/Page<Order> selectByCondition(OrderParam orderParam, Pageable pageable); }

    UserService.java

    public interface UserService {/*** 查詢所有數(shù)據(jù)* @return user*/List<User> selectList();/*** 根據(jù)名稱查詢* @param name name* @return user*/User findUserByName(String name);/*** 根據(jù)電話查詢* @param phone 電話* @return user*/List<User> findUserByPhone(String phone);/*** 分頁查詢* @param pageable 分頁參數(shù)* @return user*/Page<User> findByPage(Pageable pageable);/*** 根據(jù)名稱更新電話* @param phone 電話* @param name 名稱* @return 影響行數(shù)*/User updateByName(String phone, String name);/*** 根據(jù)名稱刪除* @param name 名稱* @return 影響行數(shù)*/User deleteByName(String name);/*** 新增* @param user user* @return user*/User add(User user); }

    UserServiceImpl.java

    @Service public class UserServiceImpl implements UserService {@Autowiredprivate UserRepository userRepository;@Overridepublic List<User> selectList() {return userRepository.findAll();}@Overridepublic User findUserByName(String name) {return userRepository.findUserByName(name);}@Overridepublic List<User> findUserByPhone(String phone) {return userRepository.findUserByPhone(phone);}@Overridepublic Page<User> findByPage(Pageable pageable) {return userRepository.findByPage(pageable);}@Overridepublic User updateByName(String phone, String name) {userRepository.updateByName(phone, name);return findUserByName(name);}@Overridepublic User deleteByName(String name) {User user = findUserByName(name);userRepository.deleteByName(name);return user;}@Overridepublic User add(User user) {return userRepository.save(user);} }

    OrderServiceImpl.java

    @Service public class OrderServiceImpl implements OrderService {@Autowiredprivate OrderRepository orderRepository;@Overridepublic List<Order> selectList() {return orderRepository.findAll();}@Overridepublic OrderInfo selectOrderByCode(String orderCode) {return orderRepository.selectOrderByCode(orderCode);}@Overridepublic List<Order> selectByExample(Order order) {// exact:精確比配 contains: 模糊匹配 startsWith:從頭匹配// 同 matcher -> matcher.exact();ExampleMatcher exampleMatcher = matching().withMatcher("userId", GenericPropertyMatcher::exact).withMatcher("orderCode", GenericPropertyMatcher::contains).withMatcher("orderDate", GenericPropertyMatcher::startsWith);Example<Order> example = Example.of(order, exampleMatcher);return orderRepository.findAll(example);}@Overridepublic Page<Order> selectByCondition(OrderParam orderParam, Pageable pageable) {return orderRepository.findAll((root, query, cb) -> {List<Predicate> predicates = new ArrayList<>();// equal userIdif (Objects.nonNull(orderParam.getUserId())) {predicates.add(cb.equal(root.get("userId"), orderParam.getUserId()));}// like orderCodeif (StringUtils.isNotBlank(orderParam.getOrderCode())) {predicates.add(cb.like(root.get("orderCode"), "%" + orderParam.getOrderCode() + "%"));}// betweenif (StringUtils.isNotBlank(orderParam.getOrderStartDate()) && StringUtils.isNotBlank(orderParam.getOrderEndDate())) {predicates.add(cb.between(root.get("orderDate"), orderParam.getOrderStartDate(), orderParam.getOrderEndDate()));}// greater thanif (Objects.nonNull(orderParam.getTotalMoney())) {predicates.add(cb.greaterThan(root.get("totalMoney"), orderParam.getTotalMoney()));}return query.where(predicates.toArray(new Predicate[0])).getRestriction();}, pageable);} }

    OrderInfo.java

    public interface OrderInfo {Long getUserId();Long getOrderId();Integer getAge();String getOrderCode();String getAddress();String getPhone();String getOrderDate(); }

    OrderParam.java

    public class OrderParam {private Long id;private Long userId;private String orderCode;private BigDecimal totalMoney;private String orderStartDate;private String orderEndDate;// get&set }

    OrderController.java

    @RestController @RequestMapping(value = "/order") public class OrderController {@Autowiredprivate OrderService orderService;@GetMapping(value = "/list")public List<Order> list() {return orderService.selectList();}@GetMapping(value = "/queryByCode/{orderCode}")public OrderInfo queryByCode(@PathVariable String orderCode) {return orderService.selectOrderByCode(orderCode);}@GetMapping(value = "/queryByExample")public List<Order> selectByExample(@RequestBody Order order) {return orderService.selectByExample(order);}@GetMapping(value = "/queryByCondition")public Page<Order> queryByCondition(@RequestBody OrderParam orderParam, Pageable pageable) {return orderService.selectByCondition(orderParam, pageable);} }

    UserController.java

    @RestController @RequestMapping(value = "/user") public class UserController {@Autowiredprivate UserService userService;@GetMapping(value = "/list")public List<User> list() {return userService.selectList();}@GetMapping(value = "/findByName/{name}")public User findByName(@PathVariable String name) {return userService.findUserByName(name);}@GetMapping(value = "/findByPhone/{phone}")public List<User> findByPhone(@PathVariable String phone) {return userService.findUserByPhone(phone);}@GetMapping(value = "/page")public Page<User> page(Pageable pageable) {return userService.findByPage(pageable);}@PostMapping(value = "/add")public User add(User user) {return userService.add(user);}@PutMapping(value = "/updateByName")public User updateByName(@RequestBody User user) {return userService.updateByName(user.getPhone(), user.getName());}@DeleteMapping(value = "/deleteByName/{name}")public User deleteByName(@PathVariable String name) {return userService.deleteByName(name);} }

    InitializeDataCommand.java

    @Component public class InitializeDataCommand implements CommandLineRunner {@Autowiredprivate UserRepository userRepository;@Autowiredprivate OrderRepository orderRepository;@Overridepublic void run(String... args) throws Exception {User user1 = new User("zhangsan", 20, "2000-01-01", "shenzhen", "13888888888");User user2 = new User("lisi", 21, "1999-01-01", "shanghai", "13777777777");User user3 = new User("wangwu", 22, "1998-01-01", "beijing", "13666666666");User user4 = new User("zhaoliu", 23, "1997-01-01", "guangzhou", "13555555555");User user5 = new User("sunqi", 24, "1996-01-01", "wuhan", "13444444444");SecureRandom random = SecureRandom.getInstance("SHA1PRNG", "SUN");DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");LocalDateTime now = LocalDateTime.now();List<User> users = userRepository.saveAll(Arrays.asList(user1, user2, user3, user4, user5));List<Order> orders = users.stream().map(user -> {Order order = new Order();order.setUserId(user.getId());order.setOrderCode("OC202005231205000" + (users.indexOf(user) + 1));order.setOrderDate(dateTimeFormatter.format(now.minusDays(random.nextInt(100))));order.setTotalMoney(BigDecimal.valueOf(random.nextDouble() * random.nextInt(10000)));return order;}).collect(Collectors.toList());orderRepository.saveAll(orders);} }

    3.6 git 地址

    spring-boot/spring-boot-06-jdbc/spring-boot-data-jpa

    4.效果展示

    啟動(dòng) SpringBootJpaDemoApplication.main 方法,在 spring-boot-data-jpa.http 訪問下列地址,觀察輸出信息是否符合預(yù)期。

    4.1 t_user

    查詢用戶列表(所有)

    ### GET /user/list GET http://localhost:8080/user/list Accept: application/json

    根據(jù)用戶名查詢

    ### GET /user/findByName/{name} GET http://localhost:8080/user/findByName/lisi Accept: application/json

    根據(jù)手機(jī)號(hào)查詢

    ### GET /user/findByPhone/{phone} GET http://localhost:8080/user/findByPhone/13666666666 Accept: application/json

    查詢用戶列表(分頁)

    ### GET /user/page GET http://localhost:8080/user/page Accept: application/json Content-Type: application/json{"pageable":{"pageNumber":1,"pageSize":3,"orderBy":"age desc"} }

    更新用戶信息

    ### PUT /user/updateByName PUT http://localhost:8080/user/updateByName Content-Type: application/json{"name": "zhangsan","phone": "13456789012" }

    刪除用戶

    ### DELETE /user/deleteByName/{name} DELETE http://localhost:8080/user/deleteByName/zhangsan Content-Type: application/json

    4.2 t_order

    查詢訂單列表(所有)

    ### GET /order/list GET http://localhost:8080/order/list Accept: application/json

    根據(jù)訂單編號(hào)關(guān)聯(lián)查詢

    ### GET /order/queryByCode/{orderCode} GET http://localhost:8080/order/queryByCode/OC2020052312050002 Accept: application/json

    多條件查詢訂單

    ### GET /order/queryByExample GET http://localhost:8080/order/queryByExample Accept: application/json Content-Type: application/json{ "userId":2, "orderCode":"OC202005231", "orderDate": "2020-05-17" }

    多條件混合查詢

    ### GET /order/queryByCondition GET http://localhost:8080/order/queryByCondition Accept: application/json Content-Type: application/json{"userId": 2,"orderCode": "OC20200523","totalMoney": 20,"orderStartDate": "2020-02-10 16:17:12","orderEndDate": "2020-05-30 16:17:12" }

    5.源碼分析

    5.1 @Repository 如何加載的?

    SpringBooApplication 應(yīng)用啟動(dòng)時(shí),會(huì)調(diào)用 createApplicationContext 方法,這里指定了默認(rèn) web 應(yīng)用的類型是 AnnotationConfigServletWebServerApplicationContext。在 AnnotationConfigServletWebServerApplicationContext 的構(gòu)造函數(shù)中,調(diào)用了 AnnotatedBeanDefinitionReader 的構(gòu)造方法,最終通過 registerAnnotationConfigProcessors 方法將一些和注解掃描相關(guān)的 Processor 注冊到 context 中,其中有一個(gè)類是 ConfigurationClassPostProcessor,這個(gè)比較關(guān)鍵。

    在調(diào)用 refreshContext 方法時(shí),最終會(huì)調(diào)用到 AbstractApplicationContext 的 refresh 方法,在這個(gè)流程中,invokeBeanFactoryPostProcessors 方法觸發(fā)了 ConfigurationClassPostProcessor,將注解進(jìn)行掃描,從而注冊到 registry 中。

    5.2 UserRepository 的動(dòng)態(tài)代理

    UserRepository 繼承自 JpaRepository,JpaRepository 有一個(gè) FactoryBean 叫 JpaRepositoryFactoryBean,它實(shí)現(xiàn)了InitializingBean 接口,在 afterPropertiesSet 中進(jìn)行了代理操作。同時(shí)它也實(shí)現(xiàn)了 FactoryBean 接口,提供一個(gè) getObject 方法來獲取 bean 的實(shí)例。

    在 factory.getRepository 方法中,有一個(gè) getRepositoryInformation 方法,它的實(shí)現(xiàn)如下

    private RepositoryInformation getRepositoryInformation(RepositoryMetadata metadata,RepositoryComposition composition) {RepositoryInformationCacheKey cacheKey = new RepositoryInformationCacheKey(metadata, composition);return repositoryInformationCache.computeIfAbsent(cacheKey, key -> {// 這里的 baseClass 為 SimpleJpaRepositoryClass<?> baseClass = repositoryBaseClass.orElse(getRepositoryBaseClass(metadata));return new DefaultRepositoryInformation(metadata, baseClass, composition);}); }

    這里的 getRepositoryBaseClass 獲取一個(gè) baseClass,實(shí)際返回一個(gè) SimpleJpaRepository.class,這個(gè) baseClass 在后面作為被代理對(duì)象使用。

    在 getTargetRepositoryViaReflection 方法中,根據(jù)這個(gè) baseClass,通過反射創(chuàng)建對(duì)象

    protected final <R> R getTargetRepositoryViaReflection(RepositoryInformation information,Object... constructorArguments) {// 獲取到 baseClass,即為 SimpleJpaRepositoryClass<?> baseClass = information.getRepositoryBaseClass();return getTargetRepositoryViaReflection(baseClass, constructorArguments); }protected final <R> R getTargetRepositoryViaReflection(Class<?> baseClass, Object... constructorArguments) {Optional<Constructor<?>> constructor = ReflectionUtils.findConstructor(baseClass, constructorArguments);// 通過反射創(chuàng)建對(duì)象對(duì)象return constructor.map(it -> (R) BeanUtils.instantiateClass(it, constructorArguments)).orElseThrow(() -> new IllegalStateException(String.format("No suitable constructor found on %s to match the given arguments: %s. Make sure you implement a constructor taking these",baseClass, Arrays.stream(constructorArguments).map(Object::getClass).collect(Collectors.toList()))));}

    然后將這個(gè)對(duì)象作為 target 放到 result 中,result 又添加了一些 advisor 和 advice,這些在查詢時(shí)被構(gòu)建成鏈接器鏈

    // 獲取到一個(gè) SimpleJpaRepository 實(shí)例 Object target = getTargetRepository(information);// Create proxy ProxyFactory result = new ProxyFactory(); // 作為目標(biāo)對(duì)象 result.setTarget(target); result.setInterfaces(repositoryInterface, Repository.class, TransactionalProxy.class);if (MethodInvocationValidator.supports(repositoryInterface)) {result.addAdvice(new MethodInvocationValidator()); } // 添加 advisor result.addAdvisor(ExposeInvocationInterceptor.ADVISOR);postProcessors.forEach(processor -> processor.postProcess(result, information));if (DefaultMethodInvokingMethodInterceptor.hasDefaultMethods(repositoryInterface)) {result.addAdvice(new DefaultMethodInvokingMethodInterceptor()); }// 添加 advice ProjectionFactory projectionFactory = getProjectionFactory(classLoader, beanFactory); result.addAdvice(new QueryExecutorMethodInterceptor(information, projectionFactory));composition = composition.append(RepositoryFragment.implemented(target)); result.addAdvice(new ImplementationMethodExecutionInterceptor(composition)); // 獲取代理對(duì)象 T repository = (T) result.getProxy(classLoader);

    最終生成的代理對(duì)象即為如下所示

    5.3 Jpa 查詢流程是怎樣的?

    這里以 UserServiceImpl#findUserByName 說一下 jpa 的查詢流程

    在 UserServiceImpl 調(diào)用了 UserRepository,UserRepository 是一個(gè)代理對(duì)象,它被 JdkDynamicAopProxy 所代理,所以執(zhí)行 UserRepository 中方法時(shí),會(huì)調(diào)用 JdkDynamicAopProxy 中 invoke 方法。

    @Override @Nullable public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {Object oldProxy = null;boolean setProxyContext = false;TargetSource targetSource = this.advised.targetSource;Object target = null;try {if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {// The target does not implement the equals(Object) method itself.return equals(args[0]);}else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {// The target does not implement the hashCode() method itself.return hashCode();}else if (method.getDeclaringClass() == DecoratingProxy.class) {// There is only getDecoratedClass() declared -> dispatch to proxy config.return AopProxyUtils.ultimateTargetClass(this.advised);}else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&method.getDeclaringClass().isAssignableFrom(Advised.class)) {// Service invocations on ProxyConfig with the proxy config...return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);}Object retVal;if (this.advised.exposeProxy) {// Make invocation available if necessary.oldProxy = AopContext.setCurrentProxy(proxy);setProxyContext = true;}// Get as late as possible to minimize the time we "own" the target,// in case it comes from a pool.// 獲取目標(biāo)對(duì)象target = targetSource.getTarget();Class<?> targetClass = (target != null ? target.getClass() : null);// Get the interception chain for this method.// 構(gòu)建攔截鏈List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);// Check whether we have any advice. If we don't, we can fallback on direct// reflective invocation of the target, and avoid creating a MethodInvocation.if (chain.isEmpty()) {// We can skip creating a MethodInvocation: just invoke the target directly// Note that the final invoker must be an InvokerInterceptor so we know it does// nothing but a reflective operation on the target, and no hot swapping or fancy proxying.Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);}else {// We need to create a method invocation...MethodInvocation invocation =new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);// Proceed to the joinpoint through the interceptor chain.retVal = invocation.proceed();}// Massage return value if necessary.Class<?> returnType = method.getReturnType();if (retVal != null && retVal == target &&returnType != Object.class && returnType.isInstance(proxy) &&!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {// Special case: it returned "this" and the return type of the method// is type-compatible. Note that we can't help if the target sets// a reference to itself in another returned object.retVal = proxy;}else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {throw new AopInvocationException("Null return value from advice does not match primitive return type for: " + method);}return retVal;}finally {if (target != null && !targetSource.isStatic()) {// Must have come from TargetSource.targetSource.releaseTarget(target);}if (setProxyContext) {// Restore old proxy.AopContext.setCurrentProxy(oldProxy);}} }

    在 JdkDynamicAopProxy 中會(huì)通過 getInterceptorsAndDynamicInterceptionAdvice 獲取到一條鏈,實(shí)際上它是一個(gè)攔截器鏈,它由一下幾個(gè)部分組成:

    • ExposeInvocationInterceptor: 將當(dāng)前的invocation設(shè)置到上下文中
    • CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor: 判斷是自定義方法還是jpa中方法,如果是自定義方法直接執(zhí)行下一個(gè)攔截器;否則綁定資源再執(zhí)行下一個(gè)攔截器
    • PersistenceExceptionTranslationInterceptor: 捕獲RuntimeException,出現(xiàn)異常之后攔截器才生效
    • TransactionInterceptor: 給后面要執(zhí)行的攔截器添加后置事務(wù)處理
    • DefaultMethodInvokingMethodInterceptor: 判斷是否 defaultMethod,如果不是走下一個(gè)攔截器;否則使用MethodHandle執(zhí)行
    • RepositoryFactorySupport$QueryExecutorMethodInterceptor: 執(zhí)行自定義查詢
    • RepositoryFactorySupport$ImplementationMethodExecutionInterceptor:攔截 RepositoryComposition
    • PersistenceExceptionTranslationInterceptor:異常處理攔截器

    最終在 QueryExecutorMethodInterceptor 中調(diào)用 doInvoke 方法執(zhí)行自定義查詢

    @Nullable private Object doInvoke(MethodInvocation invocation) throws Throwable {Method method = invocation.getMethod();if (hasQueryFor(method)) {// 執(zhí)行查詢return queries.get(method).execute(invocation.getArguments());}// 繼續(xù)執(zhí)行下一個(gè)攔截器return invocation.proceed(); }

    在 execute 中,通過調(diào)用 AbstractJpaQuery#execute -> AbstractJpaQuery#doExecute -> JpaQueryExecution#execute -> JpaQueryExecution.SingleEntityExecution#doExecute -> AbstractProducedQuery#getSingleResult -> AbstractProducedQuery#list -> AbstractProducedQuery#doList -> org.hibernate.internal.SessionImpl#list,使用 hibernate 完成查詢。

    6.參考

  • 官方 spring-data-jpa
  • 官方文檔-Spring Boot Features/JPA
  • 總結(jié)

    以上是生活随笔為你收集整理的10.SpringBoot学习(十)——JDBC之 Spring Boot Jpa的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。