一、概述

Spring的事务管理分成两类:

  1. 编程式事务管理(手动编写代码完成事务管理)
  2. 声明式事务管理(不需要手动编写代码,需要配置)

二、准备工作

1. 创建表

 CREATE TABLE `account` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(10) DEFAULT NULL,
`money` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB

2. 创建项目并引入Maven依赖

  创建项目并引入如下Maven依赖:

<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.5.RELEASE</version>
</dependency> <dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.13</version>
</dependency> <!-- https://mvnrepository.com/artifact/c3p0/c3p0 -->
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
</dependency> <!-- Spring 整合测试的包 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>

结构目录如下:

3. 编写实体类

public class Account {
private Integer id;
private String name;
private Integer money;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getMoney() {
return money;
}
public void setMoney(Integer money) {
this.money = money;
}
@Override
public String toString() {
return "Account [id=" + id + ", name=" + name + ", money=" + money + "]";
}
}

4. 编写Dao层

编写接口


/**
* 银行账户的相关操作 此处用了@see注释,在实现类可以继承接口中方法的注释内容
*
* @author hao
* @see AccountDaoImpl
*
*/
public interface IAccountDao { /**
* 添加账户
*
* @param account 要添加的账户
*/
public void add(Account account); /**
* 转出的方法
*
* @param from :转出的账户,打出钱
* @param money :要转账金额
*/
public void out(Account from, Integer money); /**
* 转出的方法
*
* @param to 转入的账户,收到钱
* @param money 要转账金额
*/
public void in(Account to, Integer money); /**
* 通过名字查询账户
* @param name 账户名
* @return
*/
public Account selectOneByName(String name); }

实现类

public class AccountDaoImpl implements IAccountDao{

    @Autowired
@Qualifier("jdbcTemplate")
private JdbcTemplate jdbcTemplate; @Override
public void add(Account account) {
String sql = "insert into account values(null,?,?)";
jdbcTemplate.update(sql,account.getName(),account.getMoney());
} @Override
public Account selectOneByName(String name) {
String sql = "select * from account where name = ?";
Account account = null;
try {//这里需要捕获结果集为空时的异常
account = jdbcTemplate.queryForObject(sql, new RowMapper<Account>() { @Override
public Account mapRow(ResultSet rs, int rowNum) throws SQLException {
Account account = new Account();
account.setId(rs.getInt("id"));
account.setName(rs.getString("name"));
account.setMoney(rs.getInt("money"));
return account;
} }, name);
} catch (EmptyResultDataAccessException e) {
e.printStackTrace();
return null;
} return account;
} public void out(Account from, Integer money) {
String sql = "update account set money = money-? where name =? ";
jdbcTemplate.update(sql, money,from.getName());
} public void in(Account to, Integer money) {
String sql ="update account set money = money+? where name =?";
jdbcTemplate.update(sql,money,to.getName());
} }

5. 业务层

接口

/**
*
* @author hao
* @see AccountServiceImpl
*/
public interface IAccountService { /**
* 向数据库中添加用户
*
* @param account 要添加的用户对象
*/
public void addAccount(Account account); /**
* 转账的方法
*
* @param from 转出的账户
* @param to 转入的账户
* @param money 转账金额
*/
public void transfer(Account from, Account to, Integer money); /**
*
* @param name 需要查询的账户名
* @return
*/
public Account findAccountByName(String name);
}

实现类

/**
* 没有添加事务
* @author hao
*
*/
public class AccountServiceImpl implements IAccountService {
// 注入 accountDao 利用setter方法注入属性
private IAccountDao accountDao; public void setAccountDao(IAccountDao accountDao) {
this.accountDao = accountDao;
} @Override
public void addAccount(Account account) {
accountDao.add(account);
} @Override
public Account findAccountByName(String name) {
Account account = accountDao.selectOneByName(name);
return account;
} @Override
public void transfer(Account from, Account to, Integer money) {
accountDao.out(from, money);// 转出钱
int i= 1/0 //出现异常时
accountDao.in(to, money);// 收入钱
}
}

