欢迎使用CSDN-markdown编辑器

来源:互联网 发布:盐城市阳光扶贫大数据 编辑:程序博客网 时间:2024/06/02 05:11

SSH框架整合问题之使用声明式事务管理,hibernate中update操作无效的问题

使用spring声明式事务管理

<bean id="transactionManager"        class="org.springframework.orm.hibernate3.HibernateTransactionManager"           p:sessionFactory-ref="sessionFactory"/><!--配置事务增强处理bean,指定事务管理器  -->       <tx:advice id="txAdvice" transaction-manager="transactionManager">         <!-- 配置详细的事务定义 -->         <tx:attributes>         <!--  所有以get开头的方法都是只读的-->           <tx:method name="get*" read-only="true"/>           <!-- 其他方法默认的事务设置,指定超时时长为5秒 -->           <tx:method name="*" isolation="DEFAULT" propagation="REQUIRED" timeout="5"/>         </tx:attributes>    </tx:advice>       <aop:config>    <!-- 配置一个切入点 -->      <aop:pointcut id="myPointcut" expression="bean(readerService)||bean(bookService)"/>      <!-- 指定在mypointcut切入点应用txAdvice事务增强处理 -->      <aop:advisor advice-ref="txAdvice" pointcut-ref="myPointcut"/>    </aop:config>

由spring框架统一进行事务管理,在业务逻辑层(service层)目标方法之前开启事务,在方法结束后结束事务。

Service层

public class ReaderServiceImpl implements ReaderService {    private IReaderDAO readerDAO;    public IReaderDAO getReaderDAO() {        return readerDAO;    }    public void setReaderDAO(IReaderDAO readerDAO) {        this.readerDAO = readerDAO;    }    @Override    public int register(Reader baseBean){        String name=baseBean.getName();        String telNum=baseBean.getTelNum();                if(readerDAO.getByName(name)!=null||readerDAO.getByTelNum(telNum)!=null)            return -1;                        //-1.当前用户已注册        else{            readerDAO.save(baseBean);               return 1;                          //1.注册成功        }    }@Override    public boolean changePassword(Reader baseBean,String newPassword) {        Reader reader=readerDAO.get(Reader.class, baseBean.getId());        if(reader.getPassword().equals(baseBean.getPassword())){            reader.setPassword(newPassword);            readerDAO.update(reader);            return true;        }else            return false;    }

DAO层

public class IDAOImpl  implements IDAO {    private SessionFactory factory;    private ThreadLocal<Session> local=new ThreadLocal<Session>();    public void setFactory(SessionFactory factory){        this.factory=factory;    }    public SessionFactory getFactory(){        return this.factory;    }    public Session getSession(){        Session session=local.get();        if(session==null){            session=factory.openSession();            local.set(session);        }        return session;    }    @Override    public Serializable save(T entity) {        Session session=getSession();        Serializable id=session.save(entity);        return id;    }    @Override    public void update(T entity) {        Session session=getSession();        session.update(entity);    }

我这里利用了ThreadLocal线程本地变量,为每一个线程绑定一个Session,以避免Session开启过多,增加开销的情况。

但这里就出现了问题,当调用ReaderServiceImpl的register方法(即调用dao的save方法)是有用的,而调用changePassword方法(即dao的update方法)则无用。

解决方法:
将dao中getSession()改为

  public Session getSession(){        return factory.getCurrentSession();    }

分析:
对于Session:
Session是应用程序和数据库层进行交互操作的一个单线程对象,Session是有一个必选的一级缓存的,在显式flush之前,所有的持久化数据都会存在缓存中。
当使用OpenSession打开的Session不会在事务提交时刷新缓存,
而getCurrentSession得到 Session的flushBeforeCompletionEnabled参数为true,会在提交时刷新缓存。
所以update操作会先将更新数据存在一级缓存中,不刷新缓存就是无效。
而save操作有效是因为save方法要求执行方法同时立即执行相应的sql语句,并返回唯一标识符,所以只要事务提交,不刷新缓存也是有效的

1 0
原创粉丝点击