【发布时间】:2021-06-22 06:19:31
【问题描述】:
这是我之前的问题How to model packages, versions and licenses? 的后续问题。
这是我的数据库设置。
V1__create_table_license.sql
CREATE TABLE IF NOT EXISTS license (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL,
reference TEXT NOT NULL,
is_deprecated_license_id BOOLEAN NOT NULL,
reference_number INTEGER NOT NULL,
license_id TEXT NOT NULL,
is_osi_approved BOOLEAN NOT NULL
);
INSERT INTO license
("name",reference,is_deprecated_license_id,reference_number,license_id,is_osi_approved)
VALUES
('MIT License','./MIT.json',false,275,'MIT',true);
V2__create_npm_package.sql
CREATE TABLE IF NOT EXISTS npm_package (
id BIGSERIAL PRIMARY KEY,
name TEXT NOT NULL,
description TEXT NOT NULL
);
INSERT INTO npm_package
(name, description)
VALUES
('react', 'React is a JavaScript library for building user interfaces.'),
('react-router-dom', 'DOM bindings for React Router'),
('typescript', 'TypeScript is a language for application scale JavaScript development'),
('react-dom', 'React package for working with the DOM.');
V3__create_npm_version.sql
CREATE TABLE IF NOT EXISTS npm_package_version (
npm_package_id BIGINT NOT NULL REFERENCES npm_package,
version TEXT NOT NULL,
license_id INTEGER NOT NULL REFERENCES license,
UNIQUE(npm_package_id, version)
)
这是我的 Java 对象。
License.java
@Entity
public class License {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String reference;
private Boolean isDeprecatedLicenseId;
private Integer referenceNumber;
private String name;
private String licenseId;
private Boolean isOsiApproved;
}
LicenseRepository.java
public interface LicenseRepository extends JpaRepository<License, Integer> {
License findByLicenseIdIgnoreCase(String licenseId);
}
NpmPackage.java
@Entity
public class NpmPackage {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String description;
@OneToMany(mappedBy = "npmPackage", cascade = CascadeType.ALL, orphanRemoval = true)
private List<NpmPackageVersion> versions = new ArrayList<>();
public NpmPackage() {}
public void addVersion(NpmPackageVersion version) {
this.versions.add(version);
version.setNpmPackage(this);
}
public void removeVersion(NpmPackageVersion version) {
this.versions.remove(version);
version.setNpmPackage(null);
}
}
@Entity
public class NpmPackageVersion {
public NpmPackageVersion() {}
public NpmPackageVersion(String version, License license) {
this.setVersion(version);
this.license = license;
}
@EmbeddedId private NpmPackageIdVersion npmPackageIdVersion = new NpmPackageIdVersion();
@MapsId("npmPackageId")
@ManyToOne(fetch = FetchType.LAZY)
private NpmPackage npmPackage;
@ManyToOne(fetch = FetchType.LAZY)
private License license;
@Embeddable
public static class NpmPackageIdVersion implements Serializable {
private static final long serialVersionUID = 3357194191099820556L;
private Long npmPackageId;
private String version;
// ...
}
public String getVersion() {
return this.npmPackageIdVersion.version;
}
public void setVersion(String version) {
this.npmPackageIdVersion.version = version;
}
}
MyRunner.java
@Component
class MyRunner implements CommandLineRunner {
@Autowired LicenseRepository licenseRepository;
@Autowired NpmPackageRepository npmPackageRepository;
@Override
// @Transactional
public void run(String... args) throws Exception {
// get license from database
var license = licenseRepository.findByLicenseIdIgnoreCase("mit");
// get package from db
var dbPackage = npmPackageRepository.findByNameIgnoreCase("react");
var version = new NpmPackageVersion("1.0.0", license);
dbPackage.addVersion(version);
npmPackageRepository.save(dbPackage);
}
}
在我之前的问题中,我得到了使用fetch = FetchType.EAGER 的答案,但后来我了解到这并不理想。我想使用惰性获取。
@OneToMany(mappedBy = "npmPackage", fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true)
private List<NpmPackageVersion> versions = new ArrayList<>();
所以我删除了急切的获取并遇到了错误。
org.hibernate.LazyInitializationException:无法延迟初始化角色集合:com.example.bom.NpmPackage.NpmPackage.versions,无法初始化代理 - 没有会话
使用@Transactional 注释一切正常。为什么会这样?我试图在网上阅读所有内容,但我仍然不明白。我知道数据库会话在某个时候关闭,我想知道究竟是什么情况。我也想知道我是否可以做一些事情,例如我尝试获取所有版本以确保在添加另一个版本之前加载它们。
那么我真的必须使用@Transactional 还是有其他解决方案?我只是想了解正在发生的“魔术”:)
非常感谢!
【问题讨论】:
标签: java postgresql spring-boot hibernate