Spring--事务管理

1、通常在java ee编程中,有两种事务管理的方式:全局事务和本地事务。

  全局事务:可以同时管理多个transaction,但是通常都需要依赖于容器的事务管理

  本地事务:直接使用jdbc的事务管理但是不能同时管理多个事务 

2、但是在spring的事务管理中,它解决了全局事务和本地事务的缺点,它是的程序员可以在任何开发环境中都使用一致的编程模式,而且不依赖与任何的事务管理api。spring提供了声明式事务管理(推荐使用)和编程式事务管理。

spring的事务抽象中,依赖的最重要的一个类就是:org.springframework.transaction.PlatformTransactionManager接口

public interfact PlatformTransactionManager{
    
    TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException;
    
    void commit(TransactionStatus status) throws TransactionException;
    
    void rollback(TransactionStatus status) throws TransactionException;p
}

这是一个最基本的服务提供接口(SPI)。

getTransaction()方法依赖于一个TransactionDefinition类型的参数,返回一个TransactionStatus类型的对象,返回的TransactionStatus可以是一个新的transaction也有可能是一个已存的transaction。一个TransactionStatus总是和一个线程的执行相关联的。

TransactionDefinition接口指明了以下内容:

Isolation(隔离性):当前事务和其他事务是隔离开的

Propagation(传播):通常在事务范围里面执行的代码都会在这个事务里执行,但是,当一个事务已经存在的时候,你可以选择指定在事务方法被执行的事件中的行为,例如:代码可以在已存的事务中持续执行,或者已存的事务可以被挂起,然后一个创建一个新的事务。

Timeout(持久性):当前事务执行多久结束或者自动回滚

Read-only status(只读):但你的代码只是读操作,并没有对数据做修改的时候,就可以选择使用只读事务,只读事务操作在使用hibernate之类的情况下会是一个最佳的优化。

TransactionStatus接口提供了一种简单的方式去控制事务的执行和查询事务状态

public interface TransactionStatus extends SavepointManager {

    boolean isNewTransaction();

    boolean hasSavepoint();

    void setRollbackOnly();

    boolean isRollbackOnly();

    void flush();

    boolean isCompleted();

}

不论使用声明式事务管理还是编程式事务管理,都需要正确的实现PlatformTransactionManager接口,通常都是通过依赖注入来实现。

下面是一种使用最基本的JDBC来实现本地PlatformTransactionManager的例子。

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
    <property name="driverClassName" value="${jdbc.driverClassName}" />
    <property name="url" value="${jdbc.url}" />
    <property name="username" value="${jdbc.username}" />
    <property name="password" value="${jdbc.password}" />
</bean>

相关联的PlatformTransactionManager类的定义需要注入一个dataSource

<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
</bean>

当你使用Java EE容器中的JTA的时候,你可以使用容器的DataSource,下面是一个使用JTA和JNDI的例子:

<?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:jee="http://www.springframework.org/schema/jee"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/jee
        http://www.springframework.org/schema/jee/spring-jee.xsd">

    <jee:jndi-lookup id="dataSource" jndi-name="jdbc/jpetstore"/>

    <bean id="txManager" class="org.springframework.transaction.jta.JtaTransactionManager" />

    <!-- other <bean/> definitions here -->

</beans>

JtaTransactionManager不需要知道DataSource,或者其他特定的资源,因为它使用的是容器的全局事务管理结构。

你也可以更简单使用Hibernate的本地事务管理,但是你需要定义一个hibernate的LocalSessionFactoryBean,用来实例化Hibernate的Session实例。

<bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
    <property name="dataSource" ref="dataSource"/>
    <property name="mappingResources">
        <list>
            <value>org/springframework/samples/petclinic/hibernate/petclinic.hbm.xml</value>
        </list>
    </property>
    <property name="hibernateProperties">
        <value>
            hibernate.dialect=${hibernate.dialect}
        </value>
    </property>
</bean>

<bean id="txManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager">
    <property name="sessionFactory" ref="sessionFactory"/>
</bean>

3、事务中的资源同步

①高级同步实现

  首选的实现是使用spring的最高级模板。这个模板是基于持久综合APIs或者使用本地的ORM APIs和食物通知工厂类或者代理。通常使用JdbcTemplate来实现。

②低级同步实现

  像DataSourceUtils(JDBC用),EntityManagerFactoryUtils(JPA用),SessionFactoryUtils(Hibernate用)PersistenceManagerFactoryUtils(JDO用)等等之类的既存的低级事务管理类。当你想程序代码直接处理本地持久APIs资源类型的时候,你可以使用这些类来保证获得合适的Spring Framework-Managed实例。

例如:在JDBC的时候,使用Spring的org.springframework.jdbc.datasource.DataSourceUtils类来代理传统的JDTC调用getConnection()方法来实现

Connection conn = DataSourceUtils.getConnection(dataSource);

