目录


一,自定义注解

/**
* 自定义事务注解
* 空注解,用来标识
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyTransactional {
}

二,自己的连接管理器

/**
* 自己的连接器
*/
@Component
public class MyConnectionManager {

/**
* 这个是最容易出错的点,连接要让每一个线程独立,不然当一个线程的操作,产生异常后,事务回滚,那就会把另一线程的操作也回滚掉,这就产生线程不安全问题
*/
private ThreadLocal<Connection> connectionThreadLocal = new ThreadLocal<>();

@Autowired
private DataSource dataSource;

public Connection getConnection() {
Connection connection = this.connectionThreadLocal.get();
if (null == connection) {
try {
Connection connection1 = dataSource.getConnection();
connectionThreadLocal.set(connection1);
} catch (SQLException e) {
e.printStackTrace();
}
}
return this.connectionThreadLocal.get();
}
}

三,自己的数据库操作模板类

/**
* 自己的数据库操作模板类
*/
@Component
public class MyJdbcTemplate {

@Autowired
private MyConnectionManager connectionManager;

// 要throws exception
public void execute(String sql) throws SQLException {
Connection connection = connectionManager.getConnection();
PreparedStatement preparedStatement = connection.prepareStatement(sql);
preparedStatement.execute();
}
}

四,定义切面,实现注解核心逻辑

/**
* 将自定义的事务注解,使用AOP的方式,来增强它的功能
*/
@Aspect
@Component
public class MyTransactionalAspect {

@Autowired
private MyConnectionManager connectionManager;

/**
* 让标记着@myTransactional注解的方法,不直接调用,而是在该方法前后增加代码,增强该方法功能
* @param proceedingJoinPoint
* @param myTransactional 这个是增强点的定义,也就是说当遇到这个增强点标签(这里是@MyTransactional)时,就切入到它的代码中,@MyTransactional就是切入点
* 可以参考:https://www.cnblogs.com/ssslinppp/p/5845659.html
* @throws Throwable
*/
@Around("@annotation(myTransactional)")
public void doTransactional(ProceedingJoinPoint proceedingJoinPoint, MyTransactional myTransactional) throws Throwable {
Connection conn = null;
try {
/**
* 方法执行前增强
*/
System.out.println("setAutoCommit false");
conn = connectionManager.getConnection();
conn.setAutoCommit(false);

/**
* 调用实际的方法,即标注@myTransactional注解的方法
*/
proceedingJoinPoint.proceed();

/**
* 方法执行后增强
*/
conn.commit();
System.out.println("=====事务提交======");
} catch (Exception e) {
e.printStackTrace();
conn.rollback();
System.out.println("=====事务回滚=====");
throw new Exception();
}
}
}

五,测试

@MyTransactional    // 要throws异常才能回滚,如果被try catch那就相当于没有异常,所以不会回滚
public void addUser(User user) throws Exception {
String sql = "insert into t_user(age, name, address) " +
"values(" + user.getAge() + ",'" + user.getName() + "','" + user.getAddress() + "')";

System.out.println(sql);
myJdbcTemplate.execute(sql);

String sql2 = "insert into t_log(content)values('增加用户,用户名为:"+user.getName()+"')";
myJdbcTemplate.execute(sql2);
System.out.println("==========Add user completed============");

//测试回滚功能
System.out.println("制造异常,测试回滚功能!");
throw new Exception();
}