• SpringBoot jpa 注解 @ElementCollection 实现一对多关联


    环境:

    jdk: openjdk11

    springboot: 2.2

    操作系统: win10教育版 1903

    1. pom.xml (jpa依赖主要在 jpa-redis注释下的两个)

      1 <?xml version="1.0" encoding="UTF-8"?>
      2 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      3          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
      4     <modelVersion>4.0.0</modelVersion>
      5     <parent>
      6         <groupId>org.springframework.boot</groupId>
      7         <artifactId>spring-boot-starter-parent</artifactId>
      8         <version>2.2.4.RELEASE</version>
      9         <relativePath/> <!-- lookup parent from repository -->
     10     </parent>
     11     <groupId>com.rurjs</groupId>
     12     <artifactId>starter</artifactId>
     13     <version>0.0.1</version>
     14     <name>RurjsStarter</name>
     15     <description>Demo project for Spring Boot</description>
     16 
     17     <properties>
     18         <java.version>11</java.version>
     19         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
     20         <security-jwt.version>1.0.9.RELEASE</security-jwt.version>
     21         <jjwt.version>0.9.0</jjwt.version>
     22         <spring-cloud-dependency-version>2.1.2.RELEASE</spring-cloud-dependency-version>
     23     </properties>
     24 
     25     <dependencies>
     26         <dependency>
     27             <groupId>org.springframework.boot</groupId>
     28             <artifactId>spring-boot-starter-web</artifactId>
     29         </dependency>
     30         <!--开发工具-->
     31         <dependency>
     32             <groupId>org.springframework.boot</groupId>
     33             <artifactId>spring-boot-devtools</artifactId>
     34             <scope>runtime</scope>
     35             <optional>true</optional>
     36         </dependency>
     37         <dependency>
     38             <groupId>org.apache.commons</groupId>
     39             <artifactId>commons-lang3</artifactId>
     40             <version>3.9</version>
     41         </dependency>
     42         <!--lombok工具-->
     43         <dependency>
     44             <groupId>org.projectlombok</groupId>
     45             <artifactId>lombok</artifactId>
     46             <optional>true</optional>
     47         </dependency>
     48         <!--单元测试-->
     49         <dependency>
     50             <groupId>org.springframework.boot</groupId>
     51             <artifactId>spring-boot-starter-test</artifactId>
     52             <scope>test</scope>
     53             <exclusions>
     54                 <exclusion>
     55                     <groupId>org.junit.vintage</groupId>
     56                     <artifactId>junit-vintage-engine</artifactId>
     57                 </exclusion>
     58             </exclusions>
     59         </dependency>
     60         <dependency>
     61             <groupId>io.projectreactor</groupId>
     62             <artifactId>reactor-test</artifactId>
     63             <scope>test</scope>
     64         </dependency>
     65         <!--jpa-redis-->
     66         <dependency>
     67             <groupId>org.springframework.boot</groupId>
     68             <artifactId>spring-boot-starter-data-jpa</artifactId>
     69         </dependency>
     70         <dependency>
     71             <groupId>mysql</groupId>
     72             <artifactId>mysql-connector-java</artifactId>
     73             <!--<version>5.1.46</version>-->
     74         </dependency>
     75         <dependency>
     76             <groupId>org.springframework.boot</groupId>
     77             <artifactId>spring-boot-starter-data-redis</artifactId>
     78         </dependency>
     79         <!--oauth2认证-->
     80         <dependency>
     81             <groupId>org..springframework.cloud</groupId>
     82             <artifactId>spring-cloud-starter-oauth2</artifactId>
     83             <version>${spring-cloud-dependency-version}</version>
     84         </dependency>
     85         <dependency>
     86             <groupId>org.springframework.cloud</groupId>
     87             <artifactId>spring-cloud-starter-security</artifactId>
     88             <version>${spring-cloud-dependency-version}</version>
     89         </dependency>
     90         <dependency>
     91             <groupId>org.springframework.security</groupId>
     92             <artifactId>spring-security-jwt</artifactId>
     93             <version>${security-jwt.version}</version>
     94         </dependency>
     95         <dependency>
     96             <groupId>io.jsonwebtoken</groupId>
     97             <artifactId>jjwt</artifactId>
     98             <version>0.7.0</version>
     99         </dependency>
    100         <!--json-->
    101         <dependency>
    102             <groupId>com.alibaba</groupId>
    103             <artifactId>fastjson</artifactId>
    104             <version>1.2.57</version>
    105         </dependency>
    106         <!--API文档-springfox-swagger2-->
    107         <dependency>
    108             <groupId>io.springfox</groupId>
    109             <artifactId>springfox-swagger2</artifactId>
    110             <version>2.9.2</version>
    111             <!--排除这个包,这里有个bug: Illegal DefaultValue  for parameter type integer-->
    112             <exclusions>
    113                 <exclusion>
    114                     <groupId>io.swagger</groupId>
    115                     <artifactId>swagger-models</artifactId>
    116                 </exclusion>
    117             </exclusions>
    118         </dependency>
    119         <dependency>
    120             <groupId>io.swagger</groupId>
    121             <artifactId>swagger-models</artifactId>
    122             <version>1.5.21</version>
    123         </dependency>
    124         <dependency>
    125             <groupId>io.springfox</groupId>
    126             <artifactId>springfox-swagger-ui</artifactId>
    127             <version>2.9.2</version>
    128         </dependency>
    129     </dependencies>
    130 
    131     <build>
    132         <plugins>
    133             <plugin>
    134                 <groupId>org.springframework.boot</groupId>
    135                 <artifactId>spring-boot-maven-plugin</artifactId>
    136             </plugin>
    137         </plugins>
    138     </build>
    139 
    140 </project>

    2. application.yml( 主要是 spring.datasource 和 spring.jpa部分)

     1 server:
     2   port: 9018
     3 spring:
     4   redis:
     5     host: 127.0.0.1
     6     database: 0
     7   datasource:
     8     url: jdbc:mysql://127.0.0.1:3306/rurjs_starter?characterEncoding=UTF-8&serverTimezone=UTC
     9     username: root
    10     password: DRsXT5sJ6Oi55LPj
    11   jpa:
    12     hibernate:
    13       ddl-auto: update
    14     database: mysql
    15     show-sql: true
    16     database-platform: org.hibernate.dialect.MySQL5InnoDBDialect
    17 
    18 rjsSecurity:
    19   exclude:
    20     antMatchers: /oauth/**,/login,/home
    21 #logging:
    22 #  level: debug

    3. 主类

     1 package com.rurjs.starter;
     2 
     3 import org.springframework.boot.SpringApplication;
     4 import org.springframework.boot.autoconfigure.SpringBootApplication;
     5 import org.springframework.web.bind.annotation.RequestMapping;
     6 import org.springframework.web.bind.annotation.RestController;
     7 
     8 @SpringBootApplication
     9 public class RurjsStarterApplication {
    10 
    11     public static void main(String[] args) {
    12         SpringApplication.run(RurjsStarterApplication.class, args);
    13     }
    14 
    15     @RestController
    16     public class HealthController{
    17 
    18         @RequestMapping("ping")
    19         public String ping()
    20         {
    21             return "Pong";
    22         }
    23     }
    24 }

    4. 实体类

    package com.rurjs.starter.config.sso.domain;
    
    
    import lombok.Getter;
    import lombok.Setter;
    import lombok.ToString;
    import org.hibernate.annotations.Fetch;
    import org.hibernate.annotations.FetchMode;
    import org.springframework.data.jpa.domain.support.AuditingEntityListener;
    import org.springframework.security.core.GrantedAuthority;
    import org.springframework.security.oauth2.provider.ClientDetails;
    import java.io.Serializable;
    import javax.persistence.*;
    import java.util.*;
    @Getter @Setter @ToString @Entity @EntityListeners(AuditingEntityListener.
    class) @Table public class OauthClientDetails implements Serializable{ private static final long serialVersionUID = 2930534157595467437L; @Id private String clientId;//client_id @Fetch(FetchMode.JOIN) @ElementCollection private Set<String> resourceIds;//资源id private String clientSecret;//client 密钥 }

    自动生成表如下:

    mysql> show create table oauth_client_details_resource_ids;
    +-----------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
    | Table                             | Create Table                                                                                                                                                                                                                                                                                                                                                                                               |
    +-----------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
    | oauth_client_details_resource_ids | CREATE TABLE `oauth_client_details_resource_ids` (
      `oauth_client_details_client_id` varchar(255) NOT NULL,
      `resource_ids` varchar(255) DEFAULT NULL,
      KEY `FKo1c1xapbgjtw5kgq9c1fy8vp3` (`oauth_client_details_client_id`),
      CONSTRAINT `FKo1c1xapbgjtw5kgq9c1fy8vp3` FOREIGN KEY (`oauth_client_details_client_id`) REFERENCES `oauth_client_details` (`client_id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8 |
    +-----------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
    1 row in set (0.03 sec)
    
    mysql> 

    5. Dao

    package com.rurjs.starter.config.sso.dao;
    
    import com.rurjs.starter.config.sso.domain.OauthClientDetails;
    import org.springframework.data.jpa.repository.JpaRepository;
    import org.springframework.stereotype.Repository;
    
    import java.util.Collection;
    @Repository("OauthClientDetailsDao")
    public interface OauthClientDetailsDao extends JpaRepository<OauthClientDetails,String> {
    
        //批量删除.
        public int deleteAllByClientIdIn(Collection<String> clientId);
    }

    6. 单元测试

    package com.rurjs.starter;
    
    import com.rurjs.starter.config.sso.dao.OauthClientDetailsDao;
    import com.rurjs.starter.config.sso.domain.OauthClientDetails;
    
    import org.junit.jupiter.api.Test;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
    import org.springframework.security.oauth2.provider.ClientDetailsService;
    import org.springframework.transaction.annotation.Transactional;
    
    import java.util.ArrayList;
    import java.util.HashSet;
    import java.util.List;
    import java.util.Set;
    
    @SpringBootTest
    class RurjsStarterApplicationTests {
    
        @Autowired
        private OauthClientDetailsDao oauthClientDetailsDao;
    
        @Test
        public void ClientInsert()
        {
            Set<String> resources = new HashSet<>();
            resources.add("resource1");resources.add("all");
    
            OauthClientDetails oauthClientDetails = new OauthClientDetails();
            oauthClientDetails.setClientId("client1");
            oauthClientDetails.setClientSecret("123456");
            oauthClientDetails.setResourceIds(resources);
    
            OauthClientDetails oauthClientDetails1 = oauthClientDetailsDao.save(oauthClientDetails);
    
            System.out.println(oauthClientDetails1);
        }
    
        @Test
        public void ClientQuery()
        {
            String clientId = "client1";
            OauthClientDetails oauthClientDetails = oauthClientDetailsDao.findById(clientId).orElse(null);
            System.out.println(oauthClientDetails);
        }
    }

    7. 可能的一些问题及解决方式.

    1.  添加数据(带一对多关系)时正常,但是查询的时候抛出异常如下
      org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.rurjs.starter.config.sso.domain.OauthClientDetails.resourceIds, could not initialize proxy - no Session
      
          at org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:606)
          at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:218)
          at org.hibernate.collection.internal.AbstractPersistentCollection.readSize(AbstractPersistentCollection.java:162)
          at org.hibernate.collection.internal.PersistentSet.size(PersistentSet.java:168)
          at java.base/java.util.HashSet.<init>(HashSet.java:119)
          at com.rurjs.starter.config.sso.domain.OauthClientDetails.getResourceIds(OauthClientDetails.java:66)
          at com.rurjs.starter.config.sso.domain.OauthClientDetails.toString(OauthClientDetails.java:18)
          at java.base/java.lang.String.valueOf(String.java:2951)
          at java.base/java.io.PrintStream.println(PrintStream.java:897)
          at com.rurjs.starter.RurjsStarterApplicationTests.ClientQuery(RurjsStarterApplicationTests.java:87)
          at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
          at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
          at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
          at java.base/java.lang.reflect.Method.invoke(Method.java:566)
          at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:675)
          at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
          at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:125)
          at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:132)
          at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:124)
          at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:74)
          at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115)
          at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105)
          at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:104)
          at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:62)
          at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:43)
          at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:35)
          at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104)
          at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98)
          at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$6(TestMethodTestDescriptor.java:202)
          at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
          at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:198)
          at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:135)
          at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:69)
          at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:135)
          at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
          at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
          at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
          at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
          at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
          at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
          at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
          at java.base/java.util.ArrayList.forEach(ArrayList.java:1540)
          at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
          at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139)
          at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
          at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
          at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
          at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
          at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
          at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
          at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
          at java.base/java.util.ArrayList.forEach(ArrayList.java:1540)
          at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
          at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139)
          at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
          at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
          at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
          at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
          at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
          at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
          at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
          at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:32)
          at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
          at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:51)
          at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:229)
          at org.junit.platform.launcher.core.DefaultLauncher.lambda$execute$6(DefaultLauncher.java:197)
          at org.junit.platform.launcher.core.DefaultLauncher.withInterceptedStreams(DefaultLauncher.java:211)
          at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:191)
          at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:128)
          at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:74)
          at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
          at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
          at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)

      解决方式:在实体类中 给有一对多关系的属性(如 resourceIds )上添加注解 @Fetch(FetchMode.JOIN);无该注解和注解为 @Fetch(FetchMode.SUBSELECT)或 @Fetch(FetchMode.SELECT)时,都会抛出该异常,按异常信息来说,解决懒加载问题也行,题主未并未使用 解决懒加载的方式解决该异常。

  • 相关阅读:
    python前端之css
    前端开发
    python前端开发工具篇
    python数据结构和算法2 顺序表和链表
    python数据结构和算法3 栈、队列和排序
    python数据结构和算法 二叉树
    python数据结构和算法1
    python18天-pycharm & 正则表达式
    Head First Servlets & JSP 学习笔记 第五章 —— 作为Web应用
    Head First Servlets & JSP 学习笔记 第四章 —— 作为Servlet
  • 原文地址:https://www.cnblogs.com/tu13/p/java_springboot_jpa_entity.html
Copyright © 2020-2023  润新知