当前位置: 首页 > 知识库问答 >
问题:

针对H2的spring数据JPA查询失败,未找到架构

巫马劲
2023-03-14

我有一个名为user的实体,如下所示:

    @Entity
    @JsonSerialize(using = UserSerializer.class)
    @Table(uniqueConstraints={@UniqueConstraint(columnNames = {"username"})})
    public class User implements UserDetails {

        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;

        @Column(unique = true, updatable = false)
        private String username;

        private String password;

        @OneToOne(cascade={CascadeType.ALL})
        @JoinColumn(name = "person_id")
        private Person person;

        @OneToOne(cascade={CascadeType.PERSIST})
        @JoinColumn(name = "maintainer_id")
        private Maintainer maintainer;

        @ManyToMany(cascade={CascadeType.PERSIST, CascadeType.MERGE}, fetch = 
 FetchType.EAGER)
        @JoinTable(name = "user_role",
                joinColumns = @JoinColumn(name = "user_id",
                        nullable = false, updatable = false),
                inverseJoinColumns = @JoinColumn(name = "role_id",
                        nullable = false, updatable = false))
        private Set<Role> roles;

        public User() {
        }

        public User(String username, String password, Person person, Maintainer maintainer, Set<Role> roles) {
            this.username = username;
            this.password = password;
            this.person = person;
            this.maintainer = maintainer;
            this.roles = roles;
        }

        // builder inner class omitted 

        // getters and setters omitted

        // equals, hashCode and toString omitted    
    }

我还有一个用户摘要类,它旨在返回以进行分页和排序:

public class UserRow {
    private Long id;
    private String username;
    private String firstName;
    private String lastName;
    private Set<Role> roles;
    private String role;
    private Long maintainerId;
    private String maintainerName;

    public static UserRow of(Long id, String username, String firstName, String lastName, Set<Role> roles, Long maintainerId, String maintainerName) {
        UserRow userRow = new UserRow();

        userRow.id = id;
        userRow.username = username;
        userRow.firstName = firstName;
        userRow.lastName = lastName;
        userRow.roles = roles;
        userRow.maintainerId = maintainerId;
        userRow.maintainerName = maintainerName;


        return userRow;
    }

// getters, setters, equals, hashCode and toString omitted
}

这与所有其他实体一起似乎在h2中很好地初始化,从控制台我看到如下内容:

create table user (
   id bigint generated by default as identity,
    password varchar(255),
    username varchar(255),
    maintainer_id bigint,
    person_id bigint,
    primary key (id)
)

create table user_role (
   user_id bigint not null,
    role_id bigint not null,
    primary key (user_id, role_id)
)

甚至:

alter table user 
   add constraint UK_sb8bbouer5wak8vyiiy4pf2bx unique (username)

现在,我已经设置了控制器、服务和存储库...

控制器:

@Secured("ROLE_ADMIN")
@GetMapping(value = {"/users", "/users/maintainers/{mid}"}, produces = "application/json")
@ResponseStatus(value = HttpStatus.OK)
Response<List<User>> getPagedUsers(
        @PathVariable("mid") Optional<Long> maintainerId,
        @PageableDefault(page = DEFAULT_PAGE_NUMBER, size = DEFAULT_PAGE_SIZE)
        @SortDefault.SortDefaults({
                @SortDefault(sort = "username", direction = Sort.Direction.ASC),
                @SortDefault(sort = "p.lastName", direction = Sort.Direction.ASC)
        }) Pageable pageable) {

    Page<UserRow> users;
    if (maintainerId.isPresent()) {
        users = userService.findSortedSummaryByMaintainer(maintainerId.get(), pageable);
    } else {
        users = userService.findSortedSummary(pageable);
    }

    return Response.of(users);
}

服务:公共接口UserService扩展了UserDetailsService{

    Page<UserRow> findSortedSummary(Pageable pageable);

    @Service
    class UserServiceImpl implements UserService {

        private static final Logger LOG = LoggerFactory.getLogger(UserService.class);

        @Autowired
        BCryptPasswordEncoder bCryptPasswordEncoder;

        @Autowired
        UserRepository userRepository;

        @Autowired
        RoleRepository roleRepository;

        public Page<UserRow> findSortedSummary(Pageable pageable) {

            Page<UserRow> userPage = userRepository.findSortedSummary(pageable.next());

            userPage.forEach(us -> us.setRole(findMostPrivilegedRole(us.getRoles())));

            return userPage;
        }

    }

}

存储库:公共界面UserRepository扩展了JpaRepository{

    @Query(value = "select u.username, p.firstName, p.lastName, u.roles, m.id, m.name "
                    + "from User u "
                    + "inner join u.person p "
                    + "inner join u.maintainer m",
            countQuery = "select count(*) "
                    + "from User u "
                    + "inner join u.person p "
                    + "inner join u.maintainer m",
            nativeQuery = true)
    Page<UserRow> findSortedSummary(Pageable pageable);

}

