在下面的代码中,如果我不清除当前会话,即使我想返回该父母的所有孩子的数量,该方法也会返回女孩的数量。
可以清楚地看到,id 为 1 的父母有 3 个孩子(2 个女孩和 1 个男孩),但只返回女孩,因为之前的检索方法只返回有女孩的父母。当我清除会话以避免从缓存返回时,它按预期返回 3。谁能帮我理解为什么会这样,在不清除当前会话的情况下如何避免这种情况?
@Service
public class ExampleServiceImpl implements ExampleService {
@Autowired
private ExampleRepository exampleRepository;
@Autowired
private SessionFactory sessionFactory;
@Override
@Transactional(readOnly = true)
public int getNumberOfChildren() {
List<Parent> parentList = exampleRepository.retrieveParentsWithGirls();
//sessionFactory.getCurrentSession().clear();
Parent parent = exampleRepository.retrieveParentWithId(1);
System.out.println(parent.getChildSet().size());
return parent.getChildSet().size();
}
}
让我分享我拥有的所有代码以及数据库脚本以使其更清晰。
存储库:
@Repository
public class ExampleRepositoryImpl implements ExampleRepository {
@Autowired
private SessionFactory sessionFactory;
@Override
public List<Parent> retrieveParentsWithGirls() {
CriteriaBuilder builder = sessionFactory.getCriteriaBuilder();
CriteriaQuery<Parent> criteria = builder.createQuery(Parent.class);
Root<Parent> parentRoot = criteria.from(Parent.class);
Fetch<Parent, Child> fetchChildren = parentRoot.fetch("childSet", JoinType.LEFT);
Join<Parent, Child> joinChildren = (Join<Parent, Child>) fetchChildren;
criteria.where(builder.equal(joinChildren.get("sex"), "girl"));
criteria.distinct(true);
return sessionFactory.getCurrentSession().createQuery(criteria).getResultList();
}
@Override
public Parent retrieveParentWithId(int id) {
CriteriaBuilder builder = sessionFactory.getCriteriaBuilder();
CriteriaQuery<Parent> criteria = builder.createQuery(Parent.class);
Root<Parent> parentRoot = criteria.from(Parent.class);
parentRoot.fetch("childSet", JoinType.LEFT);
criteria.where(builder.equal(parentRoot.get("id"), id));
return sessionFactory.getCurrentSession().createQuery(criteria).getSingleResult();
}
}
实体:
@Entity
@Table(name = "child")
public class Child {
@Id
@Column(name = "id", unique = true, nullable = false)
@GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;
@Column(name = "sex")
private String sex;
@JoinColumn(name = "parent_id", referencedColumnName = "id")
@ManyToOne(fetch = FetchType.LAZY)
private Parent parent;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Parent getParent() {
return parent;
}
public void setParent(Parent parent) {
this.parent = parent;
}
}
@Entity
@Table(name = "parent")
public class Parent {
@Id
@Column(name = "id", unique = true, nullable = false)
@GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;
@OneToMany(fetch = FetchType.LAZY, mappedBy = "parent")
private Set<Child> childSet;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public Set<Child> getChildSet() {
return childSet;
}
public void setChildSet(Set<Child> childSet) {
this.childSet = childSet;
}
}
数据库配置:
@EnableTransactionManagement
@Configuration
@Conditional(DatabaseRequiredCondition.class)
public class DatabaseConfiguration {
@Value("${jdbc.driverClassName}")
private String DB_DRIVER;
@Value("${jdbc.pwd}")
private String DB_PASSWORD;
@Value("${jdbc.url}")
private String DB_URL;
@Value("${jdbc.username}")
private String DB_USERNAME;
@Value("${hibernate.dialect}")
private String HIBERNATE_DIALECT;
@Value("${hibernate.showSql}")
private String HIBERNATE_SHOW_SQL;
@Value("${hibernate.packagesScan}")
private String ENTITYMANAGER_PACKAGES_TO_SCAN;
@Value("${hibernate.tx_timeout}")
private Integer TIMEOUT_AS_SECONDS;
@Bean
@Primary
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(DB_DRIVER);
dataSource.setUrl(DB_URL);
dataSource.setUsername(DB_USERNAME);
dataSource.setPassword(DB_PASSWORD);
return dataSource;
}
@Bean
@Primary
public LocalSessionFactoryBean sessionFactory() throws IOException {
LocalSessionFactoryBean sessionFactoryBean = new LocalSessionFactoryBean();
sessionFactoryBean.setDataSource(dataSource());
sessionFactoryBean.setPackagesToScan(ENTITYMANAGER_PACKAGES_TO_SCAN);
Properties hibernateProperties = new Properties();
hibernateProperties.put("hibernate.dialect", HIBERNATE_DIALECT);
hibernateProperties.put("hibernate.show_sql", HIBERNATE_SHOW_SQL);
hibernateProperties.put("hibernate.format_sql", true);
sessionFactoryBean.setHibernateProperties(hibernateProperties);
return sessionFactoryBean;
}
@Bean(name="transactionManager")
@Primary
public HibernateTransactionManager transactionManager() throws IOException {
HibernateTransactionManager transactionManager =
new HibernateTransactionManager(sessionFactory().getObject());
transactionManager.setDefaultTimeout(TIMEOUT_AS_SECONDS);
return transactionManager;
}
}
脚本:
create table parent (id serial);
create table child (id serial, parent_id integer not null, sex character varying(10));
INSERT INTO public.parent values(default);
INSERT INTO public.parent values(default);
INSERT INTO public.child
(parent_id, sex)
VALUES(1, 'girl');
INSERT INTO public.child
(parent_id, sex)
VALUES(1, 'girl');
INSERT INTO public.child
(parent_id, sex)
VALUES(1, 'boy');
运行代码时生成的脚本:
Hibernate:
select
parent0_.id as id1_23_0_,
childset1_.id as id1_5_1_,
childset1_.parent_id as parent_i3_5_1_,
childset1_.sex as sex2_5_1_,
childset1_.parent_id as parent_i3_5_0__,
childset1_.id as id1_5_0__
from
parent parent0_
left outer join
child childset1_
on parent0_.id=childset1_.parent_id
where
childset1_.sex=?
Hibernate:
select
parent0_.id as id1_23_0_,
childset1_.id as id1_5_1_,
childset1_.parent_id as parent_i3_5_1_,
childset1_.sex as sex2_5_1_,
childset1_.parent_id as parent_i3_5_0__,
childset1_.id as id1_5_0__
from
parent parent0_
left outer join
child childset1_
on parent0_.id=childset1_.parent_id
where
parent0_.id=1
休眠版本:5.4.5.Final