spring学习笔记(7)——spring事务管理方式

8 篇文章 0 订阅

spring事务管理有两种方式:一种是传统的编程式事务管理,即通过编写代码实现事务的管理,包括定义事务的开始、程序正常执行后事务提交、异常时进行事务回滚。
另一种是基于AOP技术实现的声明式事务,其主要思想是将事务管理作为一个“方面”代码单独编写,程序员只关心核心业务逻辑代码,然后通过AOP技术将事务管理的“方面”代码织入到业务类中。

下面通过一个银行转账的例子说明事务:
首先先配置好ssh框架见spring笔记(6)。

  1. 数据库实体类和映射文件
    这里写图片描述
    实体类:
package com.test.bean;

public class Account {
    private int id;
    private String accountNo;
    private double balance;
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getAccountNo() {
        return accountNo;
    }
    public void setAccountNo(String accountNo) {
        this.accountNo = accountNo;
    }
    public double getBalance() {
        return balance;
    }
    public void setBalance(double balance) {
        this.balance = balance;
    }

}

2、DAO层

package com.test.dao;

import java.util.List;

import com.test.bean.Account;

public interface AccountDAO {
    // 根据账号获取账户对象
    public List getAccountByAccountNo(String accountNo);

    // 转账
    public void transfer(Account a1, Account a2);

}
package com.test.dao.impl;

import java.util.List;

import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

import com.test.bean.Account;
import com.test.dao.AccountDAO;

public class AccountDAOImpl extends HibernateDaoSupport implements AccountDAO {


    //转账
    public void transfer(Account a1, Account a2) {
        this.getHibernateTemplate().update(a1);
        this.getHibernateTemplate().update(a2);
    }

    //根据账号获取账户对象
    public List getAccountByAccountNo(final String accountNo) {
        // TODO Auto-generated method stub
        String hql ="from Account account where account.accountNo=?";   
        return this.getHibernateTemplate().find(hql,accountNo);
    }
}

3、service层

package com.test.service;

import java.util.List;

import com.test.bean.Account;

public interface AccountService {
    // 根据账号获取账户对象
    public List getAccountByAccountNo(String accountNo);

    // 转账
    public void transfer(Account a1, Account a2);
}
package com.test.service.impl;

import java.util.List;

import com.test.bean.Account;
import com.test.dao.AccountDAO;
import com.test.service.AccountService;

public class AccountServiceImpl implements AccountService{
    //用AccountDAO接口声明对象,并添加set方法用于依赖注入
    AccountDAO accountDAO;
    public void setAccountDAO(AccountDAO accountDAO) {
        this.accountDAO = accountDAO;
    }

    //转账
    //使用@Transactional注解实现transfer方法的事务管理
    public void transfer(Account a1, Account a2) {
        accountDAO.transfer(a1, a2);
    }
    //根据账号获取账户对象
    public List getAccountByAccountNo(String accountNo) {
        // TODO Auto-generated method stub
        return accountDAO.getAccountByAccountNo(accountNo);
    }

}

4、action层

package com.test.action.account;

import java.util.List;

import com.opensymphony.xwork2.ActionSupport;
import com.test.bean.Account;
import com.test.service.AccountService;

public class AccountManagerAction extends ActionSupport {
    // 定义属性,用于封装表单数据
    private String ac1;
    private String ac2;
    private String amount;

    public String getAc1() {
        return ac1;
    }

    public void setAc1(String ac1) {
        this.ac1 = ac1;
    }

    public String getAc2() {
        return ac2;
    }

    public void setAc2(String ac2) {
        this.ac2 = ac2;
    }

    public String getAmount() {
        return amount;
    }

    public void setAmount(String amount) {
        this.amount = amount;
    }

    // 使用AccountBiz接口声明对象,并添加set方法用于依赖注入
    private AccountService service;

    public void setAccountService(AccountService service) {
        this.service = service;
    }

