Fork me on GitHub

Spring(九)Spring对事务的支持

一、对事务的支持

事务:是一组原子操作的工作单元,要么全部成功,要么全部失败

Spring管理事务方式:

  • JDBC编程事务管理:--可以控制到代码中的行

可以清楚的控制事务的边界,事务控制粒度化细(编程的方式

  • JDBC声明事务管理---可以控制到方法

事务相关API不用介入程序之中,将事务管理与实际业务代码解耦合(配置XML的方式)

 

 

二、JDBC编程事务管理

Spring提供两种方式实现编程式的事务管理:

  • 实现PlatformTransactionManager接口
  • 使用TransactionTemplate模式

2.1、实现PlatformTransactionManager接口

大致步骤:

  • 指定PlatformTransactionManager的实现类
  • 定义事务TransactionDefinition
  • 将事务定义传送给TransactionStatus
  • 将欲进行的事务用try..catch语句封起来
  • 如果事务出错,调用PlatformTransactionManager的rollback方法
package com.pb.transaction.demo;

import javax.sql.DataSource;

import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;

/**
 * 使用TransactionManager事务管理
 * 缺点:侵入代码
 * 优点:控制度细粒度
 */
public class TransactionManagerDemo {
    
    public static void main(String[] args) {
    ClassPathXmlApplicationContext cpx=new ClassPathXmlApplicationContext("applicationContext.xml");    
    //获取platform对象
    PlatformTransactionManager ptm=(PlatformTransactionManager) cpx.getBean("transactionManager");
    //事务定义器
    DefaultTransactionDefinition dtd=new DefaultTransactionDefinition();
    //设置事务定义器的行为
    dtd.setPropagationBehavior(DefaultTransactionDefinition.PROPAGATION_REQUIRED);
    //事务状态通过事务管理器创建
    TransactionStatus ts=ptm.getTransaction(dtd);
    
    //进行事务
    
    try {
        //获取数据源
        DataSource ds=(DataSource) cpx.getBean("dataSource");
        //创建JDBCTemplacte
        JdbcTemplate jt=new JdbcTemplate(ds);
        //执行更新或者插入等操作
        jt.update("insert into person values(11,'TTM',23)");
        jt.update("update person set name='张王八' where id=7");
        ptm.commit(ts);
        
        System.out.println("===========");
    } catch (Exception e) {
        ptm.rollback(ts);
        System.out.println("撤消=======");
        e.printStackTrace();
    }
    
    }

}

 

2.2、使用TransactionTemplate模式

 

大致步骤:

  • 需要封装一个TransactionManager
  • 创建事务回滚类
  • 执行TransactionManager的execute()方法
package com.pb.transaction.demo;

import javax.sql.DataSource;

import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;

/**
 * 使用TransactionTemplate事务管理 缺点:侵入代码 优点:控制度细粒度
 */
public class TransactionTeplateDemo {

    public static void main(String[] args) {
        ClassPathXmlApplicationContext cpx = new ClassPathXmlApplicationContext(
                "applicationContext.xml");
        // 获取platform对象
        PlatformTransactionManager ptm = (PlatformTransactionManager) cpx
                .getBean("transactionManager");
        // 事务模版
        TransactionTemplate tt = new TransactionTemplate(ptm);
        // 获取数据源
        DataSource ds = (DataSource) cpx.getBean("dataSource");
        // 创建JDBCTemplacte
        final JdbcTemplate jt = new JdbcTemplate(ds);
        // 进行事务回调函数
        tt.execute(new TransactionCallbackWithoutResult() {

            @Override
            protected void doInTransactionWithoutResult(TransactionStatus arg0) {
                // 执行更新或者插入等操作
                jt.update("insert into person values(17,'TOM',23)");
                jt.update("update person set name='李四3' where id=4");


            }
        });

        
    }

}

 

2.3、编程事务配置

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

<!-- 声明数据源  org.springframework.jdbc.datasource.DriverManagerDataSource/com.mchange.v2.c3p0.ComboPooledDataSource-->                    
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<!--驱动  -->
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
<!--url  -->
<property name="url" value="jdbc:oracle:thin:@localhost:1521:orcl"/>
<!--用户名  -->
<property name="username" value="accp"/>
<!--密码  -->
<property name="password" value="accp"/>
</bean>

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

 

三、JDBC声明事务管理

主要通过AOP功能实现

不需要修改原有的类

使用TransationProxyFactoryBean指定要介入的事务以及方法

实体类:数据库中有与之相对应的表

package com.pb.entity;

public class Person {
    private Long id;
    private String name;
    private Integer age;
    public Long getId() {
        return id;
    }
    public void setId(Long id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Integer getAge() {
        return age;
    }
    public void setAge(Integer age) {
        this.age = age;
    }
    
    
}

dao和实现类

package com.pb.dao;

import java.util.List;

import com.pb.entity.Person;

public interface PersonDao {

    public int insert(Person p);
    
    public int batchInsert(List<Person> persons);
    
}
//实现类
package com.pb.dao.impl;

import java.util.List;

import javax.sql.DataSource;

import org.springframework.jdbc.core.JdbcTemplate;

import com.pb.dao.PersonDao;
import com.pb.entity.Person;

public class PersonDaoImpl implements PersonDao {
    private JdbcTemplate jdbcTemplate;
    
    public void setDataSource(DataSource ds){
        jdbcTemplate=new JdbcTemplate(ds);
    }
    @Override
    public int insert(Person p) {
        String sql="insert into person values(?,?,?)";
        Object [] params={p.getId(),p.getName(),p.getAge()};
        return jdbcTemplate.update(sql,params);
    }

    @Override
    public int batchInsert(List<Person> persons) {
        int count=0;
        for (Person person : persons) {
            insert(person);
            count++;
        }
        return count;
    }

}

测试类

package com.pb.transation.aop.demo;

import java.util.ArrayList;
import java.util.List;

import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.pb.dao.PersonDao;
import com.pb.entity.Person;

public class FirstAOPTransationDemo {

    public static void main(String[] args) {
        ClassPathXmlApplicationContext cpx=new ClassPathXmlApplicationContext("applicationContext.xml");    
        //这里调用代理的类
        PersonDao personDao=(PersonDao) cpx.getBean("personDaoProxy");
        
        Person p1=new Person();
        p1.setId(new Long(28));
        p1.setName("朱雀");
        p1.setAge(199);
        Person p2=new Person();
        p2.setId(new Long(29));
        p2.setName("玄武");
        p2.setAge(150);
        List<Person> persons=new ArrayList<Person>();
        persons.add(p1);
        persons.add(p2);
        int count=personDao.batchInsert(persons);
        System.out.println("更新了,"+count+"条记录");
        
    }

}

applicationContext.xml配置文件

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

<!-- 声明数据源  org.springframework.jdbc.datasource.DriverManagerDataSource/com.mchange.v2.c3p0.ComboPooledDataSource-->                    
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<!--驱动  -->
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
<!--url  -->
<property name="url" value="jdbc:oracle:thin:@localhost:1521:orcl"/>
<!--用户名  -->
<property name="username" value="accp"/>
<!--密码  -->
<property name="password" value="accp"/>
</bean>
<!--接口实现类  -->
<bean id="personDao" class="com.pb.dao.impl.PersonDaoImpl">
<property name="dataSource" ref="dataSource"></property>
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<bean id="personDaoProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<!--指定接口  -->
<property name="proxyInterfaces" >
<list>
<value>com.pb.dao.PersonDao</value>
</list>
</property>
<!-- 管理的目标 -->
<property name="target" ref="personDao"/>
<!--注入事务管理  -->
<property name="transactionManager" ref="transactionManager"></property>
<!--事务管理的方法 和方式 -->
<property name="transactionAttributes">
<props>
<prop key="batch*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>


</beans>

四、事务的属性

声明式事务以方法为边界,简单的讲,一个方法被看成一个事务

Spring中事务的属性:

  • 传播行为(Propagation Behavior)
  • 隔离级别(Lsolation Level)
  • 只读提示(Rean-only Hints)
  • 事务超时期限(The Transaction Timeout period)

4.1、传播行为

4.2、隔离级别

 

五、Spring2.0后声明式事务管理:基于XMLSchema

步骤:

  1. 加入相关的XML命名空间
  2. 使用<tx:advice>标签指定Advice
  3. 使用<aop:config>标签配置事务管理
<?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: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.1.xsd
    http://www.springframework.org/schema/aop
    http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
    http://www.springframework.org/schema/tx
    http://www.springframework.org/schema/tx/spring-tx-3.1.xsd">

<!-- 声明数据源  org.springframework.jdbc.datasource.DriverManagerDataSource/com.mchange.v2.c3p0.ComboPooledDataSource-->                    
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<!--驱动  -->
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
<!--url  -->
<property name="url" value="jdbc:oracle:thin:@localhost:1521:orcl"/>
<!--用户名  -->
<property name="username" value="accp"/>
<!--密码  -->
<property name="password" value="accp"/>
</bean>
<!--接口实现类  -->
<bean id="personDao" class="com.pb.dao.impl.PersonDaoImpl">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--事务管理的类  -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--指明事务管理  -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<!--指定方法和方式  -->
<tx:attributes>
<tx:method name="batch*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<aop:config>
<!--切入点  -->
<aop:pointcut expression="execution(* com.pb.dao.PersonDao.*(..) )" id="mypoint"/>
<!--关切入点和切入对象事务  -->
<aop:advisor advice-ref="txAdvice" pointcut-ref="mypoint"/>
</aop:config>
</beans>

六、基于注解的事务管理

package com.pb.dao.impl;

import java.util.List;

import javax.sql.DataSource;

import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.pb.dao.PersonDao;
import com.pb.entity.Person;
//在要管理的类下加上@transactional
@Transactional
public class PersonDaoImpl implements PersonDao {
    private JdbcTemplate jdbcTemplate;
    
    public void setDataSource(DataSource ds){
        jdbcTemplate=new JdbcTemplate(ds);
    }
    @Override
    public int insert(Person p) {
        String sql="insert into person values(?,?,?)";
        Object [] params={p.getId(),p.getName(),p.getAge()};
        return jdbcTemplate.update(sql,params);
    }
    //在要管理的方法下加上属性propagation=Propagation.REQUIRED
    @Transactional(propagation=Propagation.REQUIRED)
    public int batchInsert(List<Person> persons) {
        int count=0;
        for (Person person : persons) {
            insert(person);
            count++;
        }
        return count;
    }

}

配置文件中加入一条

<?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: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.1.xsd
    http://www.springframework.org/schema/aop
    http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
    http://www.springframework.org/schema/tx
    http://www.springframework.org/schema/tx/spring-tx-3.1.xsd">

<!-- 声明数据源  org.springframework.jdbc.datasource.DriverManagerDataSource/com.mchange.v2.c3p0.ComboPooledDataSource-->                    
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<!--驱动  -->
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
<!--url  -->
<property name="url" value="jdbc:oracle:thin:@localhost:1521:orcl"/>
<!--用户名  -->
<property name="username" value="accp"/>
<!--密码  -->
<property name="password" value="accp"/>
</bean>
<!--接口实现类  -->
<bean id="personDao" class="com.pb.dao.impl.PersonDaoImpl">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--事务管理的类  -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--指明注解方式的事务管理器  -->
<tx:annotation-driven transaction-manager="transactionManager"/>


</beans>

 

posted @ 2015-04-12 17:28  森林森  阅读(1929)  评论(0编辑  收藏  举报