当已经存在一个相关联的同步连接的时候,那么这个连接会被返回,否则的话则会返回一个新的连接。

③TransactionAwareDataSourceProxy

  在很底层存在一个TransactionAwareDataSourceProxy类,这是一个DataSource的代理类,对DataSource类实行了一个包装并且加了一个对Spring管理的事务的认识。

  通常我们都不需要使用这个类,除了既存的代码必须调用并且传递一个标准的DataSource接口实现。

4、声明式事务管理

下面是一个实现转账的具体实例:

表结构定义:

package com.fuwh.dao;

//定义一个出入帐的接口类
public interface MoneyDao {
    
    public abstract void inMoney(int money,int id);
    
    public abstract void outMoney(int money,int id);

    
}
 1 package com.fuwh.dao.impl;
 2 
 3 import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
 4 import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
 5 
 6 import com.fuwh.dao.MoneyDao;
 7 
 8 //出入帐接口类的具体实现类
 9 public class MoneyDaoImpl implements MoneyDao{
10 
11     private NamedParameterJdbcTemplate namedParameterJdbcTemplate;
12     
13     public void setNamedParameterJdbcTemplate(NamedParameterJdbcTemplate namedParameterJdbcTemplate) {
14         this.namedParameterJdbcTemplate = namedParameterJdbcTemplate;
15     }
16 
17     @Override
18     public void inMoney(int money,int id) {
19         // TODO Auto-generated method stub
20         String sql="update t_money set money=money+:money where id=:id";
21         MapSqlParameterSource msps=new MapSqlParameterSource("money", money);
22         msps.addValue("id", id);
23         namedParameterJdbcTemplate.update(sql, msps);
24     }
25 
26     @Override
27     public void outMoney(int money,int id) {
28         // TODO Auto-generated method stub
29         String sql="update t_money set money=money-:money where id=:id";
30         MapSqlParameterSource msps=new MapSqlParameterSource("money",money);
31         msps.addValue("id", id);
32         namedParameterJdbcTemplate.update(sql, msps);
33     }
34 
35 }
package com.fuwh.Service;

//定义一个转账服务类
public interface MoneyService {

    public void transferMoney(int money,int inId,int outId);
}
 1 package com.fuwh.Service.impl;
 2 
 3 import com.fuwh.dao.MoneyDao;
 4 import com.fuwh.Service.MoneyService;
 5 
 6 //转账服务类的具体实现
 7 public class MoneyServiceImpl implements MoneyService {
 8 
 9     private MoneyDao moneyDao;
10     
11     public void setMoneyDao(MoneyDao moneyDao) {
12         this.moneyDao = moneyDao;
13     }
14 
15     @Override
16     public void transferMoney(int money, int inId, int outId) {
17         // TODO Auto-generated method stub
18         moneyDao.outMoney(money, outId);
19         moneyDao.inMoney(money, inId);
20     }
21 
22 }
package com.fuwh.test;

import org.junit.Before;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.fuwh.Service.MoneyService;

//Junit测试类
public class Test {

    private ApplicationContext ac;    

    @Before
    public void setUp() throws Exception {
        ac=new ClassPathXmlApplicationContext("beans.xml");
    }

    @org.junit.Test
    public void testTransfer() {
        MoneyService md=(MoneyService)ac.getBean("moneyService");
        md.transferMoney(50, 1, 2);
    }
}
 1 <?xml version="1.0" encoding="UTF-8"?>
 2 
 3 <beans xmlns="http://www.springframework.org/schema/beans"
 4     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 5     xmlns:aop="http://www.springframework.org/schema/aop"
 6     xmlns:context="http://www.springframework.org/schema/context"
 7     xmlns:tx="http://www.springframework.org/schema/tx"
 8     xsi:schemaLocation="http://www.springframework.org/schema/beans
 9         http://www.springframework.org/schema/beans/spring-beans.xsd
