1 事务简介
1.1 事务概念
事务:在数据层保障一系列的数据库操作同时成功或同时失败
四大特性:
- 原子性(atomicity):一个事务要么全部提交成功,要么全部失败回滚,不能只执行其中的一部分操作
- 一致性(consistency):事务的执行不能破坏数据库数据的完整性和一致性,一个事务在执行前后,数据库都必须处于一致性状态。如果数据库系统在运行过程中发生故障,有些事务尚未完成就被迫中断但对数据库所作的修改有一部分已写入物理数据库,就会导致数据库就处于一种不正确的状态,也就是不一致的状态
- 隔离性(isolation):事务的隔离性是指在并发环境中,并发的事务时相互隔离的,一个事务的执行不能不被其他事务干扰。
- 持久性(durability):一旦事务提交,那么它对数据库中的对应数据的状态的变更就会永久保存到数据库中。
Spring事务:在数据层或业务层保障一系列数据库操作同时成功或同时失败
1.2 Spring管理事务API
(1)PlatformTransactionManager:平台事务管理器。
- commit:提交事务
- rollback:回滚事务
(2)DataSourceTransactionManager:接口,Spring提供了具体的实现类:DataSourceTransactionManager。只需要给它一个DataSource对象,就可以去业务层管理事务。
Mybatis内部采用的时JDBC事务,所以Spring整合Mybatis可以采用DataSourceTransactionManager事务管理器。
2 Spring事务简单案例:银行转账案例
2.1 需求分析
转账,A账户减钱与B账户加钱应同时完成,故可使用事务。
2.2 环境搭建与项目实现
(1)创建数据库表
create database test character set utf8;
use test;
CREATE TABLE `spring_db`.`account` (
`id` int NOT NULL AUTO_INCREMENT COMMENT '用户id',
`name` varchar(255) NOT NULL COMMENT '用户名',
`money` double NOT NULL AUTO_INCREMENT COMMENT '账户金额',
PRIMARY KEY (`id`)
);
insert into account values(1,'jerry',1000);
insert into account values(2,'tom',1000);
(2)创建maven项目并配置pom.xml文件
配置打包方式和引用依赖:spring-context,druid,mybatis,mysql-connector-java,spring-jdbc,junit,spring-test。
<groupId>com.pra</groupId>
<artifactId>spring_mybatis_bank</artifactId>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.20</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.16</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.11</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.31</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.20</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.1.0</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.3.20</version>
</dependency>
</dependencies>
(3)创建模型类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Account {
private Integer id;
private String name;
private Double money;
public Account(String name, Double money) {
this.name = name;
this.money = money;
}
}
(4)创建mapper接口
public interface AccountMapper {
@Update("update account set money = money + #{money} where id = #{id}")
public void inMoney(@Param("id") Integer id,@Param("money") Double money);
@Update("update account set money = money - #{money} where id = #{id}")
public void outMoney(@Param("id") Integer id,@Param("money") Double money);
}
(5)创建Service接口和实现类
@Service
public class AccountServiceImpl implements AccountService {
@Autowired
private AccountMapper accountMapper;
@Override
public void transfer(Account account1, Account account2, Double money) {
accountMapper.inMoney(account2.getId(), money);
accountMapper.outMoney(account1.getId(), money);
}
}
public interface AccountService {
/**
* @param account1
* @param account2
*/
void transfer(Account account1, Account account2, Double money);
}
(6)创建jdbc.properties文件
(7)创建JdbcConfig配置类
public class JdbcConfig {
@Value("${jdbc.driver}")
private String driver;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
@Bean
public DataSource dataSource(){
DruidDataSource dds = new DruidDataSource();
dds.setDriverClassName(driver);
dds.setUrl(url);
dds.setUsername(username);
dds.setPassword(password);
return dds;
}
}
(8)创建MybatisConfig配置类
public class MybatisConfig {
@Bean
public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource){
SqlSessionFactoryBean ssfb = new SqlSessionFactoryBean();
ssfb.setDataSource(dataSource);
ssfb.setTypeAliasesPackage("com.pra.bank.entity");
return ssfb;
}
@Bean
public MapperScannerConfigurer mapperScannerConfigurer(){
MapperScannerConfigurer msc = new MapperScannerConfigurer();
msc.setBasePackage("com.pra.bank");
return msc;
}
}
(9)创建SpringConfig配置类
@Configuration
@ComponentScan("com.pra.bank")
@PropertySource("jdbc.properties")
@Import({JdbcConfig.class, MybatisConfig.class})
public class SpringConfig {
}
(10)Spring整合Junit测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfig.class)
public class BankTest {
@Autowired
private AccountServiceImpl accountService;
@Test
public void bankTest2(){
Account acc1 = new Account(1,"jerry",1000.0);
Account acc2 = new Account(2,"tom",1000.0);
accountService.transfer(acc2,acc1,99.0);
}
}
代码最终成功运行,应熟记spring与mybatis整合的流程,以便以后可能用到