spring声明事务的方式,使用注解的方式
⚫ 名称:@Transactional
⚫ 类型:方法注解,类注解,接口注解
⚫ 位置:方法定义上方,类定义上方,接口定义上方
⚫ 作用:设置当前类/接口中所有方法或具体方法开启事务,并指定相关事务属性
⚫ 范例:
@Transactional(
readOnly = false,
timeout = -1,
isolation = Isolation.DEFAULT,
rollbackFor = {ArithmeticException.class, IOException.class},
noRollbackFor = {},
propagation = Propagation.REQUIRES_NEW
)
⚫ 名称:tx:annotation-driven
⚫ 类型:标签
⚫ 归属:beans标签
⚫ 作用:开启事务注解驱动,并指定对应的事务管理器
⚫ 范例:
<tx:annotation-driven transaction-manager="txManager"/>
⚫ 名称:@EnableTransactionManagement
⚫ 类型:类注解
⚫ 位置:Spring注解配置类上方
⚫ 作用:开启注解驱动,等同XML格式中的注解驱动
⚫ 范例:
@Configuration
@ComponentScan("com.fs")
@PropertySource("classpath:jdbc.properties")
@Import({JDBCConfig.class,MyBatisConfig.class,TransactionManagerConfig.class})
@EnableTransactionManagement
public class SpringConfig {
}
public class TransactionManagerConfig {
@Bean
public PlatformTransactionManager getTransactionManager(@Autowired DataSource dataSource){
return new DataSourceTransactionManager(dataSource);
}
}
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.fs</groupId>
<artifactId>day04_spring_AOP_Transaction_02</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.9.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.1.9.RELEASE</version>
</dependency>
<!-- jdbc-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.1.9.RELEASE</version>
</dependency>
<!-- spring整合mybatis-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.1</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.5</version>
</dependency>
<!-- mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<!--druid连接池-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.20</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
</dependency>
<!-- aop切面包-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.5</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://192.168.93.132:3306/test
jdbc.username=root
jdbc.password=root
package com.fs.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.context.annotation.Import;
import org.springframework.transaction.annotation.EnableTransactionManagement;
//表示这个类是一个spring的配置类,并将其存入到ioc容器中
@Configuration
/*开启扫描注解的那些包
*/
@ComponentScan("com.fs")
//引入其他的配置类
@Import({JdbcConfig.class,MybatisConfig.class,TransactionManagerConfig.class})
//开启切面自动代理
@EnableAspectJAutoProxy
//开启声明式事务管理 相当于配置文件中的
@EnableTransactionManagement
public class SpringConfig {
}
package com.fs.config;
import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.PropertySource;
/*
*/
@PropertySource("classpath:jdbc.properties")
public class JdbcConfig {
//@Value("${Key}")
@Value("${jdbc.driver}")
private String driver;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
/*
*/
//将返回的DruidDataSource交给ioc管理
@Bean
public DruidDataSource getDruidDataSource(){
//创建DruidDataSource
DruidDataSource druidDataSource = new DruidDataSource();
//给属性赋值,这个是上面从配置文件中依耐注入给属性的
druidDataSource.setDriverClassName(driver);
druidDataSource.setUrl(url);
druidDataSource.setUsername(username);
druidDataSource.setPassword(password);
//返回DruidDataSource,然后交给ioc管理
return druidDataSource;
}
}
package com.fs.config;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import javax.sql.DataSource;
public class MybatisConfig {
/*
*/
@Bean
public SqlSessionFactoryBean getSqlSessionFactoryBean(@Autowired DataSource dataSource){
//创建sql会话工厂类 //这里@Autowired也是从ioc拿DataSource
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
//从ioc容器中取出jdbcConfig中配置的druidDatasource
sqlSessionFactoryBean.setDataSource(dataSource);
//配置起别名
sqlSessionFactoryBean.setTypeAliasesPackage("com.fs.pojo");
return sqlSessionFactoryBean;
}
/*
*/
//创建MyBatis动态代理扫描类
@Bean
public MapperScannerConfigurer getMapperScannerConfigurer(){
//创建映扫描配置类
MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
//设置动态代理扫描的dao的包
mapperScannerConfigurer.setBasePackage("com.fs.dao");
//交给spring管理
return mapperScannerConfigurer;
}
}
package com.fs.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import javax.sql.DataSource;
/*
声明式事务配置类
*/
public class TransactionManagerConfig {
/*
*/
@Bean
public PlatformTransactionManager getTransactionManager(@Autowired DataSource dataSource){
//使用Spring的平台事务管理器,是一个接口,使用他的实现类构造器传递一个连接池
DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
//传递一个连接池
dataSourceTransactionManager.setDataSource(dataSource);
return dataSourceTransactionManager;
}
}
package com.fs.pojo;
import lombok.Data;
@Data
public class Account {
private Integer id;
private String name;
private Double money;
}
package com.fs.dao;
import com.fs.pojo.Account;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
import java.util.List;
public interface AccountDao {
@Select("select * from account")
List<Account> findAll();//查询所有
//根据名字修改money
@Update("UPDATE account SET money = #{money} WHERE name = #{name}")
void transferMoney(Account account);
//根据名字查询账户信息
@Select("select * from account where name = #{name}")
Account findAccountByName(@Param("name") String name);
}
package com.fs.service;
import com.fs.pojo.Account;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
/*
在接口上配置@Transactional,那么他下面的实现类都会进行事务管理
这个注解就相当于配置文件中的这些配置
如果不写属性,该注解的默认配置为
@Transactional(
readOnly = false,
timeout = -1,
isolation = Isolation.DEFAULT,
rollbackFor = {ArithmeticException.class, IOException.class},
noRollbackFor = {},
propagation = Propagation.REQUIRES_NEW
)
*/
public interface AccountService {
List<Account> findAll();
Account findAccountByName(String name);
//对这个方法开启事务使用默认配置
@Transactional
void transferMoneyAtoB(String aName,String bName,Integer money);
}
package com.fs.service.impl;
import com.fs.dao.AccountDao;
import com.fs.pojo.Account;
import com.fs.service.AccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.sql.DataSource;
import java.util.List;
/*
*/
@Service
public class AccountServiceImpl implements AccountService {
//从ioc获取MyBatis动态代理的accountDao实现类
@Autowired
private AccountDao accountDao;
@Autowired
private DataSource dataSource;
@Override
public List<Account> findAll() {
return accountDao.findAll();
}
@Override
public Account findAccountByName(String name) {
return accountDao.findAccountByName(name);
}
//转账的业务实现
@Override
public void transferMoneyAtoB(String aName, String bName, Integer money) {
//先查出两个人的数据
Account aAccount = accountDao.findAccountByName(aName);
Account bAccount = accountDao.findAccountByName(bName);
//然后a减钱,b加钱
aAccount.setMoney(aAccount.getMoney()-money);
bAccount.setMoney(bAccount.getMoney()+money);
//然后调用转账方法(sql语句为更新账户)
accountDao.transferMoney(aAccount);
//制作一个异常
// int i = 1/0;
accountDao.transferMoney(bAccount);
}
}
package com.fs.service.impl;
import com.fs.config.SpringConfig;
import com.fs.pojo.Account;
import com.fs.service.AccountService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.util.List;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfig.class)
public class AccountServiceImplTest {
@Autowired
private AccountService accountService;
//测试查询所有方法
@Test
public void findAll() {
List<Account> all = accountService.findAll();
System.out.println(all);
}
//测试转账方法已经使用@Transactional绑定事务
@Test
public void transferMoneyAtoB() {
//测试转账方法
accountService.transferMoneyAtoB("小付","小花",100);
}
}
业务层转账方法正常运行成功后数据表数据
由于我们测试代码中是小付向小花转账100元,代码执行成功后应该小付900,小花1100
业务层转账方法我们给制作一个异常1/0 的/ by zero异常,
运存测试转账方法控制台输出
数据库中表的数据
小付原本900,小花1100,我们进行了转账业务,但是制作了异常,事务会进行回滚,所以金额不会发生变化