您的位置:首页 > 编程语言 > Java开发

Spring中事务源码初次接触

2020-07-13 06:12 751 查看

软件实现事务的三种方式

  1. 通过xml代码配置声明式事务
  2. 通过Java代码实现事务 通过DataSourceTransactionManager 实现
  3. 通过注解 @Transactional

同一个事务管理的代码逻辑中,每次执行sql语句都是基于同一个连接

通过注解实现事务 @Transactional
ORM框架本身可以获取连接但是无法确保获取的同一事务管理的同一连接,所以引入事务同步管理器通过TransactionSynchronizationManager获取连接。其中引入ThreaLocal概念,它是一个线程级别的变量,每个线程都有一个ThredLocal就是每个线程都拥有自己独立的一个变量,竞争条件就被彻底消除了,在并发模式下是绝对安全的变量。

// 最简化的ORM框架 --  绑定参数,生成SQL、结果映射、pojo对象
@Component // 交给你spring托管 创建对象 注入
public class MyJdbcTemplate {

@Autowired
TonyTransactionManage tonyTransactionManage;

public void execute(String sql) throws SQLException {
// 1. 数据库链接
// dataSource.getConnection(); 这个方法连接池提供的,每次获取一个连接池中空闲连接
Connection connection = tonyTransactionManage.getConnection(); // 这个地方不应管每次都是新连接
// 2. 执行SQL语句
Statement statement = connection.createStatement();
statement.execute(sql);
}
}
/**
* 存放有连接
*/
@Component
public class TonyTransactionManage {
@Autowired
DataSource dataSource;

private ThreadLocal<Connection> connection = new ThreadLocal<>(); // 多个线程共用了同一个连接,导致回滚的时候出现数据错乱

public Connection getConnection() throws SQLException {
if (connection.get() == null) {
connection.set( dataSource.getConnection());
}
return connection.get();
}

}
@Autowired
MyJdbcTemplate myJdbcTemplate;

//  不用框架事务处理机制 自己去做事务处理?
// 事务控制不应在ORM框架,而是业务代码层面
public void delete(String userId) throws Exception {
// TODO 事务怎么玩? --- 同一个事务管理的代码调用逻辑中,每次执行SQL语句 基于同一个连接
Connection connection = TonyTransactionManage .getConnection();
connection.setAutoCommit(false);
try{
// ---------- 业务 --------------
// SQL自动生成、参数直接传对象、查询结果映射pojo
connection.commit();
}catch(Exception e){
e.printStackTrace();
connection.rollback();
}
// ------------结束--------------
}

不通过Spring注解或xml实现事务 DataSourceTransactionManager
获取连接 DataSourceTransactionManager .getConnection();

@Autowired
DataSourceTransactionManager dataSourceTransactionManager;

@Autowired
TransactionDefinition transactionDefinition;
try{
TransactionStatus status = 	dataSourceTransactionManager.getTransaction(transactionDefinition);
// 业务代码
// 提交
dataSourceTransactionManager.commit(status);
]catch(Exception e){
dataSourceTransactionManager.rollback(status)
}

关闭连接中的自动提交 connection.setAutoCommint(false);
try{
--------------------------业务代码-------------------------------------
connection.commit();
}catch(Exception e){
e.printStackTrace();
connection.rollback();
}

通过自定义一个Spring注解实现事务
手动写一个切面

// spring提供AOP 支持到方法层级
@Aspect
@Component
public class TonyTransactionApesct {
@Autowired
TonyTransactionManage tonyTransactionManage;

// 注解标记 -- 有了这个标记spring就能识别到 需要增强
// 实际方法执行 是按照这个AOP程序重新定义的
@Around("@annotation(TonyTransactional)")
public Object doTranscation(ProceedingJoinPoint proceedingJoinPoint) throws SQLException {
Connection connection = null;
// 原来的业务逻辑- 调用
try {
connection = tonyTransactionManage.getConnection();
connection.setAutoCommit(false); // 设置为手动提交
System.out.println("方法执行前 ---- 开启事务");

Object result = proceedingJoinPoint.proceed();

System.out.println("方法执行后 ----提交");
connection.commit();
return result;
} catch (Throwable throwable) {
throwable.printStackTrace();
System.out.println("方法执行后 ----回滚");
connection.rollback();
}

return null;
}
}

手写一个注解

/**
* 事务注解
*/
public @interface TonyTransactional {
}

扩展
方法调用–》执行前从数据库连接池中获取连接存放至事务同步管理器TransactionSynchronizationManager,开启事务–》需要进行事务处理的具体方法–》ORM框架(绑定参数生成SQL)–》获取数据库连接执行SQ–》从事务同步管理器TransactionSynchronizationManager中获取数据库连接 --》数据库–》pojo结果映射–》需要进行事务处理的具体方法–》执行后提交或回滚
扩展
了解注解的封装方式 ;注解可以理解为一段标记,谁定义的谁去处理
AOP的编程思想–面向切面编程,简单来讲就是增强功能,动态的新的代码逻辑切入到指定的逻辑或指定的位置上;
AOP增强之前

//业务代码

AOP增强之后

// 前面插入新的逻辑
// 业务代码
// 后面插入新的逻辑

扩展
Spring如何实现AOP原理
通过cglib动态生成指定类的子类,然后子类重写父类的方法(待了解)

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: