web-dev-qa-db-ja.com

MySQLでのSpring Boot R2DBC-例外:テーブルが見つかりません

私はString Bootとバックエンド開発(多分3日以内)に非常に慣れていないので、構築したい =)REST APIは、さまざまなクライアントから使用します。

そこで、/registerというエンドポイントを持つ簡単なデモアプリから始めました。 JSON文字列にusernamepasswordを付けて投稿し、存在しない場合は新しいユーザーを作成します。

私はJPAHSQLDBと一緒に使用していて、メモリ上で永続的に機能しました。でも最近はAndroidに慣れているのでRxJavaを使いたかったので、MySQLR2DBCに切り替えました。

MySQLサーバーはポート3306で正常に動作しており、アプリはlocalhost:8080でPostManを使用してテストされました

この問題は、usersテーブルにクエリを実行するかエンティティを挿入しようとすると発生し、次のようになります。

{
    "timestamp": "2020-03-22T11:54:43.466+0000",
    "status": 500,
    "error": "Internal Server Error",
    "message": "execute; bad SQL grammar [UPDATE user_entity SET username = $1, password = $2 WHERE user_entity.id = $3]; nested exception is io.r2dbc.spi.R2dbcBadGrammarException: [42102] [42S02] Table \"USER_ENTITY\" not found; SQL statement:\nUPDATE user_entity SET username = $1, password = $2 WHERE user_entity.id = $3 [42102-200]",
    "path": "/register"
}

これが例外の完全な logfile です。

私は何時間も解決策を探していましたが、どこにも見つからないようですので、ここで見つけられることを願っています。

プロジェクトを分解して、ソリューションを見つけやすくしましょう。

1。データベース:

enter image description here

2。 application.properties:

logging.level.org.springframework.data.r2dbc=DEBUG
spring.datasource.url=jdbc:mysql://localhost:3306/demodb
spring.datasource.username=root
spring.datasource.password=root

3。 DatabaseConfiguration:

@Configuration
@EnableR2dbcRepositories
class DatabaseConfiguration : AbstractR2dbcConfiguration() {

    override fun connectionFactory(): ConnectionFactory
         = ConnectionFactories.get(
                builder().option(DRIVER, "mysql")
                    .option(Host, "localhost")
                    .option(USER, "root")
                    .option(PASSWORD, "root") 
                    .option(DATABASE, "demodb")
                    .build()
        )


}

4。 RegistrationController:

@RequestMapping("/register")
@RestController
class RegistrationController @Autowired constructor(private val userService: UserService) {

    @PostMapping
    fun login(@RequestBody registrationRequest: RegistrationRequest): Single<ResponseEntity<String>>
        = userService.userExists(registrationRequest.username)
            .flatMap { exists -> handleUserExistance(exists, registrationRequest) }
    
    private fun handleUserExistance(exists: Boolean, registrationRequest: RegistrationRequest): Single<ResponseEntity<String>> 
        = if (exists) Single.just(ResponseEntity("Username already exists. Please try an other one", HttpStatus.CONFLICT))
            else userService.insert(User(registrationRequest.username, registrationRequest.password)).map { user ->
                ResponseEntity("User was successfully created with the id: ${user.id}", HttpStatus.CREATED)
            }
    
}

5。 UserService:

@Service
class UserService @Autowired constructor(override val repository: IRxUserRepository) : RxSimpleService<User, UserEntity>(repository) {

    override val converter: EntityConverter<User, UserEntity> = UserEntity.Converter

    fun userExists(username: String): Single<Boolean>
        = repository.existsByUsername(username)

}

6。 RxSimpleService:

abstract class RxSimpleService<T, E>(protected open val repository: RxJava2CrudRepository<E, Long>)  {

    protected abstract val converter: EntityConverter<T, E>

    open fun insert(model: T): Single<T>
        = repository.save(converter.fromModel(model))
            .map(converter::toModel)

    open fun get(id: Long): Maybe<T>
        = repository.findById(id)
            .map(converter::toModel)

    open fun getAll(): Single<ArrayList<T>>
        = repository.findAll()
            .toList()
            .map(converter::toModels)

    open fun delete(model: T): Completable
        = repository.delete(converter.fromModel(model))

}

7。 RxUserRepository:

@Repository
interface IRxUserRepository : RxJava2CrudRepository<UserEntity, Long> {

    @Query("SELECT CASE WHEN EXISTS ( SELECT * FROM ${UserEntity.TABLE_NAME} WHERE username = :username) THEN CAST(1 AS BIT) ELSE CAST(0 AS BIT) END")
    fun existsByUsername(username: String): Single<Boolean>

}

8。そして最後に、これが私のUserEntityです。

@Table(TABLE_NAME)
data class UserEntity(
        @Id
        val id: Long,
        val username: String,
        val password: String
)  {

        companion object {
            const val TABLE_NAME = "user_entity"
        }

        object Converter : EntityConverter<User, UserEntity> {

            override fun fromModel(model: User): UserEntity
                   = with(model) { UserEntity(id, username, password) }

            override fun toModel(entity: UserEntity): User
                   = with(entity) { User(id, username, password) }

        }
}

UserRegistrationRequestは、ユーザー名とパスワードを持つ単純なオブジェクトです。私が逃したものは何ですか?さらにコードが必要な場合はコメントを残してください。

4
Tamim Attafi

Hibernateがエンティティをマッピングするため、Hibernateがエンティティのテーブルと列を作成できるようにして、userEntityに注釈を付けて、再試行してください。

@Table(TABLE_NAME)
data class UserEntity(
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        val id: Long,
        @Column(name = "")
        val username: String,
        @Column(name = "")
        val password: String
)  
0
Akshay Jain

application.propertiesを設定する必要がありますspring.jpa.hibernate.ddl-autoプロパティ。

オプションは次のとおりです。

validate: validate the schema, makes no changes to the database.
update: update the schema.
create: creates the schema, destroying previous data.
create-drop: drop the schema when the SessionFactory is closed explicitly, typically when the application is stopped.
none: does nothing with the schema, makes no changes to the database
0
Fermi-4