环境:
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. 可能的一些问题及解决方式.
- 添加数据(带一对多关系)时正常,但是查询的时候抛出异常如下
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)时,都会抛出该异常,按异常信息来说,解决懒加载问题也行,题主未并未使用 解决懒加载的方式解决该异常。