美文网首页
使用AOP功能和ThreadLocal类实现自定义事务管理

使用AOP功能和ThreadLocal类实现自定义事务管理

作者: 千锋陈老师 | 来源:发表于2019-06-14 17:32 被阅读0次

    使用AOP功能和ThreadLocal类实现自定义事务管理

    首先,需要理解ThreadLocal类的作用。ThreadLocal是为了在同一个线程中共享数据,具体原理可以参考源代码,如下:

    public void set(T value) { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value);}

    设置值实际上就是通过map存放的,与map不同的是固定将当前线程作为key值。

    public T get() {

    Thread t = Thread.currentThread();

    ThreadLocalMap map = getMap(t);

    if (map != null) {

    ThreadLocalMap.Entry e = map.getEntry(this);

    if (e != null) {

    @SuppressWarnings("unchecked")

    T result = (T)e.value;

    return result;

    }

    }

    return setInitialValue();

    }

    获取值时通过当前线程去获取值,所以如果在同一个线程中,前面存进去的值,后面是可以取出来用的,以达到线程共享数据的目的。

    接下来的例子中,主要是把一个线程中的连接共享,以达到一个线程共享一个连接,因为只有这样,才能够做到事务操作,因为同一个事务必须要求在同一个连接中,才能保证数据安全。具体代码如下:

    @Component

    public class DBManager {

    /**

    * 使用map的方式存储数据,key使用当前线程,所以能够保证一个线程共享数据,此处用来在一个线程中共享一个数据库连接

    */

    private ThreadLocal<Connection> threadLocal = new ThreadLocal<>();

    @Value("${jdbc.url}") // 使用读取properties配置文件中的数据加载url

    private String url;

    @Value("${jdbc.driver}")

    private String driver;

    @Value("${jdbc.user}")

    private String username;

    @Value("${jdbc.password}")

    private String password;

    /**

    * 创建一个新的连接

    * @return

    * @throws Exception

    */

    private Connection createConnection() throws Exception {

    Class.forName(driver);

    return DriverManager.getConnection(url, username, password);

    }

    public Connection getConnection() throws Exception {

    // 在ThreadLocal集合中获得以当前线程为key的连接对象

    Connection connection = threadLocal.get();

    // 如果获取到了连接则返回连接

    if (connection != null && !connection.isClosed()){

    return connection;

    }else {

    // 如果连接不存在或者已经关闭则创建新的连接并把连接存到ThreadLocal集合中

    connection = createConnection();

    threadLocal.set(connection);

    return connection;

    }

    }

    public void closeConnection(){

    // 在ThreadLocal集合中获得以当前线程为key的连接对象

    Connection connection = threadLocal.get();

    try {

    // 如果获取到了连接则关闭连接,并且将集合中设置为null

    if (connection != null && !connection.isClosed()){

    connection.close();

    threadLocal.set(null);

    }

    }catch (Exception e){

    e.printStackTrace();

    }

    }

    }

    在service层中,由于所有的方法都需要处理业务之外的内容,比如连接开启和关闭,事务的提交回滚等,这些应该属于AOP中切面的内容,可以提取出来解决,切面代码如下:(通过设置service层的around通知完成)

    @Component

    public class MyTransaction {

    @Resource

    private DBManager dbManager;

    // 使用aop的around的方式处理事务

    public Object doTransacition(ProceedingJoinPoint pjp){

    Connection connection = null;

    Object result = null;

    // 得到实际调用的service中方法的名称

    String methodName = pjp.getSignature().getName();

    try {

    connection = dbManager.getConnection();

    // 判断方法的名称是否需要事务操作(增、删、改需要事务操作)

    if (methodName.startsWith("update") || methodName.startsWith("save") ||

    methodName.startsWith("delete")){

    // 设置事务关闭自动提交

    connection.setAutoCommit(false);

    // 实际业务方法执行

    result = pjp.proceed();

    // 提交事务

    connection.commit();

    }else {

    result = pjp.proceed();

    }

    }catch (Throwable e){

    e.printStackTrace();

    if (connection != null){

    // 判断方法的名称是否需要事务的回滚操作操作(增、删、改需要事务操作)

    if (methodName.startsWith("update") || methodName.startsWith("save") ||

    methodName.startsWith("delete")){

    try {

    connection.rollback();

    } catch (SQLException e1) {

    e1.printStackTrace();

    }

    }

    }

    }finally {

    // 关闭连接

    dbManager.closeConnection();

    }

    return result;

    }

    }

    相关文章

      网友评论

          本文标题:使用AOP功能和ThreadLocal类实现自定义事务管理

          本文链接:https://www.haomeiwen.com/subject/dzgpfctx.html