**了解spring事物的本质**
spring事物的使用
:
不管我们使用spring集成mybatis、JdbcTemplate等,使用事物的时候只需要一个注解@Transactional,非常的方便,可能很多人没有想过这个注解是如何完成事物的工作的,今天就和大家一起探讨一下。
原生事物的实现:
package com.suning.ics.transaction;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.sql.Connection;
import java.sql.SQLException;
/**
* Created by 18077616 on 2019/9/12.
*/
@Service
public class TransacionService {
@Autowired
private MyJDBCTemplate template;
@Autowired
private MyConnectionManage connectionManage;
//开启事物的注解
//事物传播
@MyTransactional
public void insertUser() throws SQLException {
//事物在 template 里做不对,执行sql时候不知道是否需要开启,且。。。
//可以在这里做事物处理,但是每次都要写,不友好
Connection connection = connectionManage.getConnection();
connection.setAutoCommit(false);
try {
template.execute("insert INTO USER VALUES ('name1')");
template.execute("insert INTO USER VALUES ('name2')");
// template.execute("delete from user where name= 'name1'");
int i = 1 / 0;
} catch (Exception e) {
connection.rollback();
} finally {
connection.close();
}
}
}
:spring事物的实现:
定义我们自己的事物注解:
package com.suning.ics.transaction;
import java.lang.annotation.*;
/**
* 开启事物的注解
* Created by 18077616 on 2019/9/12.
*/
@Documented
@Target(ElementType.METHOD)
//@Retention(RetentionPolicy.RUNTIME)
public @interface MyTransactional {
}
注解的使用:
package com.suning.ics.transaction;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.sql.Connection;
import java.sql.SQLException;
/**
* Created by 18077616 on 2019/9/12.
*/
@Service
public class TransacionService {
@Autowired
private MyJDBCTemplate template;
@Autowired
private MyConnectionManage connectionManage;
//开启事物的注解
//事物传播
@MyTransactional
public void insertUser() throws SQLException {
//事物在 template 里做不对,执行sql时候不知道是否需要开启,且。。。
//可以在这里做事物处理,但是每次都要写,不友好
// Connection connection = connectionManage.getConnection();
// connection.setAutoCommit(false);
try {
template.execute("insert INTO USER VALUES ('name1')");
template.execute("insert INTO USER VALUES ('name2')");
// template.execute("delete from user where name= 'name1'");
int i = 1 / 0;
} catch (Exception e) {
// connection.rollback();
} finally {
// connection.close();
}
}
}
自己简单实现jdbcTemplate,主要用户sql执行,参数注入及结果的映射
package com.suning.ics.transaction;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
/**
* 本质就是集中处理sql操作,参数绑定,结果映射等
* Created by 18077616 on 2019/9/12.
*/
@Component
public class MyJDBCTemplate {
@Autowired
private MyConnectionManage connectionManage;
/**
* 这里去掉事物管理(mubastis,JdbcTemplate等集成spring后,事物都交给spring管理)
* @param sql
* @throws SQLException
*/
public void execute(String sql) throws SQLException {
Connection connection = connectionManage.getConnection();
Statement statement = connection.createStatement();
statement.execute(sql);
// try {
// connection.setAutoCommit(false); //关闭自动提交
// Statement statement = connection.createStatement();
// statement.execute(sql);
// connection.commit();
// } catch (SQLException e) {
// try {
// //数据回滚,在这里可以看到事物回滚是基于数据库连接的
// connection.rollback();
// } catch (SQLException e1) {
// e1.printStackTrace();
// }
// e.printStackTrace();
// }finally {
// //连接的关闭可能关闭了,也可能放回连接池进行复用
// connection.close();
// System.out.println("关闭连接");
// }
}
}
连接管理类:这是一个关键点,保证我们每个线程的连接是同一个连接,事物的回滚的可行性及正确性
package com.suning.ics.transaction;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
/**
* Created by 18077616 on 2019/9/12.
*/
//spring 托管创建实例,默认是单利的,那所有线程用的是同一个实例
@Component
public class MyConnectionManage {
@Autowired
DataSource dataSource1;
//因为事物是基于连接的,不同的请求不能用同一个连接
//每条sql获取新的连接是不行的
private ThreadLocal<Connection> connections = new ThreadLocal<>();
Connection connection = null;
public Connection getConnection() {
if (connections.get() == null) {
try {
connection = dataSource1.getConnection();
connections.set(connection);
} catch (SQLException e) {
e.printStackTrace();
}
} else {
connection = connections.get();
}
return connection;
}
}
spring aop 进行事物的统一管理:
package com.suning.ics.transaction;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.sql.Connection;
/**
* Created by 18077616 on 2019/9/12.
*/
@Component
@Aspect
public class MyTransactionalAspect {
@Autowired
MyConnectionManage connectionManage;
/**
* 加了注解的,方法前后执行该代码
* @return
*/
@Around("@annotation(MyTransactional)")
public Object doTransactional(ProceedingJoinPoint joinPoint)throws Throwable{
Object r = null;
Connection connection = connectionManage.getConnection();
try {
//原方法执行前执行
connection.setAutoCommit(false);
r = joinPoint.proceed(); //执行原方法
connection.commit();
//原方法执行后执行
} catch (Exception e) {
connection.rollback();
}finally {
connection.close();
}
return r;
}
}