我有针对MySQL实例或Oracle实例运行的集成测试。
在针对MySQL实例构建Maven项目时,测试正常。
这是表结构:
drop table if exists operator;
create table operator (
id bigint(20) unsigned not null auto_increment,
version int(10) unsigned not null,
name varchar(50),
unique key name (name),
description varchar(255),
operator_id varchar(50),
unique key operator_id (operator_id),
image varchar(255),
url varchar(255),
country_id bigint(20) unsigned not null,
primary key (id),
unique key id (id),
key country_id (country_id),
constraint operator_fk1 foreign key (country_id) references country (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
但是当相同的测试针对Oracle实例运行时,它会给我一个例外:
1. insert into operator (version, country_id, description, image, name, operator_id, url, id) values (0, 19, 'The SFR operator', 'sfr.jpg', 'SFR', NULL, 'sfr.fr', 10)
java.sql.SQLIntegrityConstraintViolationException: ORA-02291: integrity constraint (NITROPROJECT.OPERATOR_FK1) violated - parent key not found
这是表结构:
create table operator (
id number(10) not null,
version number(10) not null,
name varchar2(50),
constraint operator_u1 unique (name),
description varchar2(255),
operator_id varchar2(50),
constraint operator_u2 unique (operator_id),
image varchar2(255),
url varchar2(255),
country_id number(10) not null,
constraint operator_pk primary key (id),
constraint operator_fk1 foreign key (country_id) references country (id)
);
create sequence sq_id_operator increment by 1 start with 1 nomaxvalue nocycle cache 10;
create or replace trigger tr_id_inc_operator
before insert
on operator
for each row
declare
begin
if (:new.id is null)
then
select sq_id_operator.nextval into :new.id from dual;
end if;
end;
/
create table country (
id number(10) not null,
version number(10) not null,
code varchar2(4) not null,
constraint country_u1 unique (code),
name varchar2(50) not null,
list_order number(10),
constraint country_pk primary key (id)
);
create sequence sq_id_country increment by 1 start with 1 nomaxvalue nocycle cache 10;
create index country_i1 on country (list_order, name);
create or replace trigger tr_id_inc_country
before insert
on country
for each row
declare
begin
select sq_id_country.nextval into :new.id from dual;
end;
/
使用以下服务创建国家/地区:
@Modifying
@Transactional(rollbackFor = EntityAlreadyExistsException.class)
@Override
public Country add(Country country) {
if (findByCode(country.getCode()) == null) {
// Save the returned id into the entity
country = countryRepository.saveAndFlush(country);
return country;
} else {
throw new EntityAlreadyExistsException();
}
}
我可以在控制台日志中看到实际创建了该国家/地区并返回了其主键ID:
2014-09-19 13:00:05,839 DEBUG [sqlonly] com.mchange.v2.c3p0.impl.NewProxyPreparedStatement.executeUpdate(NewProxyPreparedStatement.java:147)
1. insert into country (version, code, list_order, name, id) values (0, 'fr', 1, 'France', 19)
事实上,我还添加了一个finder调用,以确保在创建国家后可以检索该国:
countryFR = new Country();
countryFR.setCode("fr");
countryFR.setName("France");
countryFR.setListOrder(1);
Country country = countryService.findByCode(countryFR.getCode());
if (country == null) {
countryFR = countryService.add(countryFR);
} else {
countryFR = country;
}
Country myc = countryService.findById(countryFR.getId());
if (myc != null) {
logger.debug("==============>> Found the country id: " + myc.getId());
}
控制台日志确实显示了记录器输出:
2014-09-19 13:00:05,854 DEBUG [BTSControllerTest] ==============>> Found the country id: 19
注意:控制台日志不会显示与该findById调用相对应的任何select语句。
然后尝试插入一个运算符:
1. insert into operator (version, country_id, description, image, name, operator_id, url, id) values (0, 19, 'The SFR operator', 'sfr.jpg', 'SFR', NULL, 'sfr.fr', 10)
您可以看到国家/地区ID与插入国家/地区的ID相同。
总结一下:
上面关于缺少select语句的说明让我想知道这个国家是否真的插入了。
插入国家/地区后检索到的主键ID为19会让我认为该国家实际上是插入的。
那么Oracle怎么抱怨它找不到运营商的外键呢?
我使用JPA2 hibernate-jpa-2.1-api 1.0.0.Final和spring-data-jpa 1.6.2.RELEASE和hibernate 4.3.6.Final
以下是连接属性:
jpaPropertiesMap.put("hibernate.dialect", databaseProperties.getHibernateDialect());
jpaPropertiesMap.put("hibernate.show_sql", "true");
jpaPropertiesMap.put("hibernate.format_sql", "true");
jpaPropertiesMap.put("hibernate.hbm2ddl.auto", databaseProperties.getHibernateHbm2ddlAuto());
jpaPropertiesMap.put("hibernate.transaction.factory_class", "org.hibernate.transaction.JDBCTransactionFactory");
jpaPropertiesMap.put("hibernate.ejb.naming_strategy", "org.hibernate.cfg.ImprovedNamingStrategy");
jpaPropertiesMap.put("hibernate.c3p0.min_size", "5");
jpaPropertiesMap.put("hibernate.c3p0.max_size", "20");
jpaPropertiesMap.put("hibernate.c3p0.timeout", "1000");
jpaPropertiesMap.put("hibernate.c3p0.max_statements", "50");
编辑:
我在JPA设置中添加了以下属性:
jpaPropertiesMap.put("hibernate.connection.autocommit", "true");
jpaPropertiesMap.put("hibernate.cache.use_query_cache", "false");
jpaPropertiesMap.put("hibernate.cache.use_second_level_cache", "false");
但它在这个问题上没有任何改变。
答案 0 :(得分:0)
我找到了解决方案。我的序列触发器缺少if语句。现在它有一个如下:if(:new.id为null)
create or replace trigger tr_id_inc_country
before insert
on country
for each row
declare
begin
if (:new.id is null)
then
select sq_id_country.nextval into :new.id from dual;
end if;
end;
/
我认为Hibernate正在获取插入的序列号,然后Oracle在提交时获得了另一个序列号。我只是在这里猜测。