SpringAOP的引入

目录

一、概念引入

1.引入依赖

2.工具类

3.实体类

4.持久层实现类

5.业务层实现类

6.配置文件

7.测试类

8.运行

查看数据库:

9.现在如果转账过程中出现异常

AccountServiceImpl(模拟异常)

再运行:

查看数据库:

10.现在做事务管理

AccountServiceImpl(事务管理)

运行

查看数据库:

11.生成代理对象

代理对象:

业务层实现类

查看数据库:


一、概念引入

入门案例(概念引入)

1.引入依赖

XML 复制代码
<dependencies>
    <!--spring的核心依赖-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.0.2.RELEASE</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/commons-logging/commons-logging -->
    <dependency>
        <groupId>commons-logging</groupId>
        <artifactId>commons-logging</artifactId>
        <version>1.2</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/log4j/log4j -->
    <!--日志-->
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.12</version>
    </dependency>
    <!--测试-->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
        <scope>test</scope>
    </dependency>
    <!--连接池 alibaba的-->
    <!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>1.1.10</version>
    </dependency>
    <!--mysql驱动-->
    <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.6</version>
    </dependency>
    <!--spring-test-->
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-test -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-test</artifactId>
        <version>5.0.2.RELEASE</version>
        <scope>test</scope>
    </dependency>
</dependencies>

2.工具类

java 复制代码
package com.qcby.utils;

import java.sql.Connection;
import java.sql.SQLException;

import javax.sql.DataSource;

import com.alibaba.druid.pool.DruidDataSource;

/**
 * 事务的工具类
 */
public class TxUtils {
   
   private static DruidDataSource ds = null;

   // 使用ThreadLocal存储当前线程中的Connection对象
   private static ThreadLocal<Connection> threadLocal = new ThreadLocal<Connection>();

   // 在静态代码块中创建数据库连接池---static代码块
   static {
      try {
         // 通过代码创建C3P0数据库连接池
         ds = new DruidDataSource();
         ds.setDriverClassName("com.mysql.jdbc.Driver");
         ds.setUrl("jdbc:mysql:///spring_db");
         ds.setUsername("root");
         ds.setPassword("2020");
      } catch (Exception e) {
         throw new ExceptionInInitializerError(e);
      }
   }

   /**
    * @Method: getConnection
    * @Description: 从数据源中获取数据库连接
    * @Anthor:
    * @return Connection
    * @throws SQLException
    */
   public static Connection getConnection() throws SQLException {

      // 从当前线程中获取Connection
      Connection conn = threadLocal.get();

      if (conn == null) {
         // 从数据源中获取数据库连接
         conn = getDataSource().getConnection();
         // 将conn绑定到当前线程
         threadLocal.set(conn);
      }
      return conn;
   }

   /**
    * @Method: startTransaction
    * @Description: 开启事务
    * @Anthor:
    *
    */
   //jdbc开启事务靠链接开启
   public static void startTransaction() {
      try {
         Connection conn = threadLocal.get();
         if (conn == null) {
            conn = getConnection();
            // 把 conn绑定到当前线程上
            threadLocal.set(conn);
         }

         // 开启事务
         conn.setAutoCommit(false);

      } catch (Exception e) {
         throw new RuntimeException(e);
      }
   }

   /**
    * @Method: rollback
    * @Description:回滚事务
    * @Anthor:
    */
   public static void rollback() {
      try {
         // 从当前线程中获取Connection
         Connection conn = threadLocal.get();
         if (conn != null) {
            // 回滚事务
            conn.rollback();
         }
      } catch (Exception e) {
         throw new RuntimeException(e);
      }
   }

   /**
    * @Method: commit
    * @Description:提交事务
    * @Anthor:
    */
   public static void commit() {
      try {
         // 从当前线程中获取Connection
         Connection conn = threadLocal.get();
         if (conn != null) {

            // 提交事务
            conn.commit();

         }
      } catch (Exception e) {
         throw new RuntimeException(e);
      }
   }

   /**
    * @Method: close
    * @Description:关闭数据库连接(注意,并不是真的关闭,而是把连接还给数据库连接池)
    * @Anthor:
    *
    */
   public static void close() {
      try {
         // 从当前线程中获取Connection
         Connection conn = threadLocal.get();//从连接池拿到链接
         if (conn != null) {
            conn.close();
            // 解除当前线程上绑定conn
            threadLocal.remove();
         }
      } catch (Exception e) {
         throw new RuntimeException(e);
      }
   }