10         http://www.springframework.org/schema/aop
11         http://www.springframework.org/schema/aop/spring-aop.xsd
12         http://www.springframework.org/schema/context
13         http://www.springframework.org/schema/context/spring-context.xsd
14         http://www.springframework.org/schema/tx
15         http://www.springframework.org/schema/tx/spring-tx.xsd">
16 
17     <!-- 配置DataSource
18          这里使用的是apache的dbcp连接池
19          需要引入apache的dbcp连接池jarbao
20          commons-dbcp2-2.1.1.jar 和 commons-pool2-2.4.2.jar
21      -->    
22     <bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close">
23         <property name="driverClassName" value="${jdbc.driverClassName}"/>
24         <property name="url" value="${jdbc.url}"/>
25         <property name="username" value="${jdbc.username}"/>
26         <property name="password" value="${jdbc.password}"/>
27     </bean>
28 
29     <context:property-placeholder location="jdbc.properties"/>
30 
31     <bean id="namedParameterJdbcTemplate" class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate">
32         <constructor-arg ref="dataSource"></constructor-arg>
33     </bean>
34     <bean id="moneyDao" class="com.fuwh.dao.impl.MoneyDaoImpl">
35         <property name="namedParameterJdbcTemplate" ref="namedParameterJdbcTemplate"></property>
36     </bean>
37     <bean id="moneyService" class="com.fuwh.Service.impl.MoneyServiceImpl">
38         <property name="moneyDao" ref="moneyDao"></property>
39     </bean>
40     
41     <!-- 声明所有的方法都使用默认的事务定义 -->
42     <tx:advice id="txAdvice" transaction-manager="txManager">
43         <tx:attributes>
44             <tx:method name="*"/>
45         </tx:attributes>
46     </tx:advice>
47 
48     <aop:config>
49         <aop:pointcut id="txPoint" expression="execution(* com.fuwh.Service.*.*(..))" />
50         <aop:advisor advice-ref="txAdvice" pointcut-ref="txPoint"/>
51     </aop:config>
52     
53     <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
54         <property name="dataSource" ref="dataSource"></property>
55     </bean>
56     
57 </beans>
#jdbc连接配置属性文件
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/db_spring
jdbc.username=root
jdbc.password=mysqladmin

5、编程式事务管理

在spring中提供了两种方式来实现编程式事务管理

  |-使用TransactionTemplate(推荐使用)

  |-使用PlatformTransaxtionManager实现

具体实现实例:

 1 package com.fuwh.Service.impl;
 2 
 3 import com.fuwh.dao.MoneyDao;
 4 
 5 import org.springframework.transaction.TransactionStatus;
 6 import org.springframework.transaction.support.TransactionCallbackWithoutResult;
 7 import org.springframework.transaction.support.TransactionTemplate;
 8 
 9 import com.fuwh.Service.MoneyService;
10 
11 //转账服务类的具体实现
12 public class MoneyServiceImpl implements MoneyService {
13 
14     private TransactionTemplate transactionTemplate;
15 
16     public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
17         this.transactionTemplate = transactionTemplate;
18     }
19 
20     private MoneyDao moneyDao;
21     
22     public void setMoneyDao(MoneyDao moneyDao) {
23         this.moneyDao = moneyDao;
24     }
25 
26     @Override
27     public void transferMoney(final int money, final int inId, final int outId) {
28         // TODO Auto-generated method stub
29         transactionTemplate.execute(new TransactionCallbackWithoutResult() {
30                         
31             @Override
32             protected void doInTransactionWithoutResult(TransactionStatus status) {
33                 // TODO Auto-generated method stub
34                 moneyDao.outMoney(money, outId);
35                 moneyDao.inMoney(money, inId);
36             }
37         });
38     }
39 
40 }
<?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:context="http://www.springframework.org/schema/context"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.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">

    <!-- 配置DataSource
         这里使用的是apache的dbcp连接池
         需要引入apache的dbcp连接池jarbao
         commons-dbcp2-2.1.1.jar 和 commons-pool2-2.4.2.jar
     -->    
    <bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close">
        <property name="driverClassName" value="${jdbc.driverClassName}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>

    <context:property-placeholder location="jdbc.properties"/>

    <bean id="namedParameterJdbcTemplate" class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate">
        <constructor-arg ref="dataSource"></constructor-arg>
    </bean>
    <bean id="moneyDao" class="com.fuwh.dao.impl.MoneyDaoImpl">
        <property name="namedParameterJdbcTemplate" ref="namedParameterJdbcTemplate"></property>
    </bean>
    <bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
        <property name="transactionManager" ref="txManager"></property>
    </bean>
    
    <bean id="moneyService" class="com.fuwh.Service.impl.MoneyServiceImpl">
        <property name="moneyDao" ref="moneyDao"></property>
        <property name="transactionTemplate" ref="transactionTemplate"></property>
    </bean>
    
    <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    
</beans>

6、<tx:advice>配置详解

默认的<tx:advice>是:

传播(propagation):REQUIRED

隔离(Isolation):DEFAULT

事务(Transaction):read/write

持久性(timeout):默认的timeout是底层的事务系统

例如:

<tx:advice id="txAdvice" transaction-manager="txManager" >
        <tx:attributes>
            <tx:method name="*" />
        </tx:attributes>
    </tx:advice>

在<tx:method>标签中,可以加入以下的配置来更改默认的设置

属性 必须? 默认 描述
name 必须   匹配的方法,*:所有的方法,get*:以get开头的方法等等
propagation 非必须 REQUIRED 食物传播行为
isolation 非必须 DEFAULT 事务隔离等级
timeout 非必须 -1 timeout的时间(秒单位)
read-only 非必须 false 是否只读
rollback-for 非必须   rollback的时候执行的方法
no-rollback-for 非必须   没有触发rollback的时候执行的方法



原文地址:https://www.cnblogs.com/zerotomax/p/6285342.html