有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java Hibernate从缓存返回错误的列表,即使预期的列表与缓存的列表不同

在下面的代码中,如果我不清除当前会话,那么即使我想返回此父对象的所有子对象的数量,也只会从该方法返回女孩的数量

可以清楚地看到,id为1的家长有三个孩子(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

Hibernate版本:5.4.5。决赛


共 (0) 个答案