我是一名 Spring Boot 初学者,在使生成的值正常工作方面遇到了麻烦。我希望让数据库 (Postgres) 在插入行时生成一个时间戳列,而不是让 Spring 生成它,但问题是 Spring 在执行更新时似乎不会从数据库中选择时间戳。
当我添加新实体时save()
,它会顺利插入数据库,并生成一个时间戳并返回给 Spring;一切正常。当我尝试访问find()
现有实体时,也会返回时间戳,所以这也很好。但是,当我尝试更新现有实体时,Spring 不会访问数据库中的时间戳,而是为相应字段返回 null。
这是实体定义:
import jakarta.persistence.*
import org.hibernate.annotations.CurrentTimestamp
import org.hibernate.generator.EventType
import java.time.OffsetDateTime
@Entity(name = "users")
@Table(name = "users")
data class User(
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
val id: Int?,
val name: String,
@Column(name = "date_created")
@CreationTimestamp(source = SourceType.DB)
val dateCreated: OffsetDateTime?,
)
假设数据库已经有了一行,例如1 | 2025-01-02 02:03:04 | user1
。像这样的 PUT 请求{ name: "new user" }
将更新name
数据库中的字段而不更改时间戳,但 JPA 返回的更新实体将是{ id: 1, name: "new user", dateCreated: null }
。我不确定这是为什么。我知道 JPA 在 INSERTing 新行时会执行额外的 SELECT 以获取 Postgres 生成的时间戳,但我不明白为什么它在 UPDATEing 时不直接获取已经存在的时间戳。
为了完整性,控制器和服务类:
import com.example.hello.User
import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.*
@RestController
@RequestMapping(path = ["/users"])
class UserController(private val userService: UserService) {
@PostMapping
fun createStaff(@RequestBody user: User): ResponseEntity<User> {
val createdUser = userService.create(user)
return ResponseEntity(createdUser, HttpStatus.CREATED)
}
@PutMapping(path = ["/{id}"])
fun updateUser(@PathVariable("id") id: Int, @RequestBody user: User): ResponseEntity<User> {
val updatedUser = userService.update(id, user)
return ResponseEntity(updatedUser, HttpStatus.OK)
}
@GetMapping(path = ["/{id}"])
fun readUser(@PathVariable("id") id: Int): ResponseEntity<User> {
val user = userService.get(id)
return user?.let { ResponseEntity.ok(it) } ?: ResponseEntity(HttpStatus.NOT_FOUND)
}
}
import com.example.hello.User
import com.example.hello.UserRepository
import org.springframework.data.repository.findByIdOrNull
import org.springframework.stereotype.Service
@Service
class UserService(private val userRepository: UserRepository) {
fun create(user: User): User {
return userRepository.save(user)
}
fun update(id: Int, user: User): User {
val userWithId = user.copy(id = id)
return userRepository.save(userWithId)
}
fun get(id: Int): User? {
return userRepository.findByIdOrNull(id)
}
}
当你调用 PUT api 时,你不仅传入
name
主体,而且传入请求User
类型,因此 Spring 会明白你的主体是:在您的
update
方法中,您只复制 id =>dateCreated
still 的对象null
。这就是为什么当它保存到数据库时,该date_created
列是null
您可以先使用查询数据库中的对象
id
,更改name
字段,然后将其保存回来。或者您可以添加
updatable = false
以确保date_created
不会被更新。由于该字段被标记为可空。并且 update 不会对 createTimeStamp 执行任何操作,因此它获取的是空数据。
您可以将您的代码更改为以下内容。