6. 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"
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"> <context:property-placeholder location="classpath:jdbc.properties"/> <!-- 配置c3p0连接池 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driver}"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="user" value="${jdbc.user}"/>
<property name="password" value="${jdbc.password}"/>
</bean> <!-- 这里需要注入数据源 -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean> <!-- 此处声明Dao层类,用注解的方式将jdbcTemplate注入到了accountDao中,也可用其他方式 -->
<bean id="accountDao" class="com.hao.tx.dao.impl.AccountDaoImpl"></bean> <!-- 此处声明业务层类,用setter的方式注入了accountDao -->
<bean id="accountService" class="com.hao.tx.service.impl.AccountServiceImpl">
<property name="accountDao" ref="accountDao"></property>
</bean> </beans>

7. 测试

@Test
public void test02() {
System.out.println("转账之前....");
Account a = accountService.findAccountByName("a");
if(a != null) {
System.out.println(a);
} Account b = accountService.findAccountByName("b");
if(b!=null) {
System.out.println(b);
} try {//这里捕获转账时出现的异常
System.out.println("开始转账.....");
accountService.transfer(a, b, 100);
}catch(ArithmeticException e) {
e.printStackTrace();
}finally {
System.out.println("转账之后....");
Account a_trans = accountService.findAccountByName("a");
if(a != null) {
System.out.println(a_trans);
}
Account b_trans = accountService.findAccountByName("b");
if(b!=null) {
System.out.println(b_trans);
}
}
}

结果分析:
  运行测试类中test02 之后会发现,如果没有事务处理的话,即使出现异常,也会改变数据库中的数据
  结果如下:
  
  

  
  

三、编程式事务

  上面程序中并没有添加事务,下面用手动编码的方式完成事务管理,需要事务管理器去真正管理事务对象,Spring提供了事务管理的模板(工具类)
  关于平台事务管理器,可以查阅【Spring】事务

1. 在业务层代码上使用事务模板

  创建业务类并使用编程式事务去进行事务管理,Spring 中提供了管理事务的模版

/**
* 编程式事务
*
* @author hao
*
*/
public class AccountServiceImpl_Program implements IAccountService { // 注入 accountDao 利用setter方法注入属性
private IAccountDao accountDao; public void setAccountDao(IAccountDao accountDao) {
this.accountDao = accountDao;
} // 注入 transactionTemplate 利用setter方法注入属性
private TransactionTemplate transactionTemplate; public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
this.transactionTemplate = transactionTemplate;
} @Override
public void addAccount(Account account) {
accountDao.add(account);
}
@Override
public Account findAccountByName(String name) {
Account account = accountDao.selectOneByName(name);
return account;
} @Override
public void transfer(Account from, Account to, Integer money) {
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus status) {
accountDao.out(from, money);
int d = 1 / 0;
accountDao.in(to, money);
}
});
} }

2. 在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"
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"> <context:property-placeholder location="classpath:jdbc.properties" />
<!-- 配置c3p0连接池 -->
<bean id="dataSource"
class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driver}" />
<property name="jdbcUrl" value="${jdbc.url}" />
<property name="user" value="${jdbc.user}" />
<property name="password" value="${jdbc.password}" />
</bean> <!-- 在容器中声明jdbc模版,这里需要注入数据源 -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean> <!-- 此处声明Dao层类,用注解的方式将jdbcTemplate注入到了accountDao中,也可用其他方式 -->
<bean id="accountDao" class="com.hao.tx.dao.impl.AccountDaoImpl"></bean> <!-- (三)、在业务层注入模板类管理事务 -->
<!-- 此处声明业务层类,用setter的方式注入了accountDao 和 管理事务的模版 -->
<bean id="accountService" class="com.hao.tx.service.impl.AccountServiceImpl_Program">
<property name="accountDao" ref="accountDao"></property>
<property name="transactionTemplate" ref="transactionTemplate"></property>
</bean> <!-- (一)、注册事务管理器: --> <!-- 配置事务管理器 这里DataSourceXXX...可以用做Spring自己的或者MyBatis的事务管理器 -->
<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>
</beans>