最后,我用以下方法来测试所有这些:

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@ActiveProfiles("embedded")
@AutoConfigureMockMvc
public class UserListControllerFunctionalTest {

    @Autowired
    private WebApplicationContext context;

    @Autowired
    private MockMvc mvc;

    @Autowired
    UserService userService;

    List<User> franks;

    @Before
    public void setup() {
        mvc = MockMvcBuilders
                .webAppContextSetup(context)
                .apply(springSecurity())
                .build();

        franks = ModelFixtures.createFrankAndCohorts();
        franks = userService.createAll(franks);
    }

    @Test
    public void getListOfUsersWithRootSuccess() throws Exception {

        mvc.perform(get("/api/users").header(AUTHORIZATION_HEADER, "Bearer " + ModelFixtures.ROOT_JWT_TOKEN))
                .andDo(print())
                .andExpect(status().isOk());

    }

    @After
    public void tearDown() {
        userService.deleteAll(franks);
    }

}

所有的Spring安全材料都经过了广泛的测试和工作。

当测试调用控制器、服务和存储库时,我在存储库中遇到故障:

原因:组织。h2.jdbc。JdbcSQLException:未找到架构“U”;SQL语句:从用户u内部加入u.person p内部加入u.maintainer m order by u.username asc,p.lastName asc limit中选择u.username、p.firstName、p.lastName、u.roles、m.id、m.name?抵消[90079-197]组织。h2.消息。数据库异常。位于org的getJdbcSQLException(DbException.java:357)。h2.消息。数据库异常。get(DbException.java:179)位于org。h2.消息。数据库异常。get(DbException.java:155)

到目前为止,我发现将“User”这样的表与“u”这样的字母混叠是可以的,h2(和MySQL)中用户的内部表是“users”,因此“User”没有保留。所以我看不出这里有什么问题。有人能帮忙吗?

相关依存关系:

|    +--- org.hibernate:hibernate-core:5.2.17.Final
|    |    +--- org.jboss.logging:jboss-logging:3.3.1.Final -> 3.3.2.Final
|    |    +--- org.hibernate.javax.persistence:hibernate-jpa-2.1-api:1.0.0.Final
|    |    +--- org.javassist:javassist:3.22.0-GA
|    |    +--- antlr:antlr:2.7.7
|    |    +--- org.jboss:jandex:2.0.3.Final
|    |    +--- com.fasterxml:classmate:1.3.0 -> 1.3.4
|    |    +--- dom4j:dom4j:1.6.1
|    |    \--- org.hibernate.common:hibernate-commons-annotations:5.0.1.Final
|    |         \--- org.jboss.logging:jboss-logging:3.3.0.Final -> 3.3.2.Final
|    +--- javax.transaction:javax.transaction-api:1.2
|    +--- org.springframework.data:spring-data-jpa:2.0.7.RELEASE
|    |    +--- org.springframework.data:spring-data-commons:2.0.7.RELEASE
|    |    |    +--- org.springframework:spring-core:5.0.6.RELEASE (*)
|    |    |    +--- org.springframework:spring-beans:5.0.6.RELEASE (*)
|    |    |    \--- org.slf4j:slf4j-api:1.7.25
|    |    +--- org.springframework:spring-orm:5.0.6.RELEASE
|    |    |    +--- org.springframework:spring-beans:5.0.6.RELEASE (*)
|    |    |    +--- org.springframework:spring-core:5.0.6.RELEASE (*)
|    |    |    +--- org.springframework:spring-jdbc:5.0.6.RELEASE (*)
|    |    |    \--- org.springframework:spring-tx:5.0.6.RELEASE (*)
|    |    +--- org.springframework:spring-context:5.0.6.RELEASE (*)
|    |    +--- org.springframework:spring-aop:5.0.6.RELEASE (*)
|    |    +--- org.springframework:spring-tx:5.0.6.RELEASE (*)
|    |    +--- org.springframework:spring-beans:5.0.6.RELEASE (*)
|    |    +--- org.springframework:spring-core:5.0.6.RELEASE (*)
|    |    \--- org.slf4j:slf4j-api:1.7.25

编辑-删除nativeQuery=true部分修复了“未找到模式”问题-本机查询必须表示按字面处理的所有元素。

然而,问题变成了:

Caused by: 

org.h2.jdbc.JdbcSQLException: Syntax error in SQL statement "

