文章目录
前言
Spring-tx是Spring框架提供的事务管理模块,它为DB事务管理提供了一种便捷的接入方式。它允许应用程序开发人员在任何环境中使用一致的编程模型,通过编程事务管理或声明式事务管理来简化事务处理的复杂性。
编程事务管理允许开发人员使用Spring框架的事务抽象,该抽象可以运行在任何底层事务基础设施上。而声明式事务管理则是一种更为简洁的方式,开发人员通常很少或不编写与事务管理相关的代码,因此不依赖于Spring Framework事务API或任何其他事务API。
Spring-tx对用户提供统一的声明式事务、编程式事务解决方案,对事务的入口、定义、传播、提交、回滚进行了封装,与业务代码隔离。它抽象出事务操作PlatformTransactionManager顶级接口,通过将连接及其他需要同步的资源交由事务同步管理器(TransactionSynchronizationManager->ThreadLocal)管理。
事务的特性包括原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)和持久性(Durability)。原子性指的是事务中的所有操作要么全部完成,要么全部不完成;一致性确保在事务开始和结束时,数据库的完整性限制没有被破坏;隔离性确保两个事务的执行互不干扰;持久性保证事务完成后对数据库的更改被持久保存。
总的来说,Spring-tx通过简化和统一事务管理的方式,使开发人员能够更专注于业务逻辑的实现,而无需过多关注底层的事务处理细节。
一、准备
1. 数据库
create table user(
id int primary key auto_increment,
name varchar(255),
age int,
address varchar(255)
)charset utf8;
INSERT INTO `test`.`user`(`id`, `name`, `age`, `address`) VALUES (1, '张三', 22, '北京');
INSERT INTO `test`.`user`(`id`, `name`, `age`, `address`) VALUES (2, '李四', 23, '邯郸');
二、后台代码
业务描述:有一个需求,用户编号销户则编号释放,将原账户编号注册为新用户(一个删,一个增)
1. 业务类
1.1 controller
package org.example.tx.annotation.controller;
import org.example.tx.annotation.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
/**
* Create by zjg on 2024/4/14
*/
@Controller
public class UserController {
@Autowired
UserService userService;
public boolean destory(int id){
return userService.destory(id);
}
}
1.2 service
1.2.1 service
package org.example.tx.annotation.service;
/**
* Create by zjg on 2024/4/14
*/
public interface UserService {
public boolean destory(int id);
}
1.2.2 impl
package org.example.tx.annotation.service.impl;
import org.example.tx.annotation.dao.UserDao;
import org.example.tx.annotation.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
/**
* Create by zjg on 2024/4/14
*/
@Service
public class UserServiceImpl implements UserService {
@Autowired
UserDao userDao;
@Transactional
@Override
public boolean destory(int id){
int delete = userDao.delete(id);
// int i=1/0;
int add = userDao.add(id);
if(delete==1&&add==1){
return true;
}
return false;
}
}
1.3 dao
1.3.1 dao
package org.example.tx.annotation.dao;
/**
* Create by zjg on 2024/4/14
*/
public interface UserDao {
public int delete(int id);
public int add(int id);
}
1.3.2 impl
package org.example.tx.annotation.dao.impl;
import org.example.tx.annotation.dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
/**
* Create by zjg on 2024/4/14
*/
@Repository
public class UserDaoImpl implements UserDao {
@Autowired
JdbcTemplate jdbcTemplate;
@Override
public int delete(int id) {
String sql="delete from user where id=?";
return jdbcTemplate.update(sql, id);
}
@Override
public int add(int id) {
String sql="insert into user value(?,?,?,?)";
return jdbcTemplate.update(sql, id, "张三", 30, "石家庄");
}
}
2.配置类
2.1 jdbc.properties
jdbc_driverClassName=com.mysql.cj.jdbc.Driver
jdbc_url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true
jdbc_username=root
jdbc_password=123456a?
2.2 SpringConfig
package org.example.tx.annotation.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.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
/**
* Create by zjg on 2024/4/14
*/
@Configuration
@ComponentScan("org.example.tx.annotation")
@EnableTransactionManagement
@PropertySource("classpath:jdbc.properties")
public class SpringConfig {
@Value("${jdbc_driverClassName}")
private String driverClassName;
@Value("${jdbc_url}")
private String url;
@Value("${jdbc_username}")
private String username;
@Value("${jdbc_password}")
private String password;
@Bean
public DruidDataSource dataSource(){
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName(driverClassName);
dataSource.setUrl(url);
dataSource.setUsername(username);
dataSource.setPassword(password);
return dataSource;
}
@Bean
public JdbcTemplate jdbcTemplate(DruidDataSource dataSource){
JdbcTemplate jdbcTemplate = new JdbcTemplate();
jdbcTemplate.setDataSource(dataSource);
return jdbcTemplate;
}
@Bean
public DataSourceTransactionManager transactionManager(DruidDataSource dataSource){
DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
transactionManager.setDataSource(dataSource);
return transactionManager;
}
}
2.3 SpringApplication
package org.example.tx.annotation;
import org.example.tx.annotation.config.SpringConfig;
import org.example.tx.annotation.controller.UserController;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
* Create by zjg on 2024/4/14
*/
public class SpringApplication {
public static void main(String[] args) {
AnnotationConfigApplicationContext acac = new AnnotationConfigApplicationContext(SpringConfig.class);
UserController userController = acac.getBean("userController", UserController.class);
userController.destory(1);
}
}
三、扩展
1. 特性
属性 | 描述 |
---|---|
原子性(Atomicity) | 事务被视为不可分割的最小工作单位,事务中的操作要么全部完成,要么全部不完成,不可能只执行其中的一部分操作。 |
一致性(Consistency) | 事务必须使数据库从一个一致性状态变换到另一个一致性状态。也就是说,一个事务执行前后,数据必须保持一致。 |
隔离性(Isolation) | 在事务执行过程中,多个事务并发执行时,一个事务的执行不应影响其他事务。即一个事务内部的操作及使用的数据对其他并发事务是隔离的,并发执行的各个事务之间不能互相干扰。 |
持久性(Durability) | 持久性也称永久性(Permanence),指一个事务一旦提交,它对数据库中数据的改变就应该是永久性的。接下来的其他操作或故障不应该对其执行结果有任何影响。 |
2. 隔离级别
隔离级别 | 描述 |
---|---|
读未提交(Read Uncommitted) | 事务可以读取未提交的其他事务的修改。这种隔离级别可能会导致脏读、不可重复读和幻读问题。 |
读已提交(Read Committed) | 一个事务只能读取已经提交的其他事务的修改。这可以防止脏读,但可能会出现不可重复读和幻读问题。 |
可重复读(Repeatable Read) | 在同一事务内,多次读取同一数据返回的结果是一致的。这可以防止脏读和不可重复读,但可能会出现幻读问题。 |
串行化(Serializable) | 最严格的隔离级别,它通过对事务进行排序,使之不可能相互冲突,从而解决脏读、不可重复读和幻读问题。但这也可能导致性能问题,因为事务只能一个接一个地执行。 |
3. 传播行为
传播行为 | 描述 |
---|---|
PROPAGATION_REQUIRED | 如果当前没有事务,就创建一个新事务;如果当前存在事务,就加入该事务。这是最常用的设置。 |
PROPAGATION_SUPPORTS | 支持当前事务,如果当前存在事务,就加入该事务;如果当前不存在事务,就以非事务方式执行。 |
PROPAGATION_MANDATORY | 支持当前事务,如果当前存在事务,就加入该事务;如果当前不存在事务,就抛出异常。 |
PROPAGATION_REQUIRES_NEW | 创建新事务,无论当前是否存在事务,都创建新事务。 |
PROPAGATION_NOT_SUPPORTED | 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。 |
PROPAGATION_NEVER | 以非事务方式执行,如果当前存在事务,则抛出异常。 |
PROPAGATION_NESTED | 如果当前存在事务,则在嵌套事务内执行;如果当前没有事务,就执行PROPAGATION_REQUIRED行为。 |