在一个相对较大的Spring Boot项目中,我有一个具有以下(过分简化)事件序列的方法:
Car car = carRepository.save(new Car());
Person person = personRepository.save(new Person(car)); // Car is a field of Person
Engine engine = engineRepository.save(new Engine());
person.getCar().setEngine(engine);
carRepository.save(person.getCar()); // without this the engine and car relation is not registered
Car
,Person
和Engine
都是@Entity
类(数据库对象)。对于此示例,其实现可以如下:
// Car.java
@Entity
@Table(name = "car_tbl")
public class Car {
@Id
@GeneratedValue
@Column(name = "car_id")
private Long id;
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "engine_id", unique = true)
private Engine engine;
}
// Person.java
@Entity
@Table(name = "person_tbl")
public class Person {
@Id
@GeneratedValue
@Column(name = "person_id")
private Long id;
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "car_id", nullable = false, unique = true)
private Car car;
}
// Engine.java
@Entity
@Table(name = "engine_tbl")
public class Engine {
@Id
@GeneratedValue
@Column(name = "engine_id")
private Long id;
}
以上方法仅在REST API方法内部使用。 并且在配置属性中启用了OSIV(在视图中打开会话)。
问题是,为什么我需要保存person.getCar()
对象?这是我在同一请求处理期间刚刚创建的Car
对象。在什么时候它会由持久性上下文变为瞬时而不是托管?我以为所有更改都会自动清除,因为启用了OSIV。
如何检测此类情况并确切知道,何时使用.save()
方法以及何时可以忽略它?
答案 0 :(得分:0)
这取决于该方法是否包含在事务中。
.save()
才能更新数据库。如何检测到此类情况并确切知道何时使用
.save()
方法以及何时可以忽略它?
.save()
方法:
new Car()
。List
中。).save()
方法。 (例如carRepository.findById(id)
和其他类似方法)。如果上述事件序列是通过@Transactional
注释的方法调用的,那么它将按预期工作。
然后,创建的Car
对象将由持久性上下文进行管理,并且在同一事务中对它的所有更改将在事务完成后刷新。
如果上述方法不属于任何事务,则对对象的所有更改都是本地的(对象属性已更改,但未刷新到数据库)。
这就是为什么必须显式调用persist()
或merge()
(在上面的情况下,内部使用这两个变量的save()
)来刷新更改的原因。
保存单个实体将执行单个SQL查询,该查询是原子的,因此是事务本身。如果事务中未包含数据库事件的顺序,则每个save()
调用都将充当独立的“事务”。
通常,这是一种不好的做法,因为如果以后的一个“事务”之一失败(引发了某种Exception
),则先前成功的事务已被刷新,从而可能使数据库从以下状态变为无效状态:业务逻辑角度。
此行为与OSIV无关。
OSIV在视图渲染期间使数据库 session 保持打开状态,以便在主请求处理完成之后,可以在视图层中执行进一步的查询(事务)。 Using OSIV is widely considered an anti-pattern.