3. 测试

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext1.xml")
public class TxAcTest001 { @Autowired
@Qualifier("accountService")
private IAccountService accountService; @Test
public void test01() {
System.out.println("转账之前....");
Account a = accountService.findAccountByName("txa");
if (a != null) {
System.out.println(a);
} Account b = accountService.findAccountByName("txb");
if (b != null) {
System.out.println(b);
} try {// 这里捕获转账时出现的异常
System.out.println("开始转账.....");
accountService.transfer(a, b, 100); //会出现异常
} catch (ArithmeticException e) {
e.printStackTrace();
} finally {
System.out.println("转账之后....");
Account a_trans = accountService.findAccountByName("txa");
if (a != null) {
System.out.println(a_trans);
}
Account b_trans = accountService.findAccountByName("txb");
if (b != null) {
System.out.println(b_trans);
}
}
}
}

结果如下:

4. 手动编码方式缺点:

  代码量增加,代码有侵入性.

四、声明式事务

声明式事务管理:(原始方式)

基于TransactionProxyFactoryBean.

1. 业务类

  创建AccountServiceImpl_DeclaProxyF类,这里是为了学习时测试使用,其实无需改变业务类的任何逻辑,可以直接copy准备中的业务类。
  

2. 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"
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"> <context:property-placeholder
location="classpath:jdbc.properties" />
<!-- 配置c3p0连接池 -->
<bean id="dataSource"
class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driver}" />
<property name="jdbcUrl" value="${jdbc.url}" />
<property name="user" value="${jdbc.user}" />
<property name="password" value="${jdbc.password}" />
</bean> <!-- 在容器中声明jdbc模版,这里需要注入数据源 -->
<bean id="jdbcTemplate"
class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean> <!-- 此处声明Dao层类,用注解的方式将jdbcTemplate注入到了accountDao中,也可用其他方式 -->
<bean id="accountDao" class="com.hao.tx.dao.impl.AccountDaoImpl"></bean> <!-- 此处声明业务层类,用setter的方式注入了accountDao -->
<bean id="accountService"
class="com.hao.tx.service.impl.AccountServiceImpl_DeclaProxyF">
<property name="accountDao" ref="accountDao"></property>
</bean> <!-- (一)、注册事务管理器: --> <!-- 配置事务管理器 这里DataSourceXXX...可以用做Spring自己的或者MyBatis的事务管理器 -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- 需要注入连接池,通过连接池获得连接 -->
<property name="dataSource" ref="dataSource" />
</bean> <!-- (二)、创建业务层代理对象: 配置生成代理对象 -->
<bean id="accountServiceProxy"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<!-- 目标对象 -->
<property name="target" ref="accountService" />
<!-- 注入事务管理器 -->
<property name="transactionManager" ref="transactionManager" />
<!-- 事务的属性设置 -->
<property name="transactionAttributes">
<props> <!-- key值表示要进行事务管理的方法 -->
<prop key="transfer">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean> </beans>

3. 测试

  注意在测试中要注入的是代理对象

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext2.xml")
public class TxAcTest002 { @Autowired
@Qualifier("accountServiceProxy") // 这里注入的代理对象
private IAccountService accountService; @Test
public void test01() {
System.out.println("转账之前....");
Account a = accountService.findAccountByName("txa");
if (a != null) {
System.out.println(a);
} Account b = accountService.findAccountByName("txb");
if (b != null) {
System.out.println(b);
} try {// 这里捕获转账时出现的异常
System.out.println("开始转账.....");
accountService.transfer(a, b, 100); //会出现异常
} catch (ArithmeticException e) {
e.printStackTrace();
} finally {
System.out.println("转账之后....");
Account a_trans = accountService.findAccountByName("txa");
if (a != null) {
System.out.println(a_trans);
}
Account b_trans = accountService.findAccountByName("txb");
if (b != null) {
System.out.println(b_trans);
}
}
}
}

4. 注意事项以及缺点

注意事项:配置代理对象时:prop格式:PROPAGATION , ISOLATION , readOnly, -Exception, +Exception 依次是:传播行为、隔离级别、事务是否只读、发生哪些异常可以回滚事务(所有的异常都回滚)、发生了哪些异常不回滚。

缺点:就是需要为每一个管理事务的类生成代理.需要为每个类都需要进行配置。

