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

在SSH框架整合中遇到使用声明式事务管理时,Hibernate的update操作无效。问题源于Spring Service层与DAO层的交互,使用ThreadLocal线程本地变量绑定Session以减少开销。解决方案是调整DAO层中getSession方法,确保在事务提交时刷新缓存,因为update操作依赖于Session的刷新来生效,而save操作由于立即执行SQL,即使不刷新缓存也能成功。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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语句,并返回唯一标识符,所以只要事务提交,不刷新缓存也是有效的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值