   /**
    * @Method: getDataSource
    * @Description: 获取数据源
    * @Anthor:
    * @return DataSource
    */
   public static DataSource getDataSource() {
      // 从数据源中获取数据库连接
      return ds;
   }

}

3.实体类

java 复制代码
package com.qcby.model;

import java.io.Serializable;

public class Account implements Serializable {
    private Integer id;
    private String name;
    private Double money;

    public Account() {
    }

    public Account(Integer id, String name, Double money) {
        this.id = id;
        this.name = name;
        this.money = money;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Double getMoney() {
        return money;
    }

    public void setMoney(Double money) {
        this.money = money;
    }

    @Override
    public String toString() {
        return "Account{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", money=" + money +
                '}';
    }
}

4.持久层实现类

java 复制代码
package com.qcby.dao.impl;

import com.qcby.dao.AccountDao;
import com.qcby.pojo.Account;
import com.qcby.utils.TxUtils;

import javax.sql.DataSource;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
import com.mysql.jdbc.Driver;

public class AccountDaoImpl implements AccountDao {
    //实现两个账户的转账
    @Override
    public void updateSaveAll(Account account){

        Connection connection=null;
        PreparedStatement stmt=null;
        try{
            //获取连接
            connection = TxUtils.getConnection();
            String sql = "update  account set money = money + ? where name = ?";
            stmt = connection.prepareStatement(sql);
            stmt.setDouble(1, account.getMoney());
            stmt.setString(2, account.getName());
            // 查询
            int result = stmt.executeUpdate();
            System.out.println("修改影响了"+result+"行数据!!");
        }catch(Exception e){
            try {
                stmt.close();
                //connection.close();
            } catch (SQLException e1) {
                e1.printStackTrace();
            }
        }
    }
}

5.业务层实现类

java 复制代码
package com.qcby.service.impl;

import com.qcby.dao.AccountDao;
import com.qcby.model.Account;
import com.qcby.service.AccountService;

public class AccountServiceImpl implements AccountService {

    private AccountDao accountDao;

    public void setAccountDao(AccountDao accountDao) {
        this.accountDao = accountDao;
    }

    @Override
    public void updateSaveAll(Account account1, Account account2) {
        //保存账号1
        accountDao.updateSaveAll(account1);
        //保存账号2
        accountDao.updateSaveAll(account2);
    }
}

6.配置文件

XML 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                           http://www.springframework.org/schema/beans/spring-beans.xsd">



    <!--配置持久层和业务层-->
    <bean id="accountService" class="com.qcby.service.impl.AccountServiceImpl">
        <property name="accountDao" ref="accountDao"></property>
    </bean>
    <bean id="accountDao" class="com.qcby.dao.impl.AccountDaoImpl">
    </bean>

</beans>

7.测试类

java 复制代码
package com.qcby;

import com.qcby.model.Account;
import com.qcby.service.AccountService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class demo {

    @Autowired
    private AccountService accountService;

    @Test
    public void run(){
        Account account1=new Account(null,"aaa",500.00);
        Account account2=new Account(null,"bbb",-500.00);
        accountService.updateSaveAll(account1,account2);
    }
}

8.运行

查看数据库:

之前:

现在:

9.现在如果转账过程中出现异常

AccountServiceImpl(模拟异常)

java 复制代码
package com.qcby.service.impl;

import com.qcby.dao.AccountDao;
import com.qcby.model.Account;
import com.qcby.service.AccountService;

public class AccountServiceImpl implements AccountService {

    private AccountDao accountDao;

    public void setAccountDao(AccountDao accountDao) {
        this.accountDao = accountDao;
    }

    @Override
    public void updateSaveAll(Account account1, Account account2) {
        //保存账号1
        accountDao.updateSaveAll(account1);
        //模拟异常
        int a=1/0;
        //保存账号2
        accountDao.updateSaveAll(account2);
    }
}

再运行:

查看数据库:

只有第一条数据变了,出现错误

10.现在做事务管理

AccountServiceImpl(事务管理)

java 复制代码
package com.qcby.service.impl;

import com.qcby.dao.AccountDao;
import com.qcby.model.Account;
import com.qcby.service.AccountService;
import com.qcby.utils.TxUtils;

public class AccountServiceImpl implements AccountService {

    private AccountDao accountDao;

    public void setAccountDao(AccountDao accountDao) {
        this.accountDao = accountDao;
    }

