spring

十、Spring事务编程

2019-01-10  本文已影响2人  I墨雨

环境搭建

create table account(
    id int primary key auto_increment,
    name varchar(20),
    money double
);
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql:///spring
jdbc.username=root
jdbc.password=123456
<?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"
       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">

    <!--加载属性文件,context方式-->
    <context:property-placeholder location="classpath:jdbc.properties"/>
    <!--配置druid连接池,表达式获取属性文件参数-->
    <bean id="druid" class="com.alibaba.druid.pool.DruidDataSource">
        <!--key值不能和name一样,加前缀jdbc.-->
        <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>
    <!--注入JdbcTemplate模板-->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="druid"/>
    </bean>

</beans>
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class SpringTest {
    @Resource(name = "jdbcTemplate")
    private JdbcTemplate jdbcTemplate;

    @Test
    public void test() {
        jdbcTemplate.update("insert into account value(null,?,?)", "ls", 10000d);
    }
}

如果能插入一条数据,则证明我们已经搭建好环境了!(要注意数据库名有没有写错!)

事务准备

package com.itlike.dao;

public interface AccountDao {
    //加钱:给谁?多少钱?
    public void addMoney(String name,Double money);
    //减钱:减谁?多少钱?
    public void minusMoney(String name,Double money);
}
//继承JdbcDaoSupport
public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao{
    @Override
    public void addMoney(String name, Double money) {
        this.getJdbcTemplate().update("update account set money=money+? where name=?",money,name);
    }

    @Override
    public void minusMoney(String name, Double money) {
        this.getJdbcTemplate().update("update account set money=money-? where name=?",money,name);
    }
}
<!--Spirng管理实现类-->
<bean id="accountDao" class="com.itlike.dao.AccountDaoImpl">
    <property name="dataSource" ref="druid"/>
</bean>

业务需求

public interface AccountService {
    // 转钱,谁给谁转?转多少?
    public void transferMoney(String from, String to, Double money);
}
public class AccountServiceImpl implements AccountService {
    //使用xml方式注入
    private AccountDao accountDao;
    public void setAccountDao(AccountDao accountDao) {
        this.accountDao = accountDao;
    }
    //转账方法
    @Override
    public void transferMoney(String from, String to, Double money) {
        this.accountDao.minusMoney(from,money);
        this.accountDao.addMoney(to,money);
    }
}
<bean id="accountService" class="com.itlike.service.AccountServiceImpl">
    <property name="accountDao" ref="accountDao"/>
</bean>

测试方法

现有两条记录:


Image 1.png
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class SpringTest {
    @Resource(name = "accountService")
    private AccountService accountService;

    @Test
    public void test() {
        accountService.transferMoney("zs","ls",50d);
    }
}

转账成功!


Image 3.png

事务问题

public void transferMoney(String from, String to, Double money) {
    this.accountDao.minusMoney(from,money);
    int i = 1/0;    //发生异常
    this.accountDao.addMoney(to,money);
}
1.PNG

会发现,za账户的钱已经减少,但ls账户的钱却没有增加,这是为什么呢?
这就是没有添加事务机制所造成的情况,zs账户钱已经减少了,但ls账户的钱还来不及增加,系统就因为发生了异常而停止运行了!
为此,我们可以添加事务机制,让发生异常时,保证业务安全。

编程式事务

需要手动编写代码

<!--配置事务管理器-->
  <bean id="transactionManager" 
        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
  </bean>

简化事务操作的模板

<bean id="transactionTemplate"
      class="org.springframework.transaction.support.TransactionTemplate">
    <property name="transactionManager" ref="transactionManager"/>
</bean>
//添加事务模板
private TransactionTemplate transactionTemplate;
public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
    this.transactionTemplate = transactionTemplate;
}

//转账方法
@Override
public void transferMoney(String from, String to, Double money) {
    this.accountDao.minusMoney(from,money);
    int i = 1/0;    //发生异常
    this.accountDao.addMoney(to,money);
}
<bean id="accountService" class="com.itlike.service.AccountServiceImpl">
    <property name="accountDao" ref="accountDao"/>
    <!-- ref映射事务管理模板transactionTemplate -->
    <property name="transactionTemplate" ref="transactionTemplate"/>
</bean>

事务配置中有回调方法

@Override
public void transferMoney(String from, String to, Double money) {
    //这是回调方法(匿名内部类)
    this.transactionTemplate.execute(new TransactionCallbackWithoutResult() {
        @Override
        protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
            //在这里添加业务代码
        }
    });

}
//转账方法
@Override
public void transferMoney(String from, String to, Double money) {
    this.transactionTemplate.execute(new TransactionCallbackWithoutResult() {
        @Override
        protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
            //匿名内部类中不能使用this
            accountDao.minusMoney(from,money);
            int i = 1/0;    //发生异常
            accountDao.addMoney(to,money);
        }
    });
}
1.PNG

声明式事务XML方式声明事务管理

把代码重置到使用编程式事务之前。

<!--配置事务管理器-->
<bean id="transactionManager"
      class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="druid"/>
</bean>

若tx报红,有两个原因:jar包没导入名称空间

<!--AOP增强事务配置-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
    <tx:attributes>
        <tx:method name="*" propagation="REQUIRED"/>
    </tx:attributes>
</tx:advice>
<!--把AOP增强添加到方法里-->
<aop:config>
    <!--第一个*是任意返回值,第二个*是指给该类里所有方法都织入Aop方法,..代表任意参数-->
    <aop:pointcut id="pointcut" expression="execution(* com.itlike.service.AccountServiceImpl.*(..))"/>
    <aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut"/>
</aop:config>

运行测试方法,可以看到,当发生除0异常时,表记录不会发生改变!

声明式事务注解方式声明事务管理

把代码重置到使用编程式事务之前。

<!--配置事务管理器-->
<bean id="transactionManager"
      class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="druid"/>
</bean>
<!--开启注解事务-->
<tx:annotation-driven transaction-manager="transactionManager"/>
@Transactional
//@Transactional(isolation= ,propagation= ) 设置隔离级别、传播行为 
public class AccountServiceImpl implements AccountService {
    //使用xml方式注入
    private AccountDao accountDao;
    public void setAccountDao(AccountDao accountDao) {
        this.accountDao = accountDao;
    }

    //转账方法
    @Override
    public void transferMoney(String from, String to, Double money) {

        this.accountDao.minusMoney(from,money);
        //int i = 1/0;    //发生异常
        this.accountDao.addMoney(to,money);

    }
}

运行测试方法,可以看到,当发生除0异常时,表记录不会发生改变!

上一篇 下一篇

猜你喜欢

热点阅读