声明值事务-基于AspectJ XML方式

1. 业务类

  创建AccountServiceImpl_DeclaAspecJ类,这里是为了学习时测试使用,其实无需改变业务类的任何逻辑,可以直接copy准备中的业务类。
  

2. XML 中的配置

 <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"> <context:property-placeholder location="classpath:jdbc.properties" />
<!-- 配置c3p0连接池 -->
<bean id="dataSource"
class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driver}" />
<property name="jdbcUrl" value="${jdbc.url}" />
<property name="user" value="${jdbc.user}" />
<property name="password" value="${jdbc.password}" />
</bean> <!-- 在容器中声明jdbc模版,这里需要注入数据源 -->
<bean id="jdbcTemplate"
class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean> <!-- 此处声明Dao层类,用注解的方式将jdbcTemplate注入到了accountDao中,也可用其他方式 -->
<bean id="accountDao" class="com.hao.tx.dao.impl.AccountDaoImpl"></bean> <!-- 此处声明业务层类,用setter的方式注入了accountDao -->
<bean id="accountService"
class="com.hao.tx.service.impl.AccountServiceImpl_DeclaAspecJ">
<property name="accountDao" ref="accountDao"></property>
</bean> <!-- (一)、注册事务管理器: --> <!-- 配置事务管理器 这里DataSourceXXX...可以用做Spring自己的或者MyBatis的事务管理器 -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- 需要注入连接池,通过连接池获得连接 -->
<property name="dataSource" ref="dataSource" />
</bean> <!-- (二)、定义增强(事务管理) -->
<!-- 定义一个增强 -->
<tx:advice id="txAdvice"
transaction-manager="transactionManager">
<!-- 增强(事务)的属性的配置 -->
<tx:attributes>
<!-- isolation:DEFAULT ,事务的隔离级别。
propagation:事务的传播行为.
read-only:false,不是只读
timeout:-1
no-rollback-for:发生哪些异常不回滚
rollback-for:发生哪些异常回滚事务
-->
<tx:method name="transfer" isolation="DEFAULT" propagation="REQUIRED"/> </tx:attributes>
</tx:advice> <!-- (三)、定义aop的配置(切点和通知的组合) -->
<!-- aop配置定义切面和切点的信息 -->
<aop:config>
<!-- 定义切点:哪些类的哪些方法应用增强 -->
<aop:pointcut
expression="execution(* com.hao.tx.service.impl.AccountServiceImpl_DeclaAspecJ+.*(..))"
id="mypointcut" />
<!-- 定义切面: -->
<aop:advisor advice-ref="txAdvice" pointcut-ref="mypointcut" />
</aop:config>
</beans>

3. 测试

  这里无需注入代理对象

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext3.xml")
public class TxAcTest003 { @Autowired
@Qualifier("accountService") // 注入Service对象,不需要注入代理对象(生成这个类的时候,已经是代理对象.)
private IAccountService accountService; @Test
public void test01() {
System.out.println("转账之前....");
Account a = accountService.findAccountByName("txa");
if (a != null) {
System.out.println(a);
} Account b = accountService.findAccountByName("txb");
if (b != null) {
System.out.println(b);
} try {// 这里捕获转账时出现的异常
System.out.println("开始转账.....");
accountService.transfer(a, b, 100); //会出现异常
} catch (ArithmeticException e) {
e.printStackTrace();
} finally {
System.out.println("转账之后....");
Account a_trans = accountService.findAccountByName("txa");
if (a != null) {
System.out.println(a_trans);
}
Account b_trans = accountService.findAccountByName("txb");
if (b != null) {
System.out.println(b_trans);
}
}
}
}

声明值事务-基于AspectJ 注解方式

1. 业务类

  • 在Service上使用注解@Transactional,此注解可以标注在方法上,还可以标注在类上:

    • 注解中有属性值:
    • isolation
    • propagation
    • readOnly
      ...
