休眠额外的查询,出现@GeneratedValue

时间:2019-06-21 14:11:30

标签: java hibernate mapping

现有子值和@GeneratedValue策略的Hibernate和关联(映射)问题。需要其他查询吗?

我正在学习Hibernate,并使用一对多,多对一和多对多关联以自己的示例进行练习。 为了查询而简化:

  • 我有Java类User,Country和Languages。一个用户只能住在一个国家(关系是多对一的),并且会说几种语言(因此关系是多对多的)

  • 我有数据库表“ users”,“ countries”,“ languages”和“ users_languages”。

  • “ country_id”存储在“用户”表中(因为每个用户只有一个),而多个“ language_id”和“ user_id”则存储在“ users_languages”表中。

  • 我已经预填了表“国家”和“语言”,因为它们是固定值,所以我不想从这些表中添加/删除任何这些值。它们将与不同的用户相关联。

表的架构(为简便起见,我删除了列):

CREATE TABLE `users` (
   `id` int(11) NOT NULL AUTO_INCREMENT,
   `username` varchar(20) NOT NULL,
   `country_id` int(11) DEFAULT NULL,
   PRIMARY KEY (`id`),
   UNIQUE KEY `username_UNIQUE` (`username`),
   CONSTRAINT `u_country_fk` FOREIGN KEY (`country_id`) REFERENCES `countries` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
 )

CREATE TABLE `countries` (
   `id` int(11) NOT NULL AUTO_INCREMENT,
   `name` varchar(45) NOT NULL,
   PRIMARY KEY (`id`),
   UNIQUE KEY `name_UNIQUE` (`name`)
 )

CREATE TABLE `languages` (
   `id` int(11) NOT NULL AUTO_INCREMENT,
   `language` varchar(15) NOT NULL,
   PRIMARY KEY (`id`),
   UNIQUE KEY `language_UNIQUE` (`language`)
 )

CREATE TABLE `users_languages` (
   `user_id` int(11) NOT NULL,
   `language_id` int(11) NOT NULL,
   PRIMARY KEY (`user_id`,`language_id`),
   CONSTRAINT `ul_language_fk` FOREIGN KEY (`language_id`) REFERENCES `languages` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
   CONSTRAINT `ul_user_fk` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
 )

如前所述,我已经在表“国家/地区”和“语言”中插入了所需的行,这样它们将对用户唯一可用。

相应的Java实体:

@Entity
@Table(name = "users")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private int id;
    @NaturalId
    @Column(name = "username", nullable = false, unique = true)
    private String username;
    @ManyToOne
    @JoinColumn(name="country_id",
    foreignKey = @ForeignKey(name = "u_country_fk"))
    private Country country;
    @ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
    @LazyCollection(LazyCollectionOption.FALSE)
    @JoinTable(
    name = "users_languages",
    joinColumns = @JoinColumn(name = "user_id", nullable = false),
    inverseJoinColumns = @JoinColumn(name = "language_id", nullable = false)
    )
    private List<Language> languages;

    public User() {
        this.languages = new ArrayList<>();
    }
    public User(String username, Country country) {
        this.username = username;
        this.country = country;
        this.languages = new ArrayList<>();
    }

    public void addLanguage(Language language) {
        this.languages.add(language);
        language.getUsers().add(this);
    }
    public void removeLanguage(Language language) {
        this.languages.remove(language);
        language.getUsers().remove(this);
    }
    public void removeAllLanguages() {
        this.languages.clear();
    }

    // getters and setters omitted
}
@Entity
@Table(name = "countries")
public class Country {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private int id;
    @NaturalId
    @Column(name = "name", nullable = false, unique = true)
    private String name;
//  @OneToMany(cascade = CascadeType.ALL)
//  @JoinColumn(name="id")
//  private Set<User> users;

    public Country() {
//      users = new HashSet<>();
    }
    public Country(String name) {
        this.name = name;
//      users = new HashSet<>();
    }

    // getters and setters omitted
}
@Entity
@Table(name = "languages")
public class Language {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private int id;
    @NaturalId
    @Column(name = "language", nullable = false, unique = true)
    private String language;
    @ManyToMany(mappedBy = "languages")
    Set<User> users;

    public Language() {
        users = new HashSet<>();
    }
    public Language(String language) {
        this.language = language;
        users = new HashSet<>();
    }

    // getters and setters omitted
}

创建新用户时,@ GeneratedValue遇到问题,因为在批处理中,我必须存储几种语言。最后,对我有用的一个是GenerationType.IDENTITY,但是我读到了Hibernate知道要使用的下一个ID所需的额外查询。此外,因为如果我创建了一个新的对象Language(该批处理已经存在于数据库中),则该批处理存在一个问题(我希望Hibernate可以自动管理它)。新对象国家/地区也是如此。因此,不是创建新对象,而是在数据库中已经存在相应的行,而是从数据库中获取它们,以将它们与正在创建的用户相关联。但是我认为Hibernate将再次执行相同的查询(检查数据库中是否存在与用户相关联的对象Language和Country),因此我可能正在重复所需查询的数量,从而降低了性能。请参见下面的代码段:

public int addUser(SessionFactory factory, String username, String countryName, String[] languages) {
    User user = null;
    try (Session session = factory.openSession()) {
        Transaction transaction = session.beginTransaction();
        Country country = (Country) session
            .createQuery("FROM Country WHERE name = :country_name")
            .setParameter("country_name", countryName).getSingleResult();
        user = new User(username, password, name, email, gender, country);
        for (String language : languages) {
            Language lang = (Language) session
                .createQuery("FROM Language WHERE language = :language")
                .setParameter("language", language).getSingleResult();
            user.addLanguage(lang);
        }
        session.persist(user);
        transaction.commit();
    }
    return user==null ? -1 : user.getId();
}

有人可以在以下几点上帮助我吗:

  • 我是否使用正确的策略生成ID?

  • 我是否使用正确的级联方法(在数据库和Hibernate中都使用)?

  • 上述方法是否有更好的方法来添加用户,从而减少对数据库的查询总数/提高性能?

  • 我也应该使乡村协会成为竞标者吗?有关国家和语言类单向/双向的建议。

  • 我应该与Hibernate一起使用的其他建议/改进吗?

非常感谢, 哈维尔

0 个答案:

没有答案