Java 如何在Hibernate中绕过缓存第一级刷新
有没有人能解释一下,为什么我的父母在我刷新实体时没有填充子对象 我在这里包括了parentDao2Test类以及ParentService、ChildService、DBChild和DBParent。parentDAO和childDao基本上很简单。ParentDAO2测试通过SpringJUnit4ClassRunner junit runner运行Java 如何在Hibernate中绕过缓存第一级刷新,java,database,spring,hibernate,jpa,Java,Database,Spring,Hibernate,Jpa,有没有人能解释一下,为什么我的父母在我刷新实体时没有填充子对象 我在这里包括了parentDao2Test类以及ParentService、ChildService、DBChild和DBParent。parentDAO和childDao基本上很简单。ParentDAO2测试通过SpringJUnit4ClassRunner junit runner运行 public class ParentDao2Test { @Autowired private ParentService paren
public class ParentDao2Test {
@Autowired private ParentService parentService;
@Test
public void testCRUD() {
DBParent parent = parentService.createParent();
assertTrue(parent.getId() > 0);
parent = parentService.createChildForParent(parent.getId());
assertTrue(parent.getChilds().size() > 0);
}
}
public class ParentService{
@Autowired ParentDao parentDao;
@Autowired ChildService childService;
@Transactional(propagation=Propagation.REQUIRES_NEW)
public DBParent createParent() {
DBParent parent = new DBParent();
parentDao.persist(parent);
return parent;
}
@Transactional(propagation=Propagation.REQUIRES_NEW)
public DBParent createChildForParent(long parentId) {
DBParent parent = parentDao.findById(parentId);
childService.createChildForParent(parentId);
HashMap<String, Object> props = new HashMap<String, Object>();
props.put("org.hibernate.cacheMode", CacheMode.IGNORE);
parentDao.refresh(parent);
return parent;
}
}
public class ChildService {
@Autowired ChildDao childDao;
@Autowired ParentDao parentDao;
@Transactional(propagation=Propagation.REQUIRES_NEW)
public DBChild createChildForParent(long parentId) {
DBParent parent = parentDao.findById(parentId);
DBChild child = new DBChild();
child.setName("Name");
childDao.persist(child);
parent.addChild(child);
parentDao.persist(parent);
parentDao.flush();
return child;
}
}
@Entity
@Table(name = "Parent")
public class DBParent {
@Id
@Column(name="id")
@GeneratedValue(strategy=GenerationType.AUTO)
private long id;
@OneToMany(fetch = FetchType.EAGER, cascade = {CascadeType.ALL}, orphanRemoval=true)
@JoinColumn(name = "childs", nullable=true)
private Set<DBChild> childs = new HashSet<DBChild>();
public DBParent() {
super();
}
}
@Entity
@Table(name = "child")
public class DBChild {
@Id
@Column(name="id")
@GeneratedValue(strategy=GenerationType.AUTO)
private long id;
@Column(name="name", nullable = false, length=1024)
private String name;
public DBChild() {
super();
}
}
公共类ParentDao2Test{
@自动连线专用家长服务;
@试验
公共void testCRUD(){
DBParent=parentService.createParent();
assertTrue(parent.getId()>0);
parent=parentService.createChildForParent(parent.getId());
assertTrue(parent.getChilds().size()>0);
}
}
公共班级家长服务{
@自动连线的ParentDao ParentDao;
@自动连线儿童服务儿童服务;
@事务性(传播=传播。需要\u新建)
public DBParent createParent(){
DBParent parent=新的DBParent();
parentDao.persist(parent);
返回父母;
}
@事务性(传播=传播。需要\u新建)
public DBParent createChildForParent(长parentId){
DBParent parent=parentDao.findById(parentId);
childService.createChildForParent(parentId);
HashMap props=newhashmap();
put(“org.hibernate.cacheMode”,cacheMode.IGNORE);
parentDao.refresh(父级);
返回父母;
}
}
公营儿童服务{
@自动连线的ChildDao ChildDao;
@自动连线的ParentDao ParentDao;
@事务性(传播=传播。需要\u新建)
public DBChild createChildForParent(长parentId){
DBParent parent=parentDao.findById(parentId);
DBChild=newdbchild();
child.setName(“名称”);
坚持(孩子);
parent.addChild(child);
parentDao.persist(parent);
parentDao.flush();
返回儿童;
}
}
@实体
@表(name=“Parent”)
公共类DBParent{
@身份证
@列(name=“id”)
@GeneratedValue(策略=GenerationType.AUTO)
私人长id;
@OneToMany(fetch=FetchType.EAGER,cascade={CascadeType.ALL},orphanRemoving=true)
@JoinColumn(name=“childs”,nullable=true)
private Set childs=new HashSet();
公共DBParent(){
超级();
}
}
@实体
@表(name=“child”)
公共类DBChild{
@身份证
@列(name=“id”)
@GeneratedValue(策略=GenerationType.AUTO)
私人长id;
@列(name=“name”,null=false,长度=1024)
私有字符串名称;
公共DBChild(){
超级();
}
}
经过一整天的深入调试,我终于找到了问题所在
我之所以看到这种行为,是因为我的事务是在REPEATABLE_READ(默认设置)中配置的。这意味着Spring保证在同一事务中对相同数据的两次读取将始终返回相同的结果。由于隔离级别优先于缓存逐出或实体刷新,因此即使我刷新或逐出父实体,这也没有效果
有一种方法可以解决此行为:
将事务隔离级别声明为READ_UNCOMMITTED或READ_COMMITTED。如果使用标准方言,可能会遇到著名的“标准JPA不支持自定义隔离级别”异常。在这种情况下,您可以应用以下解决方法:
春季3.3:
春季3.2:
为了使代码正常工作,我必须更改以下方法:
@Transactional(propagation=Propagation.REQUIRES_NEW, isolation=Isolation.READ_COMMITTED)
public DBParent createChildForParent(long parentId) {
DBParent parent = parentDao.findById(parentId);
childService.createChildForParent(parentId);
parentDao.getSession().evict(parent);
parent = parentDao.findById(parentId);
return parent;
}
尝试在父表上使用merge而不是persist,并检查在插入子实体后是否在数据库中填充了子表“childs”字段。