/**
* 声明式事务-基于AspectJ 注解方式
*
* @author hao
*
*/
public class AccountServiceImpl_DeclaAspecJAnno implements IAccountService {
// 注入 accountDao 利用setter方法注入属性
private IAccountDao accountDao; public void setAccountDao(IAccountDao accountDao) {
this.accountDao = accountDao;
} @Override
public void addAccount(Account account) {
accountDao.add(account);
} @Override
public Account findAccountByName(String name) { Account account = accountDao.selectOneByName(name);
return account;
} @Override
@Transactional(isolation=Isolation.DEFAULT,propagation=Propagation.REQUIRED,readOnly=false)
public void transfer(Account from, Account to, Integer money) {
accountDao.out(from, money);// 转出钱
int i =1/0; // 中间出现异常
accountDao.in(to, money);// 收入钱
} }

2. XML中开启注解

 <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"> <context:property-placeholder location="classpath:jdbc.properties" />
<!-- 配置c3p0连接池 -->
<bean id="dataSource"
class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driver}" />
<property name="jdbcUrl" value="${jdbc.url}" />
<property name="user" value="${jdbc.user}" />
<property name="password" value="${jdbc.password}" />
</bean> <!-- 在容器中声明jdbc模版,这里需要注入数据源 -->
<bean id="jdbcTemplate"
class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean> <!-- 此处声明Dao层类,用注解的方式将jdbcTemplate注入到了accountDao中,也可用其他方式 -->
<bean id="accountDao" class="com.hao.tx.dao.impl.AccountDaoImpl"></bean> <!-- 此处声明业务层类,用setter的方式注入了accountDao 和 管理事务的模版 -->
<bean id="accountService"
class="com.hao.tx.service.impl.AccountServiceImpl_DeclaAspecJAnno">
<property name="accountDao" ref="accountDao"></property>
</bean> <!-- (一)、注册事务管理器: --> <!-- 配置事务管理器 这里DataSourceXXX...可以用做Spring自己的或者MyBatis的事务管理器 -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- 需要注入连接池,通过连接池获得连接 -->
<property name="dataSource" ref="dataSource" />
</bean> <!-- (二)、开启注解的事务管理 -->
<tx:annotation-driven transaction-manager="transactionManager"/> </beans>

3. 测试

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext4.xml")
public class TxAcTest004 { @Autowired
@Qualifier("accountService") // 注入Service对象,不需要注入代理对象(生成这个类的时候,已经是代理对象.)
private IAccountService accountService; @Test
public void test01() {
System.out.println("转账之前....");
Account a = accountService.findAccountByName("txa");
if (a != null) {
System.out.println(a);
} Account b = accountService.findAccountByName("txb");
if (b != null) {
System.out.println(b);
} try {// 这里捕获转账时出现的异常
System.out.println("开始转账.....");
accountService.transfer(a, b, 100); //会出现异常
} catch (ArithmeticException e) {
e.printStackTrace();
} finally {
System.out.println("转账之后....");
Account a_trans = accountService.findAccountByName("txa");
if (a != null) {
System.out.println(a_trans);
}
Account b_trans = accountService.findAccountByName("txb");
if (b != null) {
System.out.println(b_trans);
}
}
}
}