SELECT 
USER0_.USERNAME AS COL_0_0_, 
PERSON1_.FIRST_NAME AS COL_1_0_, 
PERSON1_.LAST_NAME AS COL_2_0_, 
.[*] AS COL_3_0_, 
MAINTAINER2_.ID AS COL_4_0_, 
MAINTAINER2_.NAME AS COL_5_0_, 
ROLE4_.ID AS ID1_17_, 
ROLE4_.DESCRIPTION AS DESCRIPT2_17_, 
ROLE4_.ROLE_NAME AS ROLE_NAM3_17_ 
FROM USER USER0_ 
INNER JOIN PERSON PERSON1_ ON USER0_.PERSON_ID=PERSON1_.ID 
INNER JOIN MAINTAINER MAINTAINER2_ ON USER0_.MAINTAINER_ID=MAINTAINER2_.ID 
INNER JOIN USER_ROLE ROLES3_ ON USER0_.ID=ROLES3_.USER_ID 
INNER JOIN ROLE ROLE4_ ON ROLES3_.ROLE_ID=ROLE4_.ID 
ORDER BY USER0_.USERNAME ASC, PERSON1_.LAST_NAME ASC LIMIT ? OFFSET ? "; 

expected "*, NOT, EXISTS, INTERSECTS, SELECT, FROM, WITH"; 

不确定在这里“预期”的东西预期在哪里。。。

共有1个答案

拓拔辰钊
2023-03-14

好的,我已经解决了。

这一切都在查询结构中。所以正确的jpql方法是:

@Query(value = "select new au.com.avmaint.api.access.model.UserRow(u.id, u.username, p.firstName, p.lastName, m.id, m.name) "
                + "from User u "
                + "inner join u.person p "
                + "inner join u.maintainer m",
        countQuery = "select count(*) "
                + "from User u "
                + "inner join u.person p "
                + "inner join u.maintainer m")
Page<UserRow> findSortedSummary(Pageable pageable);

如果您打算返回一个非映射类(UserRow),那么您需要使用构造函数表示法。您也不能在SELECT子句中返回集合(user.roles),所以我必须在另一个查询中获取角色。这在服务层中很容易完成(请参阅forper块中的第一行):

    public Page<UserRow> findSortedSummary(Pageable pageable) {

        Page<UserRow> userPage = userRepository.findSortedSummary(pageable.next());

        userPage.forEach(row -> {
            User user = userRepository.findById(row.getId()).orElseThrow(() -> new UsernameNotFoundException("User not found: " + row.getUsername()));
            row.setRoles(user.getRoles());
            row.setRole(findMostPrivilegedRole(user.getRoles()));
        });

        return userPage;
    }

在这里,我使用了一个标准的Repository findById调用来按id返回单个用户并以这种方式获取角色。在单个查询中获取角色当然会很好,但JPQL只是没有那个级别的功能。

最后,我可能会说,除了最琐碎的领域示例(基本上是博客化的领域示例)之外,任何内容的分页和排序实际上都是相当棘手和复杂的。一旦我真正解决了这些问题,我会在博客上写一些真正有用的东西。

 类似资料:
  • 我创建了查询来根据日期间隔和房间类型搜索酒店的可用房间。当我运行此查询时,我得到以下错误: 组织。h2.jdbc。JdbcSQLException:未找到模式“R”;SQL语句: 有什么问题吗? 公共接口RoomRepository扩展JpaRepository{

  • 我将Spring boot JPA实体定义为: 上述方法在DB2中效果良好,但在H2中效果不佳。 在application.properties,我有以下设置: 当我做maven的时候 原因:org。h2。jdbc。JdbcSQLSyntaxErrorException:未找到架构“MYSCHEMA”;SQL语句:公共类CarEntity实现可序列化的{。。。 我希望在H2上创建模式,因为我在我的

  • 实现类 我正在尝试使用mockito为我的分页代码编写Junit测试用例,但它失败了,因为它期望方法的返回类型为Page.但是我返回客户列表。 我得到以下错误 如果您不确定为什么会出现上述错误,请继续阅读。由于语法的性质,可能会出现上述问题,因为: > 在错误编写的多线程测试中可能会发生此异常。有关并发测试的限制,请参阅莫基托常见问题解答。 间谍使用当(间谍.foo()).then()语法进行存根

  • 在我的测试项目中,由于以下错误,Spring容器无法创建扩展JPararePository的bean。 原因:org.springframework.beans.factory.BeanCreationException:创建名为“sr svcInfomtrRepository”的bean时出错:FactoryBean在创建对象时引发异常;嵌套异常为java.lang.NosuchMethoder

  • 我有3个实体在我的数据库。实体A具有主密钥PK-A,实体B具有主密钥PK-B,实体C具有主密钥PK-C。 实体A与实体B具有1对多关系,实体B与实体C具有1对多关系 我想在Spring Data JPA中基于PK-A(实际上是实体B中的外键)查询实体C。有可能吗? 但这行不通。还有什么建议我可以试试吗?

  • 我想列一份订单,比如 这是我的密码 我使用的是Java Spring Boot和Spring Data JPA,我遇到了如下错误 你们能帮帮我吗!我想我在《findAllOrderBycreateDateDesc》中错了。谢谢对不起我的英语。这是我第一次发布我的问题。除息的