共计 47084 个字符,预计需要花费 118 分钟才能阅读完成。
1、Spring-AOP 概述
1.1、什么是 AOP
面向切面的编程思想,在程序开发中主要用来解决一些系统层面上的问题,比如日志,事务,权限等。AOP 采用一种称为“横切”的技术,将涉及多业务流程的通用功能抽取并单独封装,形成独立的切面,在合适的时机将这些切面横向切入到业务流程指定的位置中。
OOP
AOP
1.2、AOP 的发展阶段
静态 AOP:Aspect 形式,通过特定的编译期,将实现后的 Aspect 编译并织入到系统的静态类中
动态 AOP:AOP 的织入过程在系统运行开始之后进行,而不是预先编译到系统中
1.3、AOP 作用及应用场景
对 OOP 的增强,在实际开发当中我们会遇到一些问题,这些问题不会影响到主业务的实现,所以我们叫这些问题为切面性问题。如我们的上图,这些问题会分散各个代码的各个部份,难以维护。AOP 就是把这些问题和主业务逻辑分开,达到与主业务逻辑解耦的目的。
常用的应用场景:
日志、异常处理、性能统计、声明式事务、安全、缓存等
1.4、AOP 核心术语
切面(Aspect)
通知和切点的结合,共同定义切面的全部内容。横切关注点可以被模块化为特殊的类,这些类被称为切面。再在运行的时候网业务方法上动态植入“切面类代码”。
切入点 (Pointcut)
用来匹配通知所要织入的一个点或多个连接点。通常使用类和方法名来指定这些切点。
通知(Advice)
切面的工作被称为通知。通知定义了切面是什么以及何时使用。
Spring 切面可以应用 5 中类型的通知:
Before:在方法被调用之前调用通知
After:在方法完成之后被调用通知,无论方法执行是否成功
AfterReturning:在方法成功执行之后调用通知
AfterThrowing:在方法抛出异常后调用通知
Around:通知包裹了被通知的方法,在被通知方法调用之前和调用之后执行自定义的行为
连接点(Joinpoint)
在应用执行过程中能插入切面的一个点,可以是调用方法时、抛出异常时、修改一个字段时。切面代码利用这些点插入到应用的正常流程中,添加新行为。
引入(Introduction)
允许我们向现有类添加新方法和属性
织入(Weaving)
把切面应用到目标对象并创建新的代理对象的过程。切面在指定的连接点被织入目标对象中,在声明周期里有多个点可以织入:
编译期:切面在目标类编译时被织入。
类加载期:切面在目标类加载到 JVM 时被织入。
运行期:切面在应用运行时某个时刻被织入。
代理(Proxy)
代理类伪装成目标类,它会截取对目标类中方法的调用,让调用者对目标类的调用都先变成调用伪装类,伪装类中就先执行了切面,再把调用转发给真正的目标 bean。
目标对象 (Target)
增强逻辑的织入目标类。
1.5、AOP 原理图
如何完成日志记录的切入
2、事务处理
2.1、事务问题
回到我们的 Spring003 项目,查看业务层,业务层中事务为自动处理,操作一条件 SQL 时,没有问题,如果是二条件 SQL 呢?
2.1.1、需求
在业务层加入方法:修改 2 个管理员用户的密码
2.1.2、修改业务层与持久层
持久层
//IManagerDao.java
int updateManagerTwo(Manager m1,Manager m2);
//ManagerDaoImpl.java
public int updateManagerTwo(Manager m1, Manager m2) {try {runner.update("update manager set uname=?,pword=?,zcsj=? where mid=?",m1.getUname(),m1.getPword(),m1.getZcsj(),m1.getMid());
runner.update("update manager set uname=?,pword=?,zcsj=? where mid=?",m2.getUname(),m2.getPword(),m2.getZcsj(),m2.getMid());
} catch (SQLException e) {e.printStackTrace();
}
return 0;
}
业务层
//IManagerService.java
int updateManagerTwo(Manager m1,Manager m2);
//ManagerServiceImpl.java
public int updateManagerTwo(Manager m1, Manager m2) {return managerDaoImpl.updateManagerTwo(m1,m2);
}
2.1.3、编写测试类
STest1.java
import com.tyschool.spring003.javabean.Manager;
import com.tyschool.spring003.manager.service.IManagerService;
import com.tyschool.spring003.utils.BeanFactory;
import org.junit.Test;
public class STest1 {private IManagerService ims= (IManagerService) BeanFactory.getBean("managerServiceImpl");
@Test
public void updateManagerTwo(){Manager m1=ims.findById(4);
Manager m2=ims.findById(5);
m1.setPword("12345");
m2.setPword("12345");
ims.updateManagerTwo(m1,m2);
}
}
2.2、当第二条 SQL 出现问题时
将 mid 改为 id
runner.update("update manager set uname=?,pword=?,zcsj=? where id=?",m2.getUname(),m2.getPword(),m2.getZcsj(),m2.getMid());
在进行测试:
事务并没有回滚,一条件数据发生变化。
2.3、修改事务提交
修改 updateManagerTwo() 方法
public int updateManagerTwo(Manager m1, Manager m2) {DataSource ds=runner.getDataSource();
Connection conn=null;
try {conn=ds.getConnection();
conn.setAutoCommit(false);
System.out.println(conn);
runner =new QueryRunner();
runner.update(conn,"update manager set uname=?,pword=?,zcsj=? where mid=?",m1.getUname(),m1.getPword(),m1.getZcsj(),m1.getMid());
runner.update(conn,"update manager set uname=?,pword=?,zcsj=? where mid=?",m2.getUname(),m2.getPword(),m2.getZcsj(),m2.getMid());
conn.commit();} catch (SQLException e) {e.printStackTrace();
try {conn.rollback();
} catch (SQLException ex) {ex.printStackTrace();
}
}finally{try {conn.close();
} catch (SQLException e) {e.printStackTrace();
}
}
return 0;
}
测试:
有异常就回滚,没有异常就提交
问题:
如果每个方法里都有多条 SQL 语句的操作,那么我们所有的方法都得修改为手动提交事务。那么业务层方法里面充斥着很多重复代码。并且业务层方法和事务控制方法耦合了。
3、动态代理
3.1、回顾
我们在第一阶段中已经学习过代理模式(设计模式与设计原则 - 代理模式),我们简单来回顾一下:
3.1.1、什么是代理
本来应该自己做的事情,却请了别人来做,被请的人就是代理对象。
3.1.2、代理分类
** 静态代理:** 被代理对象与代理对象需要一起实现相同的接口或者是继承相同父类。
** 动态代理:** 利用反射机制在运行时创建代理类。
3.1.3、为什么要用动态代理
动态代理的目的是在不更改原有对象(目标对象)的基础上实现功能代码的增强。
3.1.4、代理的实现方式
Proxy 类实现动态代理
CGLIB 实现动态代理
3.2、还原初始项目
3.2.1、创建项目
通过 Maven 创建 spring005 项目
3.2.2、导入对应的 jar 包
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.tyschool</groupId>
<artifactId>spring005</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.13.0</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>5.2.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.2.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>5.2.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.2.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.2.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.2.2.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.11</version>
</dependency>
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.3</version>
</dependency>
<dependency>
<groupId>commons-dbutils</groupId>
<artifactId>commons-dbutils</artifactId>
<version>1.6</version>
</dependency>
</dependencies>
</project>
3.2.3、创建 javabean
Manager.java
package com.tyschool.spring005.javabean;
import org.apache.commons.dbutils.ResultSetHandler;
import java.io.Serializable;
import java.util.Date;
public class Manager implements Serializable {private int mid;
private String uname;
private String pword;
private Date zcsj;
public int getMid() {return mid;
}
public void setMid(int mid) {this.mid = mid;
}
public String getUname() {return uname;
}
public void setUname(String uname) {this.uname = uname;
}
public String getPword() {return pword;
}
public void setPword(String pword) {this.pword = pword;
}
public Date getZcsj() {return zcsj;
}
public void setZcsj(Date zcsj) {this.zcsj = zcsj;
}
@Override
public String toString() {return "Manager{" +
"mid=" + mid +
", uname='" + uname + '\'' +
", pword='" + pword + '\'' +
", zcsj=" + zcsj +
'}';
}
}
3.2.4、完成持久层编写
//IManagerDao.java
import com.tyschool.spring005.javabean.Manager;
public interface IManagerDao {int updateManagerTwo(Manager m1, Manager m2);
}
//ManagerDaoImpl.java
import com.tyschool.spring005.javabean.Manager;
import com.tyschool.spring005.manager.dao.IManagerDao;
import org.apache.commons.dbutils.QueryRunner;
import java.sql.SQLException;
public class ManagerDaoImpl implements IManagerDao {private QueryRunner runner;
public void setRunner(QueryRunner runner) {this.runner = runner;
}
public int updateManagerTwo(Manager m1, Manager m2) {try {runner.update("update manager set uname=?,pword=?,zcsj=? where mid=?",m1.getUname(),m1.getPword(),m1.getZcsj(),m1.getMid());
runner.update("update manager set uname=?,pword=?,zcsj=? where mid=?",m2.getUname(),m2.getPword(),m2.getZcsj(),m2.getMid());
} catch (SQLException e) {e.printStackTrace();
}
return 0;
}
}
3.2.5、完成业务层编写
//IManagerService.java
import com.tyschool.spring005.javabean.Manager;
public interface IManagerService {int updateManagerTwo(Manager m1, Manager m2);
}
//ManagerServcieImpl.java
import com.tyschool.spring005.javabean.Manager;
import com.tyschool.spring005.manager.dao.IManagerDao;
import com.tyschool.spring005.manager.service.IManagerService;
public class ManagerServiceImpl implements IManagerService {private IManagerDao managerDaoImpl;
public void setManagerDaoImpl(IManagerDao managerDaoImpl) {this.managerDaoImpl = managerDaoImpl;
}
public int updateManagerTwo(Manager m1, Manager m2) {return managerDaoImpl.updateManagerTwo(m1,m2);
}
}
3.2.6、编写配置文件
applicationContext.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="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<!-- 连接数据库的必备信息 -->
<property name="driverClass" value="com.mysql.cj.jdbc.Driver"></property>
<property name="jdbcUrl" value="jdbc:mysql://192.168.1.123:3306/spring?serverTimezone=UTC"></property>
<property name="user" value="root"></property>
<property name="password" value="Root12345"></property>
</bean>
<!-- 配置 QueryRunner-->
<bean id="runner" class="org.apache.commons.dbutils.QueryRunner" scope="prototype">
<!-- 注入数据源 -->
<constructor-arg name="ds" ref="dataSource"></constructor-arg>
</bean>
<!-- 配置 DAO -->
<bean id="managerDaoImpl" class="com.tyschool.spring005.manager.dao.impl.ManagerDaoImpl" >
<property name="runner" ref="runner"></property>
</bean>
<!-- 配置 Service -->
<bean id="managerServiceImpl" class="com.tyschool.spring005.manager.service.impl.ManagerServiceImpl">
<property name="managerDaoImpl" ref="managerDaoImpl"></property>
</bean>
</beans>
3.2.7、创建工厂类
BeanFactory.java
import com.tyschool.spring005.manager.service.IManagerService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class BeanFactory {private static ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");;
private BeanFactory(){ }
public static IManagerService getIManagerService() {IManagerService iss =(IManagerService)context.getBean("managerServiceImpl");
return iss;
}
}
3.2.8、编写测试类
package com.tyschool.spring005.test;
import com.tyschool.spring005.javabean.Manager;
import com.tyschool.spring005.manager.service.IManagerService;
import com.tyschool.spring005.utils.BeanFactory;
import org.junit.Test;
public class STest {private IManagerService ims= (IManagerService) BeanFactory.getIManagerService();
@Test
public void updateManagerTwo(){Manager m1=new Manager();
Manager m2=new Manager();
m1.setPword("27966");
m2.setPword("27966");
m1.setMid(4);
m2.setMid(5);
ims.updateManagerTwo(m1,m2);
}
}
4、代理模式解决事务 - 上
4.1、代理事务分析
我们需要用业务层来控制事务的提交和回滚,当我们执行数据更新时,如果执行有异常,修改失败。但是因为我们是每次执行持久层方法都是独立事务,导致无法实现事务控制。
这个时候我们一次完整的操作使用到的 Connection 应该是同一个,而不是像前面 ManagerDaoImpl 类里面的 QueryRunner,每次操作都是从连接池里面拿到的新的连接。
4.2、代理的实现
4.2.1、创建工具类
ConnectionUtils.java
import javax.sql.DataSource;
import java.sql.Connection;
/**
* 连接的工具类,它用于从数据源中获取一个连接,并且实现和线程的绑定
*/
public class ConnectionUtils{private ThreadLocal<Connection> tl = new ThreadLocal<Connection>();
private DataSource dataSource;
public void setDataSource(DataSource dataSource) {this.dataSource = dataSource;
}
/**
* 获取当前线程上的连接
*
* @return
*/
public Connection getThreadConnection() {try {//1. 先从 ThreadLocal 上获取
Connection conn = tl.get();
//2. 判断当前线程上是否有连接
if (conn == null) {//3. 从数据源中获取一个连接,并且存入 ThreadLocal 中
conn = dataSource.getConnection();
tl.set(conn);
}
//4. 返回当前线程上的连接
return conn;
} catch (Exception e) {throw new RuntimeException(e);
}
}
/**
* 把连接和线程解绑
*/
public void removeConnection() {tl.remove();
}
}
注意:
使用 ThreadLocal 是为了让我们的同一个线程访问到同一个 Connection。
TransactionManager.java
import org.apache.commons.dbutils.QueryRunner;
import java.sql.SQLException;
/*
和事务管理相关的工具类,它包含了,开启事务,提交事务,回滚事务和释放连接
*/
public class TransactionManager {private ConnectionUtils connectionUtils;
public void setConnectionUtils(ConnectionUtils connectionUtils) {this.connectionUtils = connectionUtils;
}
/**
* 开启事务
*/
public void beginTransaction() {try {connectionUtils.getThreadConnection().setAutoCommit(false);
} catch (Exception e) {e.printStackTrace();
}
}
/**
* 提交事务
*/
public void commit() {try {connectionUtils.getThreadConnection().commit();} catch (Exception e) {e.printStackTrace();
}
}
/**
* 回滚事务
*/
public void rollback() {try {connectionUtils.getThreadConnection().rollback();} catch (Exception e) {e.printStackTrace();
}
}
/**
* 释放连接
*/
public void release() {try {connectionUtils.getThreadConnection().close();// 还回连接池中
connectionUtils.removeConnection();} catch (Exception e) {e.printStackTrace();
}
}
}
注意:
由于我们使用了连接池和线程池技术,连接使用完要关闭,线程使用结束过后我们是要归。
4.2.2、修改 ManagerDaoImpl.java
import com.tyschool.spring005.javabean.Manager;
import com.tyschool.spring005.manager.dao.IManagerDao;
import com.tyschool.spring005.utils.ConnectionUtils;
import org.apache.commons.dbutils.QueryRunner;
import java.sql.SQLException;
public class ManagerDaoImpl implements IManagerDao {private QueryRunner runner;
private ConnectionUtils connectionUtils;
public void setRunner(QueryRunner runner) {this.runner = runner;
}
public void setConnectionUtils(ConnectionUtils connectionUtils) {this.connectionUtils = connectionUtils;
}
public int updateManagerTwo(Manager m1, Manager m2) {try {runner.update(connectionUtils.getThreadConnection(),"update manager set uname=?,pword=?,zcsj=? where mid=?",m1.getUname(),m1.getPword(),m1.getZcsj(),m1.getMid());
runner.update(connectionUtils.getThreadConnection(),"update manager set uname=?,pword=?,zcsj=? where mid=?",m2.getUname(),m2.getPword(),m2.getZcsj(),m2.getMid());
} catch (SQLException e) {e.printStackTrace();
}
return 0;
}
}
4.2.3、修改 ManagerServiceImpl.java
import com.tyschool.spring005.javabean.Manager;
import com.tyschool.spring005.manager.dao.IManagerDao;
import com.tyschool.spring005.manager.service.IManagerService;
import com.tyschool.spring005.utils.TransactionManager;
public class ManagerServiceImpl implements IManagerService {private IManagerDao managerDaoImpl;
private TransactionManager txManager;
public void setTxManager(TransactionManager txManager) {this.txManager = txManager;
}
public void setManagerDaoImpl(IManagerDao managerDaoImpl) {this.managerDaoImpl = managerDaoImpl;
}
public int updateManagerTwo(Manager m1, Manager m2) {int n= 0;
try {txManager.beginTransaction();
n = managerDaoImpl.updateManagerTwo(m1,m2);
txManager.commit();} catch (Exception e) {e.printStackTrace();
txManager.rollback();} finally {txManager.release();
}
return n;
}
}
注意:
如果我们这样去书写事务的话,service 中每加入一个操作,都要去书写一次事务,所以我们要使用代理。
5、代理模式解决事务 - 下
5.1、代理的实现
5.1.1、编写代理类
A、我们要代理的对象是 IManagerService
B、编写代理类
ProxyIMS.java
import com.tyschool.spring005.manager.service.IManagerService;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyIMS {private IManagerService managerService;
private TransactionManager txManager;
public void setManagerService(IManagerService managerService) {this.managerService = managerService;
}
public void setTransactionManager(TransactionManager txManager) {this.txManager = txManager;
}
public IManagerService getManagerService(){return (IManagerService)Proxy.newProxyInstance(managerService.getClass().getClassLoader(),
managerService.getClass().getInterfaces(),
new InvocationHandler(){public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result;
try {//1. 开启事务
txManager.beginTransaction();
//2. 执行操作
result = method.invoke(managerService, args);
//3. 提交事务
txManager.commit();
//4. 返回结果
return result;
} catch (Exception e) {//5. 回滚操作
txManager.rollback();
throw new RuntimeException(e);
} finally {//6. 释放连接
txManager.release();}
}
});
}
}
5.1.2、修改配置文件
<?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="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<!-- 连接数据库的必备信息 -->
<property name="driverClass" value="com.mysql.cj.jdbc.Driver"></property>
<property name="jdbcUrl" value="jdbc:mysql://192.168.1.123:3306/spring?serverTimezone=UTC"></property>
<property name="user" value="root"></property>
<property name="password" value="Root12345"></property>
</bean>
<!-- 配置 QueryRunner-->
<bean id="runner" class="org.apache.commons.dbutils.QueryRunner" scope="prototype">
<!-- 注入数据源 -->
<!-- <constructor-arg name="ds" ref="dataSource"></constructor-arg>-->
</bean>
<!-- 配置 DAO -->
<bean id="managerDaoImpl" class="com.tyschool.spring005.manager.dao.impl.ManagerDaoImpl" >
<property name="runner" ref="runner"></property>
<property name="connectionUtils" ref="connectionUtils"></property>
</bean>
<!-- 配置 Service -->
<bean id="managerServiceImpl" class="com.tyschool.spring005.manager.service.impl.ManagerServiceImpl">
<property name="managerDaoImpl" ref="managerDaoImpl"></property>
<property name="txManager" ref="txManager"></property>
</bean>
<!-- 配置连接工具类 -->
<bean id="connectionUtils" class="com.tyschool.spring005.utils.ConnectionUtils">
<!-- 注入数据源 -->
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 配置事务 -->
<bean id="txManager" class="com.tyschool.spring005.utils.TransactionManager">
<!-- 注入连接工具类 -->
<property name="connectionUtils" ref="connectionUtils"></property>
</bean>
<!-- 配置代理类 -->
<bean id="proxyIMS" class="com.tyschool.spring005.utils.ProxyIMS">
<!-- 注入事务管理 -->
<property name="txManager" ref="txManager"></property>
<!-- 注入 service-->
<property name="managerService" ref="managerServiceImpl"></property>
</bean>
<!-- 配置代理 -->
<bean id="proxyIManagerService" factory-bean="proxyIMS" factory-method="getManagerService"></bean>
</beans>
5.1.3、编写工厂类
import com.tyschool.spring005.manager.service.IManagerService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class BeanFactory {private static ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");;
private BeanFactory(){ }
public static IManagerService getIManagerService() {IManagerService iss =(IManagerService)context.getBean("managerServiceImpl");
return iss;
}
public static IManagerService getIManagerServiceProxy(){IManagerService iss =(IManagerService)context.getBean("proxyIManagerService");
return iss;
}
}
5.1.4、编写测试类
STest.java
import com.tyschool.spring005.javabean.Manager;
import com.tyschool.spring005.manager.service.IManagerService;
import com.tyschool.spring005.utils.BeanFactory;
import org.junit.Test;
public class STest {//private IManagerService ims= (IManagerService) BeanFactory.getIManagerService();
private IManagerService ims= (IManagerService) BeanFactory.getIManagerServiceProxy();
@Test
public void updateManagerTwo(){Manager m1=new Manager();
Manager m2=new Manager();
m1.setPword("27968");
m2.setPword("27968");
m1.setMid(4);
m2.setMid(5);
ims.updateManagerTwo(m1,m2);
}
}
6、Spring-AOP 完成事务
6.1、升级项目
通过升级 spring005 项目
6.2、导入 AOP 包
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.tyschool</groupId>
<artifactId>spring005</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.13.0</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>5.2.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>5.2.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.2.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.2.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.2.2.RELEASE</version>
</dependency>
<dependency>
<groupId>aopalliance</groupId>
<artifactId>aopalliance</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.5</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.2.2.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.11</version>
</dependency>
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.3</version>
</dependency>
<dependency>
<groupId>commons-dbutils</groupId>
<artifactId>commons-dbutils</artifactId>
<version>1.6</version>
</dependency>
</dependencies>
</project>
6.3、创建 applicationContext-aop.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"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 配置数据源 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<!-- 连接数据库的必备信息 -->
<property name="driverClass" value="com.mysql.cj.jdbc.Driver"></property>
<property name="jdbcUrl" value="jdbc:mysql://192.168.1.123:3306/spring?serverTimezone=UTC"></property>
<property name="user" value="root"></property>
<property name="password" value="Root12345"></property>
</bean>
<!-- 配置 QueryRunner-->
<bean id="runner" class="org.apache.commons.dbutils.QueryRunner" scope="prototype">
<!-- 注入数据源 -->
<!-- <constructor-arg name="ds" ref="dataSource"></constructor-arg>-->
</bean>
<!-- 配置连接工具类 -->
<bean id="connectionUtils" class="com.tyschool.spring005.utils.ConnectionUtils">
<!-- 注入数据源 -->
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 配置事务 -->
<bean id="txManager" class="com.tyschool.spring005.utils.TransactionManager">
<!-- 注入连接工具类 -->
<property name="connectionUtils" ref="connectionUtils"></property>
</bean>
<!-- 配置 DAO -->
<bean id="managerDaoImpl" class="com.tyschool.spring005.manager.dao.impl.ManagerDaoImpl" >
<property name="runner" ref="runner"></property>
<property name="connectionUtils" ref="connectionUtils"></property>
</bean>
<!-- 配置 Service -->
<bean id="managerServiceImpl" class="com.tyschool.spring005.manager.service.impl.ManagerServiceImpl">
<property name="managerDaoImpl" ref="managerDaoImpl"></property>
</bean>
<!-- 配置 aop-->
<aop:config>
<!-- 配置通用切入点表达式 -->
<aop:pointcut id="pt1" expression="execution(* com.tyschool.spring005.manager.service.impl.*.*(..))"/>
<aop:aspect id="txAdvice" ref="txManager">
<!-- 配置前置通知:开启事务 -->
<aop:before method="beginTransaction" pointcut-ref="pt1"/>
<!-- 配置后置通知:提交事务 -->
<aop:after-returning method="commit" pointcut-ref="pt1"/>
<!-- 配置异常通知:回滚事务 -->
<aop:after-throwing method="rollback" pointcut-ref="pt1"/>
<!-- 配置最终通知:释放连接 -->
<aop:after method="release" pointcut-ref="pt1"/>
</aop:aspect>
</aop:config>
</beans>
6.4、使用测试类
import com.tyschool.spring005.javabean.Manager;
import com.tyschool.spring005.manager.service.IManagerService;
import com.tyschool.spring005.utils.BeanFactory;
import org.junit.Test;
public class STest {private IManagerService ims= (IManagerService) BeanFactory.getIManagerService();
//private IManagerService ims= (IManagerService) BeanFactory.getIManagerServiceProxy();
@Test
public void updateManagerTwo(){Manager m1=new Manager();
Manager m2=new Manager();
m1.setPword("27969");
m2.setPword("27969");
m1.setMid(4);
m2.setMid(5);
ims.updateManagerTwo(m1,m2);
}
}
7、AOP 配置详解 - 上
7.1、aop-config
** 作用:** 用于声明开始 aop 配置
<aop:config>
.....
</aop:config>
7.2、aop-pointcut
** 作用:** 表示 aop 切入点
属性:
expression: 定义切入点的表达式
id: 用于给切入点表达式提供 一个唯一标识
<aop:pointcut id="pt1" expression="execution(public void com.tyschool.spring005.manager.service.impl.ManagerServiceImpl.updateManagerTwo(com.tyschool.spring005.javabean.Manager,com.tyschool.spring005.javabean.Manager))"/>
expression 说明:
表达式语法:execution([修饰符] 返回值类型 包名. 类名. 方法名 (参数))
// 全匹配方式:
public void com.tyschool.spring005.manager.service.impl.ManagerServiceImpl.updateManagerTwo(com.tyschool.spring005.javabean.Manager,com.tyschool.spring005.javabean.Manager)
// 访问修饰符可以省略
void com.tyschool.spring005.manager.service.impl.ManagerServiceImpl.updateManagerTwo(com.tyschool.spring005.javabean.Manager,com.tyschool.spring005.javabean.Manager)
// 返回值可以使用 * 号,表示任意返回值
* com.tyschool.spring005.manager.service.impl.ManagerServiceImpl.updateManagerTwo(com.tyschool.spring005.javabean.Manager,com.tyschool.spring005.javabean.Manager)
// 包名可以使用 * 号,表示任意包,但是有几级包,需要写几个 *
* *.*.*.manager.service.impl.ManagerServiceImpl.updateManagerTwo(com.tyschool.spring005.javabean.Manager,com.tyschool.spring005.javabean.Manager)
// 使用.. 来表示当前包,及其子包
* com.tyschool.spring005..ManagerServiceImpl.updateManagerTwo(com.tyschool.spring005.javabean.Manager,com.tyschool.spring005.javabean.Manager)
// 类名可以使用 * 号,表示任意类
* com.tyschool.spring005..*.updateManagerTwo(com.tyschool.spring005.javabean.Manager,com.tyschool.spring005.javabean.Manager)
// 方法名可以使用 * 号,表示任意方法
* com.tyschool.spring005..*.*(com.tyschool.spring005.javabean.Manager,com.tyschool.spring005.javabean.Manager)
// 参数列表可以使用 *,表示参数可以是任意数据类型,但是必须有参数
* com.tyschool.spring005..*.*(*,com.tyschool.spring005.javabean.Manager)
// 参数列表可以使用.. 表示有无参数均可,有参数可以是任意类型
* com.tyschool.spring005..*.*(..)
全通配方式:* *..*.*(..)
<aop:pointcut id="pt1" expression="execution(* com.tyschool.spring005.manager.service.impl.*.*(..))"/>
8、AOP 配置详解 - 下
8.1、aop-aspect
** 作用:** 配置切面
属性:
id: 给切面的唯一标识
ref: 引用配置好的 bean 作为切面
<!-- 配置事务 -->
<bean id="txManager" class="com.tyschool.spring005.utils.TransactionManager">
<!-- 注入连接工具类 -->
<property name="connectionUtils" ref="connectionUtils"></property>
</bean>
<aop:aspect id="txAdvice" ref="txManager">
</aop:aspect>
8.2、通知 (aop:xxx)
8.2.1、aop:before
** 作用:** 前置通知,切入点方法执行之前执行
属性:
method: 指定前置通知的要执行方法
ponitcut-ref: 指定前置通知切入点
<!-- 配置前置通知:开启事务 -->
<aop:before method="beginTransaction" pointcut-ref="pt1"/>
8.2.2、aop:after-returning
** 作用:** 后置通知,切入点方法执行后,它和异常只能有一个执行
属性:
method: 指定前置通知的要执行方法
ponitcut-ref: 指定前置通知切入点
<!-- 配置后置通知:提交事务 -->
<aop:after-returning method="commit" pointcut-ref="pt1"/>
8.2.3、aop:after-throwing
** 作用:** 异常通知,切入点方法执行,产生异常后执行,它和后置通知只能执行一个
属性:
method: 指定前置通知的要执行方法
ponitcut-ref: 指定前置通知切入点
<!-- 配置异常通知:回滚事务 -->
<aop:after-throwing method="rollback" pointcut-ref="pt1"/>
8.2.4、aop:after
** 作用:** 最终通知,无论前面的通知是否执行,它都会执行
属性:
method: 指定前置通知的要执行方法
ponitcut-ref: 指定前置通知切入点
<!-- 配置最终通知:释放连接 -->
<aop:after method="release" pointcut-ref="pt1"/>
9、环绕通知
9.1、环绕通知
可以在方法之前、之后、发生异常时执行!
9.2、修改 TransactionManager.java
package com.tyschool.spring005.utils;
import org.apache.commons.dbutils.QueryRunner;
import org.aspectj.lang.ProceedingJoinPoint;
import java.sql.SQLException;
public class TransactionManager {private ConnectionUtils connectionUtils;
public void setConnectionUtils(ConnectionUtils connectionUtils) {this.connectionUtils = connectionUtils;
}
public Object transactionAround(ProceedingJoinPoint pjp) {// 定义返回值
Object rtValue = null;
try {// 获取方法执行所需的参数
Object[] args = pjp.getArgs();
// 前置通知:开启事务
connectionUtils.getThreadConnection().setAutoCommit(false);
// 执行方法
rtValue = pjp.proceed(args);
// 后置通知:提交事务
connectionUtils.getThreadConnection().commit();
}catch(Throwable e) {// 异常通知:回滚事务
try {connectionUtils.getThreadConnection().rollback();} catch (SQLException ex) {ex.printStackTrace();
}
e.printStackTrace();}finally {// 最终通知:释放资源
try {connectionUtils.getThreadConnection().close();} catch (SQLException e) {e.printStackTrace();
}
connectionUtils.removeConnection();}
return rtValue; }
}
9.3、修改配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 配置数据源 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<!-- 连接数据库的必备信息 -->
<property name="driverClass" value="com.mysql.cj.jdbc.Driver"></property>
<property name="jdbcUrl" value="jdbc:mysql://192.168.1.123:3306/spring?serverTimezone=UTC"></property>
<property name="user" value="root"></property>
<property name="password" value="Root12345"></property>
</bean>
<!-- 配置 QueryRunner-->
<bean id="runner" class="org.apache.commons.dbutils.QueryRunner" scope="prototype">
<!-- 注入数据源 -->
<!-- <constructor-arg name="ds" ref="dataSource"></constructor-arg>-->
</bean>
<!-- 配置连接工具类 -->
<bean id="connectionUtils" class="com.tyschool.spring005.utils.ConnectionUtils">
<!-- 注入数据源 -->
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 配置事务 -->
<bean id="txManager" class="com.tyschool.spring005.utils.TransactionManager">
<!-- 注入连接工具类 -->
<property name="connectionUtils" ref="connectionUtils"></property>
</bean>
<!-- 配置 DAO -->
<bean id="managerDaoImpl" class="com.tyschool.spring005.manager.dao.impl.ManagerDaoImpl" >
<property name="runner" ref="runner"></property>
<property name="connectionUtils" ref="connectionUtils"></property>
</bean>
<!-- 配置 Service -->
<bean id="managerServiceImpl" class="com.tyschool.spring005.manager.service.impl.ManagerServiceImpl">
<property name="managerDaoImpl" ref="managerDaoImpl"></property>
</bean>
<!-- 配置 aop-->
<aop:config>
<aop:pointcut id="pt1" expression="execution(* com.tyschool.spring005.manager.service.impl.*.*(..))"/>
<aop:aspect id="txAdvice" ref="txManager">
<aop:around method="transactionAround" pointcut-ref="pt1"/>
</aop:aspect>
</aop:config>
</beans>
测试
10、还原注解项目
10.1、创建项目
通过 maven 创建一个 spring006 项目
10.2、引入 jar 包
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.tyschool</groupId>
<artifactId>spring006</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.13.0</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>5.2.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.2.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>5.2.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.2.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.2.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.2.2.RELEASE</version>
</dependency>
<dependency>
<groupId>aopalliance</groupId>
<artifactId>aopalliance</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.5</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.2.2.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.11</version>
</dependency>
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.3</version>
</dependency>
<dependency>
<groupId>commons-dbutils</groupId>
<artifactId>commons-dbutils</artifactId>
<version>1.6</version>
</dependency>
</dependencies>
</project>
10.3、创建 javabean
Manager.java
import java.io.Serializable;
import java.util.Date;
public class Manager implements Serializable {private int mid;
private String uname;
private String pword;
private Date zcsj;
public int getMid() {return mid;
}
public void setMid(int mid) {this.mid = mid;
}
public String getUname() {return uname;
}
public void setUname(String uname) {this.uname = uname;
}
public String getPword() {return pword;
}
public void setPword(String pword) {this.pword = pword;
}
public Date getZcsj() {return zcsj;
}
public void setZcsj(Date zcsj) {this.zcsj = zcsj;
}
@Override
public String toString() {return "Manager{" +
"mid=" + mid +
", uname='" + uname + '\'' +
", pword='" + pword + '\'' +
", zcsj=" + zcsj +
'}';
}
}
10.4、持久层与业务层
持久层
//IManagerDao.java
import com.tyschool.spring006.javabean.Manager;
import java.util.List;
public interface IManagerDao {List<Manager> findAll();
int updateManagerTwo(Manager m1, Manager m2);
}
//ManagerDaoImpl.java
package com.tyschool.spring006.manager.dao.impl;
import com.tyschool.spring006.javabean.Manager;
import com.tyschool.spring006.manager.dao.IManagerDao;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Repository;
import java.sql.SQLException;
import java.util.List;
@Repository("managerDaoImpl")
public class ManagerDaoImpl implements IManagerDao {@Autowired
@Qualifier("queryRunner")
private QueryRunner runner;
public List<Manager> findAll() {List<Manager> list=null;
try {list=runner.query("select * from manager",new BeanListHandler<Manager>(Manager.class));
} catch (SQLException e) {e.printStackTrace();
}
return list;
}
public int updateManagerTwo(Manager m1, Manager m2) {System.out.println("dao");
try {runner.update("update manager set uname=?,pword=?,zcsj=? where mid=?",m1.getUname(),m1.getPword(),m1.getZcsj(),m1.getMid());
//int i=1/0;
runner.update("update manager set uname=?,pword=?,zcsj=? where mid=?",m2.getUname(),m2.getPword(),m2.getZcsj(),m2.getMid());
} catch (SQLException e) {e.printStackTrace();
}
System.out.println("daoend");
return 0;
}
}
业务层
//IManagerService.java
import com.tyschool.spring006.javabean.Manager;
import java.util.List;
public interface IManagerService {List<Manager> findAll();
int updateManagerTwo(Manager m1, Manager m2);
}
//ManagerServiceImpl.java
package com.tyschool.spring006.manager.service.impl;
import com.tyschool.spring006.javabean.Manager;
import com.tyschool.spring006.manager.dao.IManagerDao;
import com.tyschool.spring006.manager.service.IManagerService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import java.util.List;
Service("managerServiceImpl")
public class ManagerServiceImpl implements IManagerService {@Autowired
@Qualifier("managerDaoImpl")
private IManagerDao imd;
public List<Manager> findAll() {return imd.findAll();}
public int updateManagerTwo(Manager m1, Manager m2) {return imd.updateManagerTwo(m1,m2);
}
}
10.5、编写 Bean
db.properties
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://192.168.1.123:3306/spring?serverTimezone=UTC
jdbc.username=root
jdbc.password=Root12345
DbUtilsC3P0.java
package com.tyschool.spring006.utils;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.apache.commons.dbutils.QueryRunner;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.PropertySource;
import javax.sql.DataSource;
import java.beans.PropertyVetoException;
@Component
@PropertySource(value={"classpath:db.properties"},ignoreResourceNotFound = false)
public class DbUtilsC3P0 {@Value("${jdbc.driver}")
private String driver;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
// 配置数据源
@Bean(name="dataSource")
public DataSource createDateSource(){ComboPooledDataSource cds=new ComboPooledDataSource();
try {cds.setDriverClass(driver);
cds.setJdbcUrl(url);
cds.setUser(username);
cds.setPassword(password);
} catch (PropertyVetoException e) {e.printStackTrace();
}
return cds;
}
@Bean(name="queryRunner")
public QueryRunner createQueryRunner(DataSource dataSource){return new QueryRunner(dataSource);
}
}
10.6、编写配置文件
applicationContext.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"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--spring 创建对象时要扫描的包 -->
<context:component-scan base-package="com.tyschool.spring006"></context:component-scan>
<!-- 引入数据源文件 -->
<context:property-placeholder location="classpath:db.properties" />
10.7、测试
import com.tyschool.spring006.javabean.Manager;
import com.tyschool.spring006.manager.service.IManagerService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.util.List;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(value={"classpath:applicationContext.xml"})
public class STest {@Autowired
@Qualifier("managerServiceImpl")
private IManagerService ims;
@Test
public void findAll(){List<Manager> list = ims.findAll();
for(Manager m:list){System.out.println(m);
}
}
}
11、Spring-AOP 注解完成事务
11.1、添加连接工具类
ConnectionUtils.java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import javax.sql.DataSource;
import java.sql.Connection;
/**
* 连接的工具类,它用于从数据源中获取一个连接,并且实现和线程的绑定
*/
@Component("connectionUtils")
public class ConnectionUtils {private ThreadLocal<Connection> tl = new ThreadLocal<Connection>();
@Autowired
@Qualifier("dataSource")
private DataSource dataSource;
/**
* 获取当前线程上的连接
*
* @return
*/
public Connection getThreadConnection() {try {//1. 先从 ThreadLocal 上获取
Connection conn = tl.get();
//2. 判断当前线程上是否有连接
if (conn == null) {//3. 从数据源中获取一个连接,并且存入 ThreadLocal 中
conn = dataSource.getConnection();
tl.set(conn);
}
//4. 返回当前线程上的连接
return conn;
} catch (Exception e) {throw new RuntimeException(e);
}
}
/**
* 把连接和线程解绑
*/
public void removeConnection() {tl.remove();
}
}
11.2、添加切面事务类
TransactionManager.java
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
@Component("txManager")
@Aspect
public class TransactionManager {@Autowired
@Qualifier("connectionUtils")
private ConnectionUtils connectionUtils;
/**
* 开启事务
*/
@Before("execution(* com.tyschool.spring006.manager.service.impl.*.*(..))")
public void beginTransaction() {System.out.println("begin");
try {connectionUtils.getThreadConnection().setAutoCommit(false);
} catch (Exception e) {e.printStackTrace();
}
}
/**
* 提交事务
*/
@AfterReturning("execution(* com.tyschool.spring006.manager.service.impl.*.*(..))")
public void commit() {System.out.println("commit");
try {connectionUtils.getThreadConnection().commit();} catch (Exception e) {e.printStackTrace();
}
}
/**
* 回滚事务
*/
@AfterThrowing("execution(* com.tyschool.spring006.manager.service.impl.*.*(..))")
public void rollback() {System.out.println("rollback");
try {connectionUtils.getThreadConnection().rollback();} catch (Exception e) {e.printStackTrace();
}
}
/**
* 释放连接
*/
@After("execution(* com.tyschool.spring006.manager.service.impl.*.*(..))")
public void release() {System.out.println("release");
try {connectionUtils.getThreadConnection().close();// 还回连接池中
connectionUtils.removeConnection();} catch (Exception e) {e.printStackTrace();
}
}
}
注意:
@Aspect:表示当前类是一个切面
@Before:前置通知
@AfterReturning:后置通知
@AfterThrowing:异常通知
@After:最终通知
11.3、开启 Spring 对注解 AOP 支持
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--spring 创建对象时要扫描的包 -->
<context:component-scan base-package="com.tyschool.spring006"></context:component-scan>
<!-- 引入数据源文件 -->
<context:property-placeholder location="classpath:db.properties" />
<!-- 声明自动为 spring 容器中那些配置 @aspectJ 切面的 bean 创建代理,织入切面。-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
11.4、修改 ManagerDaoImpl.java
package com.tyschool.spring006.manager.dao.impl;
import com.tyschool.spring006.javabean.Manager;
import com.tyschool.spring006.manager.dao.IManagerDao;
import com.tyschool.spring006.utils.ConnectionUtils;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Repository;
import java.sql.SQLException;
import java.util.List;
@Repository("managerDaoImpl")
public class ManagerDaoImpl implements IManagerDao {@Autowired
@Qualifier("queryRunner")
private QueryRunner runner;
@Autowired
@Qualifier("connectionUtils")
private ConnectionUtils connectionUtils;
public List<Manager> findAll() {List<Manager> list=null;
try {list=runner.query(connectionUtils.getThreadConnection(),"select * from manager",new BeanListHandler<Manager>(Manager.class));
} catch (SQLException e) {e.printStackTrace();
}
return list;
}
public int updateManagerTwo(Manager m1, Manager m2) {System.out.println("dao");
try {runner.update(connectionUtils.getThreadConnection(),"update manager set uname=?,pword=?,zcsj=? where mid=?",m1.getUname(),m1.getPword(),m1.getZcsj(),m1.getMid());
//int i=1/0;
runner.update(connectionUtils.getThreadConnection(),"update manager set uname=?,pword=?,zcsj=? where mid=?",m2.getUname(),m2.getPword(),m2.getZcsj(),m2.getMid());
} catch (SQLException e) {e.printStackTrace();
}
System.out.println("daoend");
return 0;
}
}
11.5、测试
STest.java
package com.tyschool.spring006.test;
import com.tyschool.spring006.javabean.Manager;
import com.tyschool.spring006.manager.service.IManagerService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.util.List;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(value={"classpath:applicationContext.xml"})
public class STest {@Autowired
@Qualifier("managerServiceImpl")
private IManagerService ims;
@Test
public void findAll(){List<Manager> list = ims.findAll();
for(Manager m:list){System.out.println(m);
}
}
@Test
public void updateManagerTwo(){Manager m1=new Manager();
Manager m2=new Manager();
m1.setPword("27964");
m2.setPword("27964");
m1.setMid(4);
m2.setMid(5);
ims.updateManagerTwo(m1,m2);
}
}
11.6、注解事务出现的问题
java.sql.SQLException: Can''t call commit when autocommit=true
12、环绕通知(注解)
12.1、修改 TransactionManager.java
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
@Component("txManager")
@Aspect
public class TransactionManager {@Autowired
@Qualifier("connectionUtils")
private ConnectionUtils connectionUtils;
/**
* 开启事务
*/
@Before("execution(* com.tyschool.spring006.manager.service.impl.*.*(..))")
public void beginTransaction() {System.out.println("begin");
try {connectionUtils.getThreadConnection().setAutoCommit(false);
} catch (Exception e) {e.printStackTrace();
}
}
/**
* 提交事务
*/
@AfterReturning("execution(* com.tyschool.spring006.manager.service.impl.*.*(..))")
public void commit() {System.out.println("commit");
try {connectionUtils.getThreadConnection().commit();} catch (Exception e) {e.printStackTrace();
}
}
/**
* 回滚事务
*/
@AfterThrowing("execution(* com.tyschool.spring006.manager.service.impl.*.*(..))")
public void rollback() {System.out.println("rollback");
try {connectionUtils.getThreadConnection().rollback();} catch (Exception e) {e.printStackTrace();
}
}
/**
* 释放连接
*/
@After("execution(* com.tyschool.spring006.manager.service.impl.*.*(..))")
public void release() {System.out.println("release");
try {connectionUtils.getThreadConnection().close();// 还回连接池中
connectionUtils.removeConnection();} catch (Exception e) {e.printStackTrace();
}
}
// 环绕通知
@Around("execution(* com.tyschool.spring006.manager.service.impl.*.*(..))")
public Object transactionAround(ProceedingJoinPoint pjp) {// 定义返回值
Object rtValue = null;
try {// 获取方法执行所需的参数
Object[] args = pjp.getArgs();
// 前置通知:开启事务
beginTransaction();
// 执行方法
rtValue = pjp.proceed(args);
// 后置通知:提交事务
commit();} catch (Throwable e) {// 异常通知:回滚事务
rollback();
e.printStackTrace();} finally {// 最终通知:释放资源
release();}
return rtValue;
}
}
测试
12.2、切入点注解
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
@Component("txManager")
@Aspect
public class TransactionManager {@Autowired
@Qualifier("connectionUtils")
private ConnectionUtils connectionUtils;
/**
* 开启事务
*/
// @Before("execution(* com.tyschool.spring006.manager.service.impl.*.*(..))")
public void beginTransaction() {System.out.println("begin");
try {connectionUtils.getThreadConnection().setAutoCommit(false);
} catch (Exception e) {e.printStackTrace();
}
}
/**
* 提交事务
*/
// @AfterReturning("execution(* com.tyschool.spring006.manager.service.impl.*.*(..))")
public void commit() {System.out.println("commit");
try {connectionUtils.getThreadConnection().commit();} catch (Exception e) {e.printStackTrace();
}
}
/**
* 回滚事务
*/
// @AfterThrowing("execution(* com.tyschool.spring006.manager.service.impl.*.*(..))")
public void rollback() {System.out.println("rollback");
try {connectionUtils.getThreadConnection().rollback();} catch (Exception e) {e.printStackTrace();
}
}
/**
* 释放连接
*/
// @After("execution(* com.tyschool.spring006.manager.service.impl.*.*(..))")
public void release() {System.out.println("release");
try {connectionUtils.getThreadConnection().close();// 还回连接池中
connectionUtils.removeConnection();} catch (Exception e) {e.printStackTrace();
}
}
@Pointcut("execution(* com.tyschool.spring006.manager.service.impl.*.*(..))")
private void pt1(){}
// 环绕通知
@Around("pt1()")
public Object transactionAround(ProceedingJoinPoint pjp) {// 定义返回值
Object rtValue = null;
try {// 获取方法执行所需的参数
Object[] args = pjp.getArgs();
// 前置通知:开启事务
beginTransaction();
// 执行方法
rtValue = pjp.proceed(args);
// 后置通知:提交事务
commit();} catch (Throwable e) {// 异常通知:回滚事务
rollback();
e.printStackTrace();} finally {// 最终通知:释放资源
release();}
return rtValue;
}
}
测试
13、纯注解事务
13.1、编写配置类
SpringApplicationContext.java
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.context.annotation.Import;
@Configuration
@ComponentScan("com.tyschool.spring006")
@Import({DbUtilsC3P0.class})
@EnableAspectJAutoProxy
public class SpringApplicationContext {
}
13.2、编写测试类
STest1.java
import com.tyschool.spring006.javabean.Manager;
import com.tyschool.spring006.manager.service.IManagerService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = com.tyschool.spring006.utils.SpringApplicationContext.class)
public class STest1 {@Autowired
@Qualifier("managerServiceImpl")
private IManagerService ims;
@Test
public void updateManagerTwo(){Manager m1=new Manager();
Manager m2=new Manager();
m1.setPword("27965");
m2.setPword("27965");
m1.setMid(4);
m2.setMid(5);
ims.updateManagerTwo(m1,m2);
}
}