Spring_Spring与DAO_Spring的事务管理

一、Spring的事务管理

     在Spring中通常可以通过以下三种方式来实现对事务的管理:

  1. 使用Spring的事务代理工厂管理事务
  2. 使用Spring的事务注解管理事务
  3. 使用AspectJ的AOP配置管理事务

 二、Spring事务管理API

(1)事务管理接口

1、PlatformTransactionManager接口有2个常用的实现类:

  • DataSourceTransactionManager:使用JDBC或者iBatis进行持久化数据时使用;
  • HibernateTransactionManager:使用Hibernate进行持久化数据时使用。

2、Spring的回滚方式

    Spring事务的默认回滚方式是:发生运行时异常时回滚,发生受查异常时提交。不过对于受查异常,也可以手动设置其回滚方式。

(2)事务定义接口

A、5个事务隔离级别

 

B、定义了7个事务传播行为常量

  • REQUIRE: 指定的方法必须在事务内执行。若当前存在事务,就加入到当前事务中,若当前没有事务,则创建一个新事务。这种传播行为也是最常见的选择,也是Spring默认的事务传播方式;
  • SUPPORTS:指定的方法支持支持当前事务,但若当前没有事务,也可以以非事务方式执行;
  • MANDATORY:指定的方法必须在当前事务内执行,若当前没有事务,则直接抛出异常;
  • REQUIRES_NES:总是新建一个事务,若当前存在事务,就将当前事务挂起,直到新事务执行完毕;
  • NOT_SUPPORTED:指定的方法不能在事务环境中执行,若当前存在事务,就将当前事务挂起‘
  • NEVER:指定的方法不能在事务环境下执行,若当前存在事务,就直接抛出异常;
  • NESTED:指定的方法必须在事务内执行,若当前存在事务,则在嵌套事务内执行;若当前没有事务,则创建一个新事务;

 c、默认事务超时时限

三、程序举例环境搭建

购买股票举例


1、定义实体类及DB表

 

 1 public class Account {
 2     private Integer aid;
 3     private String aname;
 4     private double balance;// 余额
 5     
 6     
 7     public Account() {
 8         super();
 9     }
10 
11 
12     public Account(Integer aid, String aname, double balance) {
13         super();
14         this.aid = aid;
15         this.aname = aname;
16         this.balance = balance;
17     }
18 
19 
20     public Integer getAid() {
21         return aid;
22     }
23 
24 
25     public void setAid(Integer aid) {
26         this.aid = aid;
27     }
28 
29 
30     public String getAname() {
31         return aname;
32     }
33 
34 
35     public void setAname(String aname) {
36         this.aname = aname;
37     }
38 
39 
40     public double getBalance() {
41         return balance;
42     }
43 
44 
45     public void setBalance(double balance) {
46         this.balance = balance;
47     }
48 
49 
50     @Override
51     public String toString() {
52         return "Account [aid=" + aid + ", aname=" + aname + ", balance=" + balance + "]";
53     }
54     
55     
56 }
Account
 1 public class Stock {
 2     private Integer sid;
 3     private String sname;// 股票名称
 4     private int count;// 股票数量
 5     
 6     public Stock() {
 7         super();
 8     }
 9 
10     public Stock(Integer sid, String sname, int count) {
11         super();
12         this.sid = sid;
13         this.sname = sname;
14         this.count = count;
15     }
16 
17     public Integer getSid() {
18         return sid;
19     }
20 
21     public void setSid(Integer sid) {
22         this.sid = sid;
23     }
24 
25     public String getSname() {
26         return sname;
27     }
28 
29     public void setSname(String sname) {
30         this.sname = sname;
31     }
32 
33     public int getCount() {
34         return count;
35     }
36 
37     public void setCount(int count) {
38         this.count = count;
39     }
40 
41     @Override
42     public String toString() {
43         return "Stock [sid=" + sid + ", sname=" + sname + ", count=" + count + "]";
44     }
45 
46     
47     
48 }
Stock

二、定义Service

1 public interface IBuyStockService {
2    void openAccount(String aname,double money);//开用户
3    void openStock(String sname,int amount);
4    
5    void buyStock(String aname,double money,String sname,int amount) throws BuyStockException;
6 }
IBuyStockService
 1 import com.jmu.dao.IAccountDao;
 2 import com.jmu.dao.IStockDao;
 3 
 4 public class BuyStockService implements IBuyStockService {
 5     private IAccountDao adao;
 6     private IStockDao sdao;
 7 
 8     public void setAdao(IAccountDao adao) {
 9         this.adao = adao;
10     }
11 
12     public void setSdao(IStockDao sdao) {
13         this.sdao = sdao;
14     }
15 
16     @Override
17     public void openAccount(String aname, double money) {
18         // TODO Auto-generated method stub
19         adao.insertAccount(aname, money);
20     }
21 
22     @Override
23     public void openStock(String sname, int amount) {
24         // TODO Auto-generated method stub
25         sdao.insertStock(sname, amount);
26     }
27 
28     @Override
29     public void buyStock(String aname, double money, String sname, int amount) throws BuyStockException {
30         // TODO Auto-generated method stub
31         boolean isBuy = true;
32         adao.updateAccount(aname, money, isBuy);
33 
34         if (1 == 1) {
35             throw new BuyStockException("购买股票异常");
36         }
37         sdao.updateStock(sname, amount, isBuy);
38 
39     }
40 
41 }
BuyStockService
 1 public class BuyStockException extends Exception {
 2 
 3     public BuyStockException() {
 4         super();
 5         // TODO Auto-generated constructor stub
 6     }
 7 
 8     public BuyStockException(String message) {
 9         super(message);
10         // TODO Auto-generated constructor stub
11     }
12 
13 }
BuyStockException

