使用@Transactional 时未检索到数据库默认字段
Database default field not retrieved when using @Transactional
我有以下简单实体 FileRegistry:
@Getter
@Setter
@Entity
@ToString
@Table(name = "file_store")
public class FileRegistry {
@Id
private String name;
/**
* Creation timestamp of the registry
* This value is automatically set by database, so setter method
* has been disabled
*/
@Setter(AccessLevel.NONE)
@Column(insertable = false, updatable = false)
private LocalDateTime creationDate;
}
以下 FileRepository DAO:
@Repository
public interface FileRepository extends JpaRepository<FileRegistry, String> { }
和以下 Spring 启动测试:
@SpringBootTest(classes=PersistTestConfig.class, properties = { "spring.config.name=application,db"})
@ActiveProfiles("test")
@Transactional
public class FileRepositoryTest {
@Autowired
FileRepository fileRepository;
@Test
void insertFileTest() {
assertNotNull(fileRepository, "Error initializing File repository");
// Check registry before insertion
List<FileRegistry> allFiles = fileRepository.findAll();
assertNotNull(allFiles, "Error retrieving files from registry");
assertThat(allFiles.size(), is(0));
// Insert file
FileRegistry fileRegistry = new FileRegistry();
fileRegistry.setName("Test");
fileRepository.save(fileRegistry);
// Check that the insertion was successful
allFiles = fileRepository.findAll();
assertNotNull(allFiles, "Error retrieving files from registry");
assertThat(allFiles.size(), is(1));
assertEquals("File registry name mismatch", "Test", allFiles.get(0).getName());
System.out.println(allFiles.get(0));
}
}
持久化配置class定义如下:
@Configuration
@EnableAutoConfiguration
@EnableTransactionManagement
@EnableJpaRepositories
public class PersistTestConfig {
}
H2中的tablefile_store定义为:
CREATE TABLE file_store (name VARCHAR NOT NULL, creation_date TIMESTAMP(3) DEFAULT NOW() NOT NULL, CONSTRAINT file_store_pk PRIMARY KEY (name));
一切正常,除了当我在测试级别使用 @Transactional
时(主要是为了受益于回滚,即每次测试的数据库清理),为 creationDate 字段获取了一个空值:
FileRegistry(name=Test, creationDate=null)
当我从测试 class 中删除 @Transactional
时,获取的值包含 H2 计算的日期:
FileRegistry(name=Test, creationDate=2019-03-07T17:08:13.392)
我尝试手动刷新和合并实例,但无济于事。老实说,现在我有点迷失了 @Transactional
的真正工作原理,实际上阅读文档并检查代码,底层的 JpaRepository
实现 (SimpleJpaRepository
) 被注释了作为 @Transactional(readOnly = true)
。
如果能对此问题提供一点帮助,我们将不胜感激。
好的,明白了。
只需发出刷新 entityManager.refresh(allFiles.get(0));
即可解决问题。
我还在实体 creationDate
字段中使用 Hibernate 的 @Generated(INSERT)
特定 annotation 进行了测试,它也工作正常。
顺便说一下,我最终决定放弃这个东西,转而使用 Spring Data 的 JpaAuditing 功能,并使用 @CreatedDate
注释来注释字段来填充值,而不是依赖数据库日期(顺便说一下,在生产方面,您可能不应该依赖数据库时间)。对我来说,这更像是 "correct" 和灵活的做事方式。
我有以下简单实体 FileRegistry:
@Getter
@Setter
@Entity
@ToString
@Table(name = "file_store")
public class FileRegistry {
@Id
private String name;
/**
* Creation timestamp of the registry
* This value is automatically set by database, so setter method
* has been disabled
*/
@Setter(AccessLevel.NONE)
@Column(insertable = false, updatable = false)
private LocalDateTime creationDate;
}
以下 FileRepository DAO:
@Repository
public interface FileRepository extends JpaRepository<FileRegistry, String> { }
和以下 Spring 启动测试:
@SpringBootTest(classes=PersistTestConfig.class, properties = { "spring.config.name=application,db"})
@ActiveProfiles("test")
@Transactional
public class FileRepositoryTest {
@Autowired
FileRepository fileRepository;
@Test
void insertFileTest() {
assertNotNull(fileRepository, "Error initializing File repository");
// Check registry before insertion
List<FileRegistry> allFiles = fileRepository.findAll();
assertNotNull(allFiles, "Error retrieving files from registry");
assertThat(allFiles.size(), is(0));
// Insert file
FileRegistry fileRegistry = new FileRegistry();
fileRegistry.setName("Test");
fileRepository.save(fileRegistry);
// Check that the insertion was successful
allFiles = fileRepository.findAll();
assertNotNull(allFiles, "Error retrieving files from registry");
assertThat(allFiles.size(), is(1));
assertEquals("File registry name mismatch", "Test", allFiles.get(0).getName());
System.out.println(allFiles.get(0));
}
}
持久化配置class定义如下:
@Configuration
@EnableAutoConfiguration
@EnableTransactionManagement
@EnableJpaRepositories
public class PersistTestConfig {
}
H2中的tablefile_store定义为:
CREATE TABLE file_store (name VARCHAR NOT NULL, creation_date TIMESTAMP(3) DEFAULT NOW() NOT NULL, CONSTRAINT file_store_pk PRIMARY KEY (name));
一切正常,除了当我在测试级别使用 @Transactional
时(主要是为了受益于回滚,即每次测试的数据库清理),为 creationDate 字段获取了一个空值:
FileRegistry(name=Test, creationDate=null)
当我从测试 class 中删除 @Transactional
时,获取的值包含 H2 计算的日期:
FileRegistry(name=Test, creationDate=2019-03-07T17:08:13.392)
我尝试手动刷新和合并实例,但无济于事。老实说,现在我有点迷失了 @Transactional
的真正工作原理,实际上阅读文档并检查代码,底层的 JpaRepository
实现 (SimpleJpaRepository
) 被注释了作为 @Transactional(readOnly = true)
。
如果能对此问题提供一点帮助,我们将不胜感激。
好的,明白了。
只需发出刷新 entityManager.refresh(allFiles.get(0));
即可解决问题。
我还在实体 creationDate
字段中使用 Hibernate 的 @Generated(INSERT)
特定 annotation 进行了测试,它也工作正常。
顺便说一下,我最终决定放弃这个东西,转而使用 Spring Data 的 JpaAuditing 功能,并使用 @CreatedDate
注释来注释字段来填充值,而不是依赖数据库日期(顺便说一下,在生产方面,您可能不应该依赖数据库时间)。对我来说,这更像是 "correct" 和灵活的做事方式。