一、实验目的

熟练掌握Spring声明式事务管理。

二、实验任务

编写一个模拟银行转账的程序,要求在转账时通过Spring对事务进行控制。

三、实验内容与要求

1. 搭建项目环境

2. 在数据库中创建账户的数据表

3. 创建账户的业务层和持久化层,模拟事务的操作过程和异常处理

4. 分别使用基于XML和基于注解的声明式事务管理方式来实现

5. 通过编写代码实验事务的不同属性(传播机制、隔离级别、是否只读等)

6. 编写测试用例

四、程序设计

一、事务的操作过程和异常处理

正常情况下结果:

Spring事务底层实现_Spring事务底层实现

产生异常的情况下的结果:

Spring事务底层实现_经验分享_02

异常处理之后的结果:

Spring事务底层实现_spring_03

关键部分代码

使用全注解方式

Dao层:

@Repository
public class TxDaoImpl implements TxDao {
    @Autowired
    private  JdbcTemplate jdbcTemplate;
//    增加钱的方法
    @Override
    public void addMoney(String name){
        String sql="update account set money=money+100 where name=?";
        int update = jdbcTemplate.update(sql, name);
        System.out.println(update);
    }
//    减少钱的方法
    @Override
    public void reduceMoney(String name){
        String sql="update account set money=money-100 where name=?";
        int update = jdbcTemplate.update(sql, name);
        System.out.println(update);
    }
}

Service层:

@Service
public class TxService {
    @Autowired
    private TxDao txDao;
    //1,正常情况下事务
    public void TxDemo1(){
        txDao.addMoney("张三");
        txDao.reduceMoney("李四");
    }
    //2,产生异常情况
    public void TxDemo2(){
        txDao.addMoney("张三");
        int i=1/0;
        txDao.reduceMoney("李四");
    }
//    加入事务transational注解,异常处理之后
public void TxDemo3(){
    txDao.addMoney("张三");
    int i=1/0;
    txDao.reduceMoney("李四");
}

测试类:

public class TestSpring {
    @Test
public void txDemo1(){
    ApplicationContext context = new AnnotationConfigApplicationContext(TxConfig.class);
    TxService txService = context.getBean("txService", TxService.class);
    txService.TxDemo1();
}

配置类:

@Configuration
@ComponentScan(basePackages = {"com.wlb.spring"})
@EnableTransactionManagement//开启事务注解
public class TxConfig {
    //创建数据库连接池
    @Bean
    public DruidDataSource getDruidDataSource() {
        DruidDataSource druidDataSource = new DruidDataSource();
        druidDataSource.setDriverClassName("com.mysql.jdbc.Driver");
        druidDataSource.setUrl("jdbc:mysql://localhost:3306/spring?characterEncoding=UTF-8");
        druidDataSource.setUsername("root");
        druidDataSource.setPassword("root");
        return druidDataSource;
    }
    //创建JdbcTemplate对象
    @Bean
    public JdbcTemplate getJdbcTemplate(DataSource dataSource){
        JdbcTemplate jdbcTemplate=new JdbcTemplate();
        jdbcTemplate.setDataSource(dataSource);
        return jdbcTemplate;
    }
    //创建事务管理器对象
    @Bean
    public DataSourceTransactionManager getManger(DataSource dataSource){
        DataSourceTransactionManager dataSourceTransactionManager=new DataSourceTransactionManager();
        dataSourceTransactionManager.setDataSource(dataSource);
        return dataSourceTransactionManager;
    }
  • 使用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:context="http://www.springframework.org/schema/context"
       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.xsd
                           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
                            http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">

    <!--1.引入jdbc,properties文件-->
    <context:property-placeholder location="classpath:jdbc.properties" />
    <!--2.创建数据库连接池-->
    <bean class="com.alibaba.druid.pool.DruidDataSource" id="dataSource">
        <property name="driverClassName" value="${prop.driverClass}" />
        <property name="url" value="${prop.url}"/>
        <property name="username" value="${prop.username}"/>
        <property name="password" value="${prop.password}"/>
    </bean>
    <!--3.创建JdbcTemplate对象-->
    <bean class="org.springframework.jdbc.core.JdbcTemplate" id="jdbcTemplate">
        <property name="dataSource" ref="dataSource"/>
    </bean>
    <!--4.开启组件扫描-->
    <context:component-scan base-package="com.xg.spring"/>
    <!--5.创建事务管理器-->
    <bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager" id="dataSourceTransactionManager">
        <property name="dataSource" ref="dataSource" />
    </bean>
    <!--6.配置通知-->
    <tx:advice transaction-manager="dataSourceTransactionManager" id="transactionInterceptor">
        <!--配置通知相关参数-->
        <tx:attributes>
            <!--指定哪种规则的方法上添加事务-->
            <tx:method name="transfer" propagation="REQUIRED" isolation="READ_COMMITTED"/>
        </tx:attributes>
    </tx:advice>
    <!--配置切入点和切面-->
    <aop:config>
        <!--配置切入点-->
        <aop:pointcut id="pc" expression="execution(* com.xg.spring.service.AccountService.transfer(..))"/>
        <!--配置切面-->
        <aop:advisor advice-ref="transactionInterceptor" pointcut-ref="pc"/>
    </aop:config>
</beans>

不同属性:

1、传播行为(required_new)

Spring事务底层实现_spring_04

//关闭事务addbook()

@Repository
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public class BookDaoImpl implements BookDao{
    @Autowired
    private JdbcTemplate jdbcTemplate;
    @Override
    public void addBook(Book book) {
        String sql="insert into book(name,status) values(?,?)";
        int update = jdbcTemplate.update(sql, book.getName(), book.getStatus());
        System.out.println(update);
    }
}

开启required_NEW事务:

@Transactional(propagation= Propagation.REQUIRED_NEW)
public class TxsService {
    @Autowired
    private BookDao bookDao;
    @Autowired
    private TxDao txDao;
//测试事务的不通属性
    public void TxDemo2(){
        Book book = new Book();
        book.setName("java");
        book.setStatus("1");
        bookDao.addBook(book);
        txDao.addMoney("张三");
    }

2、是否只读readonly

@Service
@Transactional(readOnly = true)
public class TxsService {
    @Autowired
    private BookDao bookDao;
    @Autowired
    private TxDao txDao;
    //测试是否只读属性
    public  void TxDemo3(){
        bookDao.updateBook("数据结构",1);
    }

3、测试是否超时

Spring事务底层实现_bc_05

@Service
@Transactional(timeout = 0)
public class TxsService {
    @Autowired
    private BookDao bookDao;
    @Autowired
    private TxDao txDao;
    //测试是否只读属性
    public  void TxDemo3(){
        bookDao.updateBook("数据结构",1);
    }

4、测试事务回滚

public void TxDemo4(){
        bookDao.updateBook("C++",2);
        int i = 1/0;
        txDao.reduceMoney("李四");
    }}

实验总结

通过这次实验,我在理论基础之上,更深入地理解了事务对于spring所产生的重要作用,掌握了xml和注解形式配置事务的方式,不同方法的事务属性的配置不同,执行的事务也不同。