三、定义Dao 

1 public interface IAccountDao {
2 
3      void insertAccount(String aname, double money);
4      void updateAccount(String aname, double money, boolean isBuy);
5      
6 
7 }
IAccountDao
1 public interface IStockDao {
2 
3     void insertStock(String sname, int amount);
4     void updateStock(String sname, int amount, boolean isBuy);
5 
6 }
IStockDao
 1 import org.springframework.jdbc.core.support.JdbcDaoSupport;
 2 
 3 public class AccountDaoImpl extends JdbcDaoSupport implements IAccountDao {
 4 
 5     @Override
 6     public void insertAccount(String aname, double money) {
 7         // TODO Auto-generated method stub
 8         String sql = "insert into account(aname,balance) values(?,?)";
 9         this.getJdbcTemplate().update(sql, aname, money);
10     }
11 
12     @Override
13     public void updateAccount(String aname, double money, boolean isBuy) {
14         String sql = "update account set balance=balance+? where aname=?";
15         if (isBuy) {
16             // TODO Auto-generated method stub
17             sql = "update account set balance=balance-? where aname=?";
18         }
19         this.getJdbcTemplate().update(sql, money,aname);
20     }
21 
22 }
AccountDaoImpl
 1 import org.springframework.jdbc.core.support.JdbcDaoSupport;
 2 
 3 public class StockDaoImpl extends JdbcDaoSupport implements IStockDao {
 4 
 5     @Override
 6     public void insertStock(String sname, int amount) {
 7         // TODO Auto-generated method stub
 8         String sql="insert into stock(sname,count) values(?,?)";
 9         this.getJdbcTemplate().update(sql,sname,amount);
10     }
11 
12     @Override
13     public void updateStock(String sname, int amount, boolean isBuy) {
14         // TODO Auto-generated method stub
15         String sql="update stock set count=count-? where sname=?";
16         if (isBuy) {
17             sql="update stock set count=count+? where sname=?";
18         }
19         this.getJdbcTemplate().update(sql,amount,sname);
20     };
21 
22 }
StockDaoImpl

四、导入Jar包

项目结构


 

五、使用事务代理管理事务(方法一)

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <beans xmlns="http://www.springframework.org/schema/beans"
 3     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
 4     xsi:schemaLocation="
 5         http://www.springframework.org/schema/beans 
 6         http://www.springframework.org/schema/beans/spring-beans.xsd
 7         http://www.springframework.org/schema/context 
 8         http://www.springframework.org/schema/context/spring-context.xsd">
 9 <!-- IoC -->
10     
11     <!--注册数据源:C3P0 -->
12     <bean id="myDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
13         <property name="driverClass" value="${jdbc.driver}" />
14         <property name="jdbcUrl" value="${jdbc.url}" />
15         <property name="user" value="${jdbc.user}" />
16         <property name="password" value="${jdbc.password}" />
17     </bean>
18     
19    <!--  注册属性文件 -->
20    <context:property-placeholder location="classpath:jdbc.properties"/>
21    <!--注册Dao -->
22     <bean id="accountDao" class="com.jmu.dao.AccountDaoImpl">
23         <property name="dataSource" ref="myDataSource" />
24 
25     </bean>
26     <bean id="stockDao" class="com.jmu.dao.StockDaoImpl">
27         <property name="dataSource" ref="myDataSource" />
28 
29     </bean>
30 
31     <!-- 注册Service -->
32     <bean id="buyStockService" class="com.jmu.service.BuyStockService">
33         <property name="adao" ref="accountDao" />
34         <property name="sdao" ref="stockDao"/>
35     </bean>
36     
37     
38     <!-- AOP -->
39     <!-- 注册事务管理器 -->
40     <bean id="myTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
41        <property name="dataSource" ref="myDataSource"></property>
42     </bean>
43     
44     <!-- 生成事务代理对象 -->
45     <bean id="serviceProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
46        <property name="transactionManager" ref="myTransactionManager"></property>
47        <property name="target" ref="buyStockService"></property>
48        <property name="transactionAttributes">
49           <props>
50             <prop key="open*">ISOLATION_DEFAULT,PROPAGATION_REQUIRED</prop>
51             <prop key="buyStock">ISOLATION_DEFAULT,PROPAGATION_REQUIRED,-BuyStockException </prop>
52             <!-- 
53                 -异常:表示发生指定异常后 回滚 (通常是受查异常)
54                 +异常:表示发生指定异常后提交 (通常是运行时异常)
55             -->
56           </props>
57        </property>
58     </bean>
59 </beans>
applicationContext.xml