    @Override
    // 执行请求
    public String execute() throws Exception {
        System.out.println(ac1);
        System.out.println(ac2);
        Account a1 = null;
        Account a2 = null;
        // 获取账号ac1的账户对象,并更新对象中的账户余额属性
        List list1 = service.getAccountByAccountNo(ac1);
        if (list1.size() > 0) {
            a1 = (Account) list1.get(0);
            System.out.println("ac1");
            a1.setBalance((a1.getBalance() - Double.parseDouble(amount)));
        }
        // 获取账号ac2的账户对象,并更新对象中的账户余额属性
        List list2 = service.getAccountByAccountNo(ac2);
        if (list2.size() > 0) {
            a2 = (Account) list2.get(0);
            System.out.println("ac2");
            a2.setBalance((a2.getBalance() + Double.parseDouble(amount)));
        }
        try {
            // 执行转账操作
            service.transfer(a1, a2);
            System.out.println("transfer");
        } catch (Exception e) {
            // 转账失败
            System.out.println(e);
            return "error1";
        }
        // 转账成功
        return "success1";
    }
}

5、spring配置文件applicationContext.xml中配置相关类

<!--
        定义AccountDAOImpl类实例,并将已经创建LocalSessionFactoryBean的实例
        sessionFactory依赖注入到UserDAOImpl类所继承的 HibernateDaoSupport
        的sessionFactory属性
    -->
    <bean id="accountDAO" class="com.test.dao.impl.AccountDAOImpl">
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>


    <bean id="accountService" class="com.test.service.impl.AccountServiceImpl">
        <property name="accountDAO" ref="accountDAO" />
    </bean>


    <!--
        部署Struts 2的负责账户管理的控制器AccountManager
    -->
    <bean id="amAction" class="com.test.action.account.AccountManagerAction">
        <property name="accountService" ref="accountService" />
    </bean>

6、struts.xml配置

<action name="doTransfer" class="amAction">
            <!-- 定义处理结果和资源之间的映射关系 -->
            <result name="error1">error1.jsp</result>
            <result name="success1">success1.jsp</result>
</action>

7、配置声明事务
(1)、在spring配置文件中增加事务管理所需的常用命名空间声明

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
    xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/tx 
    http://www.springframework.org/schema/tx/spring-tx-3.0.xsd 
    http://www.springframework.org/schema/aop 
    http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">

(2)、声明事务管理器,在声明事务管理器时需要注入sessionFactory属性。定义事务通知,定义事务通知时需要指定一个事务管理器,然后在其属性中声明事务规则。

    <!-- 声明事务管理器 -->
    <bean id="transactionManager"
        class="org.springframework.orm.hibernate3.HibernateTransactionManager">
        <property name="sessionFactory">
            <ref bean="sessionFactory" />
        </property>
    </bean>
    <!-- 定义事务通知 -->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <!-- 指定事务传播规则 -->
        <tx:attributes>
            <!-- 对get打头的方法应用SUPPORTS事务规则 -->
            <tx:method name="get*" propagation="SUPPORTS" />
            <!-- 对其他方法应用REQUIRED事务规则 -->
            <tx:method name="*" propagation="REQUIRED"></tx:method>
        </tx:attributes>
    </tx:advice>

    <!-- 定义切面,并将事务通知和切面组合(定义哪些方法应用事务规则) -->
    <aop:config>
        <aop:pointcut id="serviceMethods" expression="execution(* com.test.service.*.*(..))" />
        <!-- 将事务通知和切面组合 -->
        <aop:advisor advice-ref="txAdvice" pointcut-ref="serviceMethods" />
    </aop:config>

8、编写测试页面

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags"%>
 <html> 
    <head>
        <title>转账页面</title>
    </head>
    <body>
       <s:form action="doTransfer.action">
            <s:textfield name="ac1" label="账户1"  /> 
             <s:textfield name="ac2" label="账户2"  /> 
             <s:textfield name="amount" label="转账金额"  /> 
             <s:submit value="转账"  /> 
       </s:form>

    </body>
</html>

第一次测试:
这里写图片描述
数据库:
这里写图片描述
第二次测试:
这里写图片描述
数据库:
这里写图片描述
账户输入错误,两个账户余额均不变化。
第三次测试:
将spring配置文件中一下代码删去,及删除声明式事务。重启工程后。
在执行第二次的操作:
这里写图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值