为了最初用数据填充数据库,我创建了实体实例并编写了一个应该将它们保存在数据库中的服务类。
以非常简单的方式,我的模型由三个类A,B和C组成。类A和B的实例都引用(相同)C的实例(用@ManyToOne
注释):
a1 -> c1
a2 -> c2
a3 -> c1
b1 -> c1
b2 -> c2
对于A和B,我使用JpaRepositories
来表示持久性。
然后我尝试以编程方式保存我创建的实例:
@Transactional
public void save(A a1, A a2, A a3, B b1, B b2) {
aRepo.save(a1);
aRepo.save(a2);
aRepo.save(a3);
bRepo.save(b1);
bRepo.save(b2);
}
我在第三行得到一个异常(“传递给persist:C”的分离实体),因为实例c1已经保存在第一行。
我该如何避免?我认为用@Transactional
在我的服务中标记我的保存方法已经足够了,但显然不是。
当然我可以写
aRepo.save(Arrays.asList(a1, a2, a3));
bRepo.save(Arrays.asList(b1, b2));
但这只会改变我的问题,因为当引用已保存的c1的b1应该被保存时,异常会发生在第二行。
如何在不获取异常的情况下保存我在一个方法中创建的数据结构?
以下是代码的其余部分:
@Entity
public class A {
@Id
@GeneratedValue
@Access(AccessType.FIELD)
private Long id;
@ManyToOne(cascade = CascadeType.ALL)
@Access(AccessType.FIELD)
private C c;
public A(C c) {
this.c = c;
}
public C getC() {
return c;
}
}
B类看起来完全一样,C类只包含ID参数。
实例是在测试用例中创建的:
public class DBTest extends AbstractH2TestCase {
@Test
public void testDataStorage() {
final AbstractApplicationContext context = new AnnotationConfigApplicationContext(DBTest.class);
try {
final PersistService persistService = context.getBean(PersistService.class);
C c1 = new C();
C c2 = new C();
A a1 = new A(c1);
A a2 = new A(c2);
A a3 = new A(c1);
B b1 = new B(c1);
B b2 = new B(c2);
persistService.save(b1, b2, a1, a2, a3);
} finally {
context.close();
}
}
}
测试的超类我在网上的某个地方找到并修改了一下:
@Configuration
@ComponentScan(basePackageClasses = A.class)
@EnableJpaRepositories
public class AbstractH2TestCase {
public AbstractH2TestCase() {
super();
}
@Bean
public DataSource dataSource() {
return new EmbeddedDatabaseBuilder().setType(H2).build();
}
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource,
JpaVendorAdapter jpaVendorAdapter) {
final LocalContainerEntityManagerFactoryBean lef = new LocalContainerEntityManagerFactoryBean();
lef.setDataSource(dataSource);
lef.setJpaVendorAdapter(jpaVendorAdapter);
final String thisPackageAndSubpackages = this.getClass().getPackage().getName();
lef.setPackagesToScan(thisPackageAndSubpackages);
return lef;
}
@Bean
public JpaVendorAdapter jpaVendorAdapter() {
final HibernateJpaVendorAdapter hibernateJpaVendorAdapter = new HibernateJpaVendorAdapter();
hibernateJpaVendorAdapter.setShowSql(false);
hibernateJpaVendorAdapter.setGenerateDdl(true);
hibernateJpaVendorAdapter.setDatabase(Database.H2);
return hibernateJpaVendorAdapter;
}
@Bean
public PlatformTransactionManager transactionManager() {
return new JpaTransactionManager();
}
}
如果你想要一个正在运行的代码版本 - 我在这里查了一下:
https://github.com/BernhardBln/stackexchange
这是一个maven项目。
答案 0 :(得分:2)
你错过了
@EnableTransactionManagement
在你的DBTest-Class
上 @EnableTransactionManagement
public class DBTest extends AbstractH2TestCase {
答案 1 :(得分:0)
您的@Transactional
注释没用,因为您没有使用容器(如J2EE或Spring)来实际确定该方法必须在一个事务中运行,因此每次调用save()
都是一个交易,这就是你获得一个独立实体的原因。
尝试在this example或the docs中使用Spring。