【Spring】编程式事务和声明式事务的更多相关文章

  1. Spring的编程式事务和声明式事务

    事务管理对于企业应用来说是至关重要的,当出现异常情况时,它也可以保证数据的一致性. Spring事务管理的两种方式 spring支持编程式事务管理和声明式事务管理两种方式. 编程式事务使用Transa ...

  2. Spring笔记(4) - Spring的编程式事务和声明式事务详解

    一.背景 事务管理对于企业应用而言至关重要.它保证了用户的每一次操作都是可靠的,即便出现了异常的访问情况,也不至于破坏后台数据的完整性.就像银行的自助取款机,通常都能正常为客户服务,但是也难免遇到操作 ...

  3. Spring编程式事务管理及声明式事务管理

    本文将深入讲解 Spring 简单而强大的事务管理功能,包括编程式事务和声明式事务.通过对本教程的学习,您将能够理解 Spring 事务管理的本质,并灵活运用之. Spring 事务属性分析 事务管理 ...

  4. Spring编程式和声明式事务实例讲解

    Java面试通关手册(Java学习指南):https://github.com/Snailclimb/Java_Guide 历史回顾: 可能是最漂亮的Spring事务管理详解 Spring事务管理 S ...

  5. spring boot中的声明式事务管理及编程式事务管理

    这几天在做一个功能,具体的情况是这样的: 项目中原有的几个功能模块中有数据上报的功能,现在需要在这几个功能模块的上报之后生成一条消息记录,然后入库,在写个接口供前台来拉取消息记录. 看到这个需求,首先 ...

  6. Spring编程式事务管理

    --------------------siwuxie095                                 Spring 编程式事务管理         以转账为例         ...

  7. spring事物配置,声明式事务管理和基于@Transactional注解的使用

    http://blog.csdn.net/bao19901210/article/details/41724355 http://www.cnblogs.com/leiOOlei/p/3725911. ...

  8. 八、Spring之深入理解声明式事务

    Spring之深入理解声明式事务 何为事务? 事务就是把一系列的动作当成一个独立的工作单元,这些动作要么全部完成,要么全部不起作用. 事务的四个属性: 1.原子性(atomicity) 事务是原子性操 ...

  9. spring学习08(声明式事务)

    11.声明式事务 11.1 回顾事务 事务在项目开发过程非常重要,涉及到数据的一致性的问题,不容马虎! 事务管理是企业级应用程序开发中必备技术,用来确保数据的完整性和一致性. 事务就是把一系列的动作当 ...

随机推荐

  1. luogu1373_小a和uim之大逃离 多维dp

    传送门 巧妙之处在于dp的设计只用设计差值即可,因此不会mle,枚举的顺序问题也解决了 #include <bits/stdc++.h> using namespace std; #def ...

  2. ext container的使用的场景

    container 是 panel 简化,他称之为容器,而panel则是面板. 如果不需要类似Ext.panel.Panel,Ext.window.Window和Ext.tab.Panel 等功能,则 ...

  3. ArrayList 的使用方法【摘要】

    ArrayList 的使用方法 1.什么是ArrayList ArrayList就是传说中的动态数组,用MSDN中的说法,就是Array的复杂版本,它提供了如下一些好处: (1)动态的增加和减少元素 ...

  4. [Apache Pulsar] 企业级分布式消息系统-Pulsar快速上手

    Pulsar快速上手 前言 如果你还不了解Pulsar消息系统,可以先看上一篇文章 企业级分布式消息系统-Pulsar入门基础 Pulsar客户端支持多个语言,包括Java,Go,Pytho和C++, ...

  5. IBM实习工作(二)

    2019年秋招前夕再次到ibm项目组参加实习两周,这次主要负责的需求是建立牛奶数据池,在二级菜单建立对账单数据池,数据由Excel导入生成. 分析整个需求,主要分为以下几块: 1.牛奶数据池前台页面, ...

  6. kubernetes API服务器的安全防护

    12.1.了解认证机制 启动API服务器时,通过命令行选项可以开启认证插件. 12.1.1.用户和组 了解用户: 分为两种连接到api服务器的客户端: 1.真实的人 2.pod,使用一种称为Servi ...

  7. javaScript今日总结

    javascript简单介绍ECMAScript 1.语法 2.变量:只能使用var定义,如果在函数的内容使用var定义,那么它是一个局部变量,如果没有使用var它是一个全局的.弱类型! 3.数据类型 ...

  8. spark源码阅读---Utils.getCallSite

    1 作用 当该方法在spark内部代码中调用时,会返回当前调用spark代码的用户类的名称,以及其所调用的spark方法.所谓用户类,就是我们这些用户使用spark api的类. 2 内部实现 2.1 ...

  9. spring-boot-plus项目打包(七)

    spring-boot-plus项目打包 项目打包 spring-boot-plus项目使用maven assembly插件进行打包 根据不同环境进行打包部署 包含启动.重启命令,配置文件提取到外部c ...

  10. DFS-递归入门

    [递归入门] 题目描述 已知 n 个整数b1,b2,-,bn 以及一个整数 k(k<n). 从 n 个整数中任选 k 个整数相加,可分别得到一系列的和. 例如当 n=4,k=3,4 个整数分别为 ...