【问题标题】:How to create relationships between objects in Spring JDBC?如何在 Spring JDBC 中创建对象之间的关系?
【发布时间】:2014-10-06 11:56:04
【问题描述】:

我想实现从 JPA 到 Spring JDBC 的关系。例如,假设我有 Account 和 Advert 对象。根据 JPA,Account 和 Advert 之间的关系是 @OneToMany

帐户类别:

public class Account {

private Long id;
private String username;
private Set<Advert> adverts = new HashSet<Advert>();

// getters + setters
}

广告类:

public class Advert {

private Long id;
private String text;
private Account account;

// getters + setters
}

AccountMapper:

public class AccountMapper implements RowMapper<Account> {

public Account mapRow(ResultSet rs, int rowNum) throws SQLException {
    Account account = new Account();
    account.setId(rs.getLong("id"));
    account.setUsername(rs.getString("username"));
    return account;
}
}

现在,我正在尝试为 Advert 类创建一个映射器。如何将帐户变量从 Advert 类映射到一行?非常感谢

【问题讨论】:

  • 如果您需要关系映射,最好使用一些 ORM 框架,例如 Hibernate。您可以在 Spring JDBC 中手动进行映射,但这可能会导致 N+1 Select 问题,或者您应该仔细重写所有查询并使用依赖关系连接实体,而且映射器会复杂得多。
  • 谢谢你的回答伙伴。我以前使用过 ORM 框架,但现在我正在开发一个更复杂的系统,并且由于其性能,我被建议使用 Spring JDBC。
  • @user1516873 N+1 选择问题是一个设计问题,无论是否使用 ORM 都可能发生。恕我直言,快速设计的 ORM 请求比 JDBC 请求更常见,因为所有请求都必须是显式的。
  • @VladMatvei 我不想坚持太多,但我认为您应该考虑其他解决方案。如果您的应用程序有这么多用户,以至于 Hibernate 成为瓶颈(并且您优化了它的所有查询),那么您可能已经考虑使用可扩展的 NoSQL 数据库。否则,只需启用 Hibernate 的缓存机制或更改您的查询。

标签: java spring hibernate jpa jdbc


【解决方案1】:

您可以在不影响应用程序性能的情况下使用 Hibernate,只需查看此 Hibernate tutorial 以获取数百个与映射实体相关的示例。

至于在 JDBC 中这样做,您需要执行以下步骤:

  1. 您需要对所有选定的列使用别名,以免 ids 列发生冲突。

  2. 您可以定义两个行映射器并使用从 Advert 到 Account 的连接并将其传递给 AccountMapper:

    public class AdvertMapper implements RowMapper<Advert> {
    
        public Advert mapRow(ResultSet rs, int rowNum) throws SQLException {
            Advert advert = new Advert();
            advert.setId(rs.getLong("advert_id"));
            advert.setText(rs.getString("advert_text"));
            return advert;      
        }
    }
    
    public class AccountMapper implements RowMapper<Account> {
    
        private final AdvertMapper advertMapper;
    
        public AccountMapper(AdvertMapper advertMapper) {
            this.advertMapper = advertMapper;
        }
    
        public Account mapRow(ResultSet rs, int rowNum) throws SQLException {
            Account account = new Account();
            account.setId(rs.getLong("account_id"));
            account.setUsername(rs.getString("account_username"));
    
            Advert advert = this.advertMapper.mapRow(rs, rowNum);
            advert.setAccount(account);
            account.getAdverts().add(advert);
    
            return account;
        }
    }
    

AccountMapper 使用 AdvertMapper 从连接的数据创建广告。

将此与 Hibernate 进行比较,所有这些映射都会为您解析。

【讨论】:

  • 这种情况下如何编写包含sql查询作为参数的jdbc模板语法?
  • queryforObject(SQL, new AccountMapper(new AdvertMapper))
  • 我的用例是:模板模型中包含定义模型列表。所以我想创建一个 Template 对象,里面是一个定义列表。
  • 那将是一个不同的问题,所以这样问,而不是作为评论。
【解决方案2】:

正如弗拉德回答的那样,解决一对一的情况很容易,如果您想将一对多映射为您的帐户 - 广告建议您不能这样做 使用 RowMapper,因为您将尝试将 ResultSet 的多行映射到一个帐户,多个广告。

您也可以手动执行此操作,也可以使用http://simpleflatmapper.org 提供从 ResultSet 到 POJO 的映射,并提供一对多支持。 请注意,如果您真的想要那些可能的双向关系,但它们不会是同一个实例。

结帐 http://simpleflatmapper.org/0104-getting-started-springjdbc.htmlhttps://arnaudroger.github.io/blog/2017/02/27/jooq-one-to-many.html

你需要得到一个 ResutlSetExtractor - 它是线程安全的,所以只需要一个实例 -,

    private final ResultSetExtractor<List<Account>> mapper = 
        JdbcTemplateMapperFactory
            .newInstance()
            .addKeys("id") // assuming the account id will be on that column 
            .newResultSetExtractor(Account.class);

    // in the method
    String query = 
        "SELECT ac.id as id, ac.username, ad.id as adverts_id, ad.text as adverts_text"
        + "FROM account ac LEFT OUTER JOIN advert ad ON ad.account_id = ac.id order by id " 
        // the order by id is important here as it uses the break on id on the root object 
        // to detect new root object creation

    List<Account> results = template.query(query, mapper);

您应该会得到一个包含广告列表的帐户列表。但 advert 没有帐号。

【讨论】:

    【解决方案3】:

    好吧,如果你不使用 ORM……你就没有对象关系映射!由于这个原因创建了所有 ORM :-)

    更重要的是,ORM 使您免于编写大量样板代码。使用直接 JDBC 代替 JPA 是一种代码优化。像任何其他代码优化一样,应该在适当的时候使用它。它相关:

    • 使用少数表且不想依赖 ORM 的库(例如:spring security 中的用户、角色和 ACL)
    • 在大型应用程序中发现瓶颈

    我的建议应该是首先使用 JPA 或隐藏在 DAO 层中的本机休眠。然后仔细分析你的性能问题,重写 JDBC 中最昂贵的部分。

    当然,你可以直接在 JDBC 中编写你的 DAO 实现,但是写起来会长很多。

    我几乎忘记了基本部分:在 ORM 中您映射类和关系,在 JDBC 中您编写独立的 SQL 查询。

    【讨论】:

    • 非常感谢您的澄清 Serge
    猜你喜欢
    • 2011-04-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-10-01
    • 2021-12-15
    • 2020-08-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多