    @Override
    public void updateSaveAll(Account account1, Account account2) {
        //在这里进行事务管理
        try {
            //开启事务
            TxUtils.startTransaction();
            //保存账号1
            accountDao.updateSaveAll(account1);
            //模拟异常
            int a=1/0;
            //保存账号2
            accountDao.updateSaveAll(account2);
            //提交事务
            TxUtils.commit();
        }catch (Exception e){
            e.printStackTrace();
            //回滚事务
            TxUtils.rollback();
        }finally {
            //关闭资源
            TxUtils.close();
        }
    }
}

这里仍然有异常,但是进行了事务管理,

运行

查看数据库:

原来:

现在:

回滚了

11.生成代理对象

代理对象:

java 复制代码
package com.qcby.proxy;

import com.qcby.service.AccountService;
import com.qcby.utils.TxUtils;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/*
* 传入目标对象,生成该对象的代理对象,返回。对目标对象的方法进行增强
* */
public class JdkProxy {
    //获取代理对象
    public static Object getProxy(AccountService accountService){
        /*
        * 使用JDK动态代理生成代理对象
        * 第一个参数:类的加载其
        * 第二个参数:当前传入的对象实现了哪些接口要字节码的对象
        * 第三个参数:回调函数
        * */
        Object proxy = Proxy.newProxyInstance(JdkProxy.class.getClassLoader(), accountService.getClass().getInterfaces(), new InvocationHandler(){
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                Object result = null;
                try {
                    //开启事务
                    TxUtils.startTransaction();
                    result = method.invoke(accountService,args);
                    //提交事务
                    TxUtils.commit();
                }catch (Exception e){
                    e.printStackTrace();
                    //回滚
                    TxUtils.rollback();
                }finally {
                    TxUtils.close();
                }
                return result;
            }
        });
        return proxy;
    }
}

业务层实现类

(有异常)(之前在这里写的事务就不用写了)

java 复制代码
package com.qcby.service.impl;

import com.qcby.dao.AccountDao;
import com.qcby.pojo.Account;
import com.qcby.service.AccountService;
import com.qcby.utils.TxUtils;

import java.sql.SQLException;

public class AccountServiceImpl implements AccountService {

    private AccountDao accountDao;//因为这里是空指针,所以要有set方法

    public void setAccountDao(AccountDao accountDao) {
        this.accountDao = accountDao;
    }

    public void updateSaveAll(Account account1, Account account2){
        try {
            //保存账号1
            accountDao.updateSaveAll(account1);
            //模拟异常
            int a=1/0;
            //保存账号2
            accountDao.updateSaveAll(account2);
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

测试类

(多了一个run2())

java 复制代码
package com.qcby.springAopTest;

import com.qcby.pojo.Account;
import com.qcby.proxy.JdkProxy;
import com.qcby.service.AccountService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class AopTest {
    @Autowired
    private AccountService accountService;

    @Test
    public void run1(){
        Account account1=new Account(null,"aaa",500.00);
        Account account2=new Account(null,"bbb",-500.00);
        accountService.updateSaveAll(account1,account2);
    }

    @Test
    public void run2(){
        Account account1=new Account(null,"aaa",500.00);
        Account account2=new Account(null,"bbb",-500.00);
        //生成代理对象
        Object proxyobj= JdkProxy.getProxy(accountService);
        AccountService proxy=(AccountService)proxyobj;
        proxy.updateSaveAll(account1,account2);
    }
}

运行:

查看数据库:

原来:

现在:

相关推荐
Karoku06633 分钟前
【企业级分布式系统】ELK优化
运维·服务器·数据库·elk·elasticsearch
小技与小术2 小时前
数据库表设计范式
数据库·mysql
安迁岚2 小时前
【SQL Server】华中农业大学空间数据库实验报告 实验三 数据操作
运维·服务器·数据库·sql·mysql
安迁岚2 小时前
【SQL Server】华中农业大学空间数据库实验报告 实验九 触发器
数据库·sql·mysql·oracle·实验报告
Loganer2 小时前
MongoDB分片集群搭建
数据库·mongodb
LKID体2 小时前
Python操作neo4j库py2neo使用之创建和查询(二)
数据库·python·neo4j
刘大浪2 小时前
后端数据增删改查基于Springboot+mybatis mysql 时间根据当时时间自动填充,数据库连接查询不一致,mysql数据库连接不好用
数据库·spring boot·mybatis
一只爱撸猫的程序猿2 小时前
简单实现一个系统升级过程中的数据平滑迁移的场景实例
数据库·spring boot·程序员
无敌岩雀2 小时前
MySQL中的索引
数据库·mysql
a_安徒生3 小时前
linux安装TDengine
linux·数据库·tdengine