首页 > 解决方案 > 在 Spring Boot 中使用 JPA 保存时,有没有办法获得“刷新”保存的实体?

问题描述

首先,我不确定这是缓存请求还是不填充字段。

我有一个名为 的实体CmsRegions,其中包含以下内容:

public class CmsRegions extends Model implements Serializable {
       
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Basic(optional = false)
    @Column(name = "id")
    private Integer id;
    
    @Basic(optional = false)
    @NotNull
    @Size(min = 1, max = 100)
    @Column(name = "name")
    private String name;
    
    @Lob
    @Size(max = 65535)
    @Column(name = "description")
    private String description;
    
    @Size(max = 2)
    @Column(name = "lang")
    private String lang;
    
    @Size(max = 2)
    @Column(name = "locale")
    private String locale;
    
    @Basic(optional = false)
    @NotNull
    @Column(name = "is_active")
    private short isActive;
    
    @Column(name = "parent_id")
    private Integer parentId;
        
    @Basic(optional = false)
    @Column(name = "created", insertable = false, updatable = false)
    @Temporal(TemporalType.TIMESTAMP)
    private Date created;
    
    @Basic(optional = false)
    @Column(name = "modified", insertable = false, updatable = false)
    @Temporal(TemporalType.TIMESTAMP)
    private Date modified;


    ...getters and setters etc...
}

我有基本的存储库调用来检索实体:

@NoRepositoryBean
public interface BaseCmsRepository<T extends Serializable> extends JpaRepository<T, Long> {
    
    @Query("SELECT a FROM #{#entityName} a WHERE a.id = :id")
    List<T> getById(
            @Param("id") Integer id
    );
    

当我保存实体时,它会很好地保存到下表中的数据库中:

CREATE TABLE `cms_regions` (
  `id` int unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(100) NOT NULL,
  `description` text,
  `lang` char(2) DEFAULT NULL,
  `locale` char(2) DEFAULT NULL,
  `is_active` tinyint unsigned NOT NULL DEFAULT '0',
  `parent_id` int unsigned DEFAULT NULL,
  `created` datetime DEFAULT CURRENT_TIMESTAMP,
  `modified` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=32 DEFAULT CHARSET=utf8;

和字段按预期设置得很好createdmodified但是我从保存操作中获得的结果实体具有NULL创建日期和修改日期的值。

我运行了一个测试 - 我的最后一个插入 ID 是 31,所以我将以下代码添加到我的控制器中:

    cmsService.saveRegion(region); // save entity

    CmsRegions  testreg1 = cmsService.getRegion(1);
    CmsRegions  testreg2 = cmsService.getRegion(region.getId());
    CmsRegions  testreg3 = cmsService.getRegion(30);
    CmsRegions  testreg4 = cmsService.getRegion(32);  // currently saved entity new ID (32)

执行此操作时 - testreg1 如希望的那样将创建和修改的日期作为 Date 对象包含在内。testreg2 包含空值(此时 region.getId() = 32)。testreg3 包含创建和修改的日期对象。

最终值 testreg4 也是 NULL。更重要的是,下次我运行它时,testreg4 中包含了createdand的值modified。但是下一次迭代,testreg2 中的 (33) 再次为 NULL。

调试中的数据图像

我不知道这是缓存问题还是什么。似乎如果我尝试在调用完成之前提取数据库值 - 即使数据现在在数据库中(通过断点确认) - 结果字段始终为空。下一次运行,它们被填充。

为什么?我需要做什么才能获得这些值?

标签: javamysqlspringspring-bootjpa

解决方案


在任何类似接口上使用JpaRepository#save或此方法保存时,将返回数据库中的实体。你可以使用它。它最常用于填充生成的 id:

assertNull(entity.getId());
entity = entityRepository.save(entity);
assertNotNull(entity.getId());

当其他进程正在更改数据并且不刷新持久性上下文时,情况会更加复杂。那时将需要另一个查询。你可以通过使用EntityManager#refresh和传递你想从数据库中“重新获取”的实体来解决这个问题。目前我不知道该机制是否存在于 spring-data-jpa 中。


推荐阅读