-异常:表示发生指定异常后 回滚 (通常是受查异常)
+异常:表示发生指定异常后提交 (通常是运行时异常)

<!-- 生成事务代理对象 -->
    <bean id="serviceProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
       <property name="transactionManager" ref="myTransactionManager"></property>
       <property name="target" ref="buyStockService"></property>
       <property name="transactionAttributes">
          <props>
            <prop key="open*">ISOLATION_DEFAULT,PROPAGATION_REQUIRED</prop>
            <prop key="buyStock">ISOLATION_DEFAULT,PROPAGATION_REQUIRED,-BuyStockException </prop>
            <!-- 
                -异常:表示发生指定异常后 回滚 (通常是受查异常)
                +异常:表示发生指定异常后提交 (通常是运行时异常)
            -->
          </props>
       </property>
    </bean>
 1 import org.junit.Before;
 2 import org.junit.Test;
 3 import org.springframework.context.ApplicationContext;
 4 import org.springframework.context.support.ClassPathXmlApplicationContext;
 5 
 6 import com.jmu.service.BuyStockException;
 7 import com.jmu.service.IBuyStockService;
 8 
 9 public class MyTest {
10 
11      private IBuyStockService service;
12      
13      @Before
14      public void before(){
15          String resource="applicationContext.xml";
16          ApplicationContext aContext=new ClassPathXmlApplicationContext(resource);
17          service=(IBuyStockService)aContext.getBean("serviceProxy");
18      }
19   
20      @Test
21      public void test01(){
22          service.openAccount("张三", 10000);
23          service.openStock("腾讯", 0);
24          
25      }
26      @Test
27      public void test02() throws BuyStockException{
28          service.buyStock("张三", 2000, "腾讯", 5);
29          
30          
31      }
32     
33     
34 }
MyTest

六、使用注解管理事务(方法二)

Spring配置文件约束

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/tx 
        http://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/aop 
        http://www.springframework.org/schema/aop/spring-aop.xsd">
View Code

    <!-- AOP -->
    <!-- 注册事务管理器 -->
    <bean id="myTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
       <property name="dataSource" ref="myDataSource"></property>
    </bean>
    
    <!-- 注册事务注解驱动 -->
    <tx:annotation-driven transaction-manager="myTransactionManager"/>   
@Transactional(isolation = Isolation.DEFAULT, propagation = Propagation.REQUIRED)
    @Override
    public void openAccount(String aname, double money) {
        // TODO Auto-generated method stub
        adao.insertAccount(aname, money);
    }

    @Transactional(isolation = Isolation.DEFAULT, propagation = Propagation.REQUIRED)
    @Override
    public void openStock(String sname, int amount) {
        // TODO Auto-generated method stub
        sdao.insertStock(sname, amount);
    }

    @Transactional(isolation = Isolation.DEFAULT, propagation = Propagation.REQUIRED,rollbackFor=BuyStockException.class)
    @Override
    public void buyStock(String aname, double money, String sname, int amount) throws BuyStockException {
        // TODO Auto-generated method stub
        boolean isBuy = true;
        adao.updateAccount(aname, money, isBuy);

        if (1 == 1) {
            throw new BuyStockException("购买股票异常");
        }
        sdao.updateStock(sname, amount, isBuy);

    }

输出结果:

七、使用AspectJ的AOP配置管理事务(重点)

导入Jar包

<!-- AOP -->
    <!-- 注册事务管理器 -->
    <bean id="myTransactionManager"
        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="myDataSource"></property>
    </bean>

    <tx:advice id="txAdvice" transaction-manager="myTransactionManager">
        <!--事务属性 -->
        <!--将事务属性织入到方法中 -->
        <tx:attributes>
            <!--这里指定的是为每一个连接点指定所要应用的事务属性 -->
            <tx:method name="open*" isolation="DEFAULT" propagation="REQUIRED" />
            <tx:method name="buyStock" isolation="DEFAULT" propagation="REQUIRED"
                rollback-for="BuyStockException" />
        </tx:attributes>
    </tx:advice>

    <!-- AOP配置 -->
    <aop:config>
        <!--这里指定的是切入点 -->
        <!-- execution(* *..service.*.open*(..)) -->
        <aop:pointcut expression="execution(* *..service.*.*(..))"
            id="myPoint" />
        <aop:advisor advice-ref="txAdvice" pointcut-ref="myPoint" />
    </aop:config>
View Code

 

posted @ 2018-03-01 15:50  honghj  阅读(1325)  评论(0编辑  收藏  举报