如果数据量过大或者层次太多,那么这样操作是会影响性能的。
“任何树形结构都可以用二叉树来表示”。其实我们创建的栏目树就是一个简型的二叉树。根据数据结构里面二叉树的遍历,再稍微修改下,将数据库设计如下图所示:
这样我们查找该节点的所有子节点,则只需要查找id在lft和rgt之间的所有节点即可。
1.查找该节点的所有子节点的Sql语句为:
<!--EndFragment-->
<!--EndFragment-->Sql代码select * from tb_subject s,tb_subject t where s.lft between t.lft and t.rgt and t.id=1 select*fromtb_subjects,tb_subjecttwheres.lftbetweent.lftandt.rgtandt.id=1 2.查找该节点的所有父节点的sql语句为:<!--EndFragment-->Sql代码select s.* from tb_subject s,tb_subject t where s.lft<t.lft and (s.rgt-s.lft)>1 and s.rgt>t.rgt and t.id=1 selects.*fromtb_subjects,tb_subjecttwheres.lft<t.lftand(s.rgt-s.lft)>1ands.rgt>t.rgtandt.id=1 下面来详细讲解下,怎么用java来实现这种算法。<!--EndFragment--> 1. 新增节点 新增节点比较简单,基本步骤为 A. 查找当前插入节点的父节点的lft值 B. 将树形中所有lft和rgt节点大于父节点左值的节点都+2 C. 将父节点左值+1,左值+2分别作为当前节点的lft和rgt 因为项目中采用的是struts2+hibernate3.2+spring2.5的框架,代码如下:<!--EndFragment-->Java代码public boolean onSave(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) { if (entity instanceof HibernateTree) { HibernateTree tree = (HibernateTree) entity; Long parentId = tree.getParentId(); String beanName = tree.getClass().getName(); Session session = getSession(); FlushMode model = session.getFlushMode(); session.setFlushMode(FlushMode.MANUAL); Integer myPosition = new Integer(0); //查找父节点的左值 if (parentId != null) { String hql = "select b.lft from " + beanName + " b where b.id=:pid"; myPosition = (Integer) session.createQuery(hql).setLong("pid", parentId).uniqueResult(); } //将树形结构中所有大于父节点左值的右节点+2 String hql1 = "update " + beanName + " b set b.rgt = b.rgt + 2 WHERE b.rgt > :myPosition"; //将树形结构中所有大于父节点左值的左节点+2 String hql2 = "update " + beanName + " b set b.lft = b.lft + 2 WHERE b.lft > :myPosition"; if (!StringUtils.isBlank(tree.getTreeCondition())) { hql1 += " and (" + tree.getTreeCondition() + ")"; hql2 += " and (" + tree.getTreeCondition() + ")"; } session.createQuery(hql1).setInteger("myPosition", myPosition) .executeUpdate(); session.createQuery(hql2).setInteger("myPosition", myPosition) .executeUpdate(); session.setFlushMode(model); //定位自己的左值(父节点左值+1)和右值(父节点左值+2) for (int i = 0; i < propertyNames.length; i++) { if (propertyNames[i].equals(HibernateTree.LFT)) { state[i] = myPosition + 1; } if (propertyNames[i].equals(HibernateTree.RGT)) { state[i] = myPosition + 2; } } return true; } return false; } publicbooleanonSave(Objectentity,Serializableid,Object[]state, String[]propertyNames,Type[]types){ if(entityinstanceofHibernateTree){ HibernateTreetree=(HibernateTree)entity; LongparentId=tree.getParentId(); StringbeanName=tree.getClass().getName(); Sessionsession=getSession(); FlushModemodel=session.getFlushMode(); session.setFlushMode(FlushMode.MANUAL); IntegermyPosition=newInteger(0); //查找父节点的左值 if(parentId!=null){ Stringhql="selectb.lftfrom"+beanName +"bwhereb.id=:pid"; myPosition=(Integer)session.createQuery(hql).setLong("pid", parentId).uniqueResult(); } //将树形结构中所有大于父节点左值的右节点+2 Stringhql1="update"+beanName +"bsetb.rgt=b.rgt+2WHEREb.rgt>:myPosition"; //将树形结构中所有大于父节点左值的左节点+2 Stringhql2="update"+beanName +"bsetb.lft=b.lft+2WHEREb.lft>:myPosition"; if(!StringUtils.isBlank(tree.getTreeCondition())){ hql1+="and("+tree.getTreeCondition()+")"; hql2+="and("+tree.getTreeCondition()+")"; } session.createQuery(hql1).setInteger("myPosition",myPosition) .executeUpdate(); session.createQuery(hql2).setInteger("myPosition",myPosition) .executeUpdate(); session.setFlushMode(model); //定位自己的左值(父节点左值+1)和右值(父节点左值+2) for(inti=0;i<propertyNames.length;i++){ if(propertyNames[i].equals(HibernateTree.LFT)){ state[i]=myPosition+1; } if(propertyNames[i].equals(HibernateTree.RGT)){ state[i]=myPosition+2; } } returntrue; } returnfalse; } 2. 修改节点 修改的时候比较麻烦,具体步骤为: 在修改lft和rgt之前,当前节点的父节点id已经改变a. 查出当前节点的左右节点(nodelft、nodergt),并nodergt-nodelft+1 = span,获取父节点的左节点parentlftb. 将所有大于parentlft的lft(左节点)、rgt(右节点)的值+spanc. 查找当前节点的左右节点(nodelft、nodergt),并parentlft-nodelft+1 = offsetd. 将所有lft(左节点) between nodelft and nodergt的值+offsete. 将所有大于nodergt的lft(左节点)、rgt(右节点)的值-span Java代码如下:<!--EndFragment-->Java代码public void updateParent(HibernateTree tree, HibernateTree preParent, HibernateTree curParent) { if (preParent != null && preParent != null && !preParent.equals(curParent)) { String beanName = tree.getClass().getName(); // 获得节点位置 String hql = "select b.lft,b.rgt from " + beanName + " b where b.id=:id"; Object[] position = (Object[]) super.createQuery(hql).setLong( "id", tree.getId()).uniqueResult(); System.out.println(hql+"| id = "+tree.getId()); int nodeLft = ((Number) position[0]).intValue(); int nodeRgt = ((Number) position[1]).intValue(); int span = nodeRgt - nodeLft + 1; // 获得当前父节点左位置 hql = "select b.lft from " + beanName + " b where b.id=:id"; int parentLft = ((Number) super.createQuery(hql).setLong("id", curParent.getId()).uniqueResult()).intValue(); System.out.println(hql+"| id = "+curParent.getId()); // 先空出位置 String hql1 = "update " + beanName + " b set b.rgt = b.rgt + "