java – 即使使用eager fetch,Hibernate也不会加载一对多的关系集
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了java – 即使使用eager fetch,Hibernate也不会加载一对多的关系集,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含6523字,纯文字阅读大概需要10分钟。
内容图文
![java – 即使使用eager fetch,Hibernate也不会加载一对多的关系集](/upload/InfoBanner/zyjiaocheng/824/ffc886c80752452cb885d79633595afc.jpg)
我有以下hibernate映射.
@OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, mappedBy = "product")
private Set<ProductLicense> productLicenses = new HashSet<ProductLicense>(0);
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "product_id", nullable = false)
private Product product;
但是当我调用product.getProductLicences()时,即使在事务方法中,我总是得到一个空Set.
sessionFactory.getCurrentSession().get(Product.class, productId))
.getProductLicenses()
以下是ProductDaoImpl类
@Repository
public class ProductDaoImpl implments ProductDao{
@Autowired
private SessionFactory sessionFactory;
@Override
public Product getProduct(Integer productId)
{
Product result = (Product) sessionFactory.getCurrentSession().get(Product.class, productId);
Hibernate.initialize(result.getProductLicenses());
//sessionFactory.getCurrentSession().refresh(result);
return result;
}
.. other methods
}
另外如果我调用Hibernate.initialize(product);不执行表之间的任何连接.
指令sessionFactory.getCurrentSession().get(Product.class,productId);不会对数据库产生任何查询(我的属性show_sql等于true).
但如果我取消注释sessionFactory.getCurrentSession().refresh(result);我可以看到sql和set已加载,我无法理解为什么在其他情况下没有加载.
但我无法理解我的映射有什么问题.
产品类别是:
@Entity
@Table(name = "product")
public class Product {
@Id
@GeneratedValue(strategy = IDENTITY)
@Column(name = "product_id", unique = true)
private Integer productId;
@NotNull
@Size(max = 200)
@Column(name = "name")
private String name;
@OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, mappedBy = "product")
private Set<ProductLicense> productLicenses = new HashSet<ProductLicense>(0);
public Set<ProductLicense> getProductLicenses()
{
return productLicenses;
}
public void setProductLicenses(Set<ProductLicense> productLicenses)
{
this.productLicenses = productLicenses;
}
//getters and setters
..
}
ProductLicense类:
@Entity
@Table(name = "product_license")
public class ProductLicense {
@Id
@GeneratedValue(strategy = IDENTITY)
@Column(name = "product_license_id", unique = true)
private Integer productLicenseId;
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "product_id", nullable = false)
private Product product;
@NotNull
@Column(name = "key")
private String key;
// getters and setters ...
}
最后我的配置如下:
@Configuration
@EnableWebMvc
@EnableTransactionManagement
@ComponentScan("com.company.package")
@PropertySource("classpath:application.properties")
public class WebAppConfig {
private static final String PROPERTY_NAME_DATABASE_DRIVER = "db.driver";
private static final String PROPERTY_NAME_DATABASE_PASSWORD = "db.password";
private static final String PROPERTY_NAME_DATABASE_URL = "db.url";
private static final String PROPERTY_NAME_DATABASE_USERNAME = "db.username";
private static final String PROPERTY_NAME_HIBERNATE_DIALECT = "hibernate.dialect";
private static final String PROPERTY_NAME_HIBERNATE_SHOW_SQL = "hibernate.show_sql";
private static final String PROPERTY_NAME_ENTITYMANAGER_PACKAGES_TO_SCAN = "entitymanager.packages.to.scan";
@Resource
private Environment env;
@Bean
public DataSource dataSource()
{
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(env.getRequiredProperty(PROPERTY_NAME_DATABASE_DRIVER));
dataSource.setUrl(env.getRequiredProperty(PROPERTY_NAME_DATABASE_URL));
dataSource.setUsername(env.getRequiredProperty(PROPERTY_NAME_DATABASE_USERNAME));
dataSource.setPassword(env.getRequiredProperty(PROPERTY_NAME_DATABASE_PASSWORD));
return dataSource;
}
private Properties hibProperties()
{
Properties properties = new Properties();
properties.put(PROPERTY_NAME_HIBERNATE_DIALECT,
env.getRequiredProperty(PROPERTY_NAME_HIBERNATE_DIALECT));
properties.put(PROPERTY_NAME_HIBERNATE_SHOW_SQL,
env.getRequiredProperty(PROPERTY_NAME_HIBERNATE_SHOW_SQL));
properties.put("hibernate.cache.provider_class", "org.hibernate.cache.NoCacheProvider");
properties.put("hibernate.cache.use_second_level_cache", "false");
return properties;
}
@Bean
public LocalSessionFactoryBean sessionFactory()
{
LocalSessionFactoryBean lsfb = new LocalSessionFactoryBean();
lsfb.setDataSource(this.dataSource());
lsfb.setPackagesToScan(env.getRequiredProperty(PROPERTY_NAME_ENTITYMANAGER_PACKAGES_TO_SCAN));
lsfb.setHibernateProperties(this.hibProperties());
return lsfb;
}
@Bean
public HibernateTransactionManager transactionManager()
{
return new HibernateTransactionManager(this.sessionFactory().getObject());
}
}
我的测试:
@Before
@Transactional
public void setUp() throws ParseException
{
product1 = new Product();
..
productService.addProduct(product1);
product2 = new Product();
..
product2 = productService.addProduct(product2);
productService.addProductLicense(product2.getProductId(), licenceKey1Product2);
productService.addProductLicense(product2.getProductId(), licenceKey2Product2);
}
@Test
@Transactional
public void addProductLicenseTest()
{
String licenseKey[] = { "thisisthekey", "thisisthekey2" };
productService.addProductLicense(product1.getProductId(), licenseKey[0]);
//sessionFactory.getCurrentSession().flush();
//sessionFactory.getCurrentSession().clear();
Product product1saved = productService.getProduct(product1.getProductId());
assertEquals(1, product1saved.getProductLicenses().size());
assertEquals(licenseKey[0], product1saved.getProductLicenses().iterator().next().getKey());
productService.addProductLicense(product1.getProductId(), licenseKey[1]);
product1saved = productService.getProduct(product1saved.getProductId());
assertEquals(2, product1saved.getProductLicenses().size());
}
解决方法:
这是(最有可能)发生的事情.
您的整个测试方法都是事务性的.因此,服务的调用发生在与测试本身的代码相同的事务中.
在测试中,您无需任何许可即可创建和保留产品.这将Product实例存储在与事务关联的会话缓存中.此产品有一个空的许可列表.
然后,您将调用仍在同一事务中的服务方法,该方法将创建一个许可证,其产品是您之前创建的产品.我的猜测是这个服务的代码如下所示:
Product product = (Product) session.get(Product.class, productId);
ProductLicense license = new ProductLicense();
license.setProduct(product);
session.persist(license);
在上面的代码中,从会话缓存中获取产品,然后使用找到的产品保留许可证.请注意,代码设置许可证的产品,但它不会将许可证添加到产品中,这就是问题所在.
然后,您将通过ID获取产品,仍然在同一个交易中.因此,Hibernate直接从缓存中检索产品.在缓存中,由于您省略了将许可证添加到产品,因此许可证列表仍为空.
因此,简而言之,维护双向关联的双方都是您的责任.如果您只初始化所有者端,Hibernate将保持关联,并且如果从数据库加载产品,将正确初始化列表.但是当产品在缓存中时,它会在您将其存储在缓存中时保留.这就是为什么你看到一个空列表,除非你明确地清除会话,从而从数据库重新加载状态.
内容总结
以上是互联网集市为您收集整理的java – 即使使用eager fetch,Hibernate也不会加载一对多的关系集全部内容,希望文章能够帮你解决java – 即使使用eager fetch,Hibernate也不会加载一对多的关系集所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。