Spring中自带的事务管理器
1、编程式事务
详情可参考官方文档:
https://www.docs4dev.com/docs/zh/spring-framework/5.1.3.RELEASE/reference/data-access.html#transaction-programmatic
优点:不需要spring进行代理,生成代理对象(反射),性能更好
缺点:事务管理的逻辑必须与业务逻辑耦合,重用性差,扩展性也差
应用场景:项目中只有几个业务方法需要事务,则适合。
1.1、 测试代码:
1.1.1、生成事务管理(TransactionTemplate)的xml文件配置:
注意导入相关的包或者依赖喔
下面是我的maven配置文件:(需要的自提)
<dependencies>
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-core</artifactId>
<version>1.4.0</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache-core</artifactId>
<version>2.6.11</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.mybatis.caches</groupId>
<artifactId>mybatis-ehcache</artifactId>
<version>1.1.0</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.6</version>
</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>5.1.35</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.12</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>org.apache.taglibs</groupId>
<artifactId>taglibs-standard-spec</artifactId>
<version>1.2.5</version>
</dependency>
<dependency>
<groupId>org.apache.taglibs</groupId>
<artifactId>taglibs-standard-impl</artifactId>
<version>1.2.5</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.41</version>
</dependency>
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.1.2</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.3.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.3.2</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.3.2</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>5.3.2</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.2</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.3.2</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>5.3.2</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-instrument</artifactId>
<version>5.3.2</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.2</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jms</artifactId>
<version>5.3.2</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-messaging</artifactId>
<version>5.3.2</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>5.3.2</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-oxm</artifactId>
<version>5.3.2</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.6</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>RELEASE</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.25</version>
</dependency>
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.4</version>
</dependency>
</dependencies>
OK我们来开始整活:
直接上配置文件代码:
数据库配置:
url=jdbc:mysql://localhost:3306/test?useUnicode=true&&characterEncoding=utf-8
driver=com.mysql.jdbc.Driver
uName=root
password=123456
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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<!--1、加载数据库的配置信息 -->
<context:property-placeholder
location="database.properties" /><!--没有配置文件的记得先创建哦 -->
<!--2、datasource数据源 -->
<bean id="dataSource"
class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${driver}" />
<property name="url" value="${url}" />
<property name="username" value="${uName}" />
<property name="password" value="${password}" />
</bean>
<!-- 3、sqlSessionFactory -->
<bean id="sqlSessionFactory"
class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 别名 -->
<property name="typeAliasesPackage" value="entity"/>
<!-- mapper XML映射 -->
<property name="mapperLocations"
value="classpath*:mapper/*Mapper.xml"></property>
<!-- 数据源 -->
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--4、mapper接口的位置 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="mapper"></property>
</bean>
<!-- 1)、事务管理(增强/通知): -->
<bean id="txManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="transactionTemplate"
class="org.springframework.transaction.support.TransactionTemplate ">
<property name="transactionManager" ref="txManager"/>
</bean>
</beans>
1.1.2、生成Mapper接口的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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
">
<!-- 1、启动注解扫描-->
<context:component-scan base-package="change"/>
<!-- 1)目标 -->
<bean id="target" class="change.ChangeMoneyImpl_BC"/>
<!-- 2)代理对象实例 -->
<bean id="proxy_BC" class="proxy.Proxy_BC"/>
<!--3)代理 -->
<bean id="changeMoney" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces" value="change.ChangeMoney"/><!-- 注意这里是接口哦 -->
<!-- 1)注入目标对象 -->
<property name="target" ref="target"/>
<!-- 2)代理对象实例 -->
<property name="interceptorNames">
<array>
<value>proxy_BC</value>
</array>
</property>
</bean>
</beans>
1.1.3、ChangMoney接口及实现类:
接口:
public interface ChangeMoney {
boolean giveMoney(int on, int to, int money);
}
/**
*@author Nical
*/
@Component
public class ChangeMoneyImpl_BC implements ChangeMoney {
@Autowired
private UserinfoMapper mapper;
@Autowired
private TransactionTemplate transactionTemplate;
class Result{
boolean result;
}
@Override
public boolean giveMoney(int on, int to, int money) {
final Result result =new Result() ;
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
try {
giveMoneyOption(on, to, money);
System.out.println("=======事务提交了BC=====");
//事务回滚
result.result = true;
}catch (Exception e){
System.out.println("=======事务回滚了BC=====");
//事务回滚
transactionStatus.setRollbackOnly();
result.result = false;
}
}
});
return result.result;
}
public void giveMoneyOption(int on, int to, int money) throws Exception {
Userinfo userinfo =mapper .selectByPrimaryKey(on);
int i=0;
if (userinfo!=null){
//设置转钱人的余额
userinfo.setMoney(userinfo.getMoney()-money);
//受影响的行数
i = mapper.updateByPrimaryKey(userinfo);
}
//被转钱人的信息
Userinfo userinfo2 =mapper .selectByPrimaryKey(to);
int j=0;
if (userinfo2!=null){
//设置转钱人的余额
userinfo2.setMoney(userinfo2.getMoney()+money);
//受影响的行数
j = mapper.updateByPrimaryKey(userinfo2);
}
if (i>0&&j>0){
System.out.println("转账成功!!");
}else {
//回滚事务
System.out.println("转账失败!!");
throw new Exception("转账失败的异常");
}
}
}
1.1.4、 测试类代码:
/**
*@author Nical
*/
//编程式事务
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({
"classpath:beans_proxy_BC.xml","classpath:beans_BC.xml"})
//生成代理的 生成事务管理器(TransactionTemplate)的
public class Test_BC {
//编程式事务,自己通过aop实现事务管理器
@Autowired
@Qualifier("changeMoney")
private ChangeMoney changeMoney;
@Test
public void test2(){
boolean result = changeMoney.giveMoney(1, 3, 300);
System.out.println(result);
}
}
1.2、 总结:
我们发现,在进行事务的处理的时候,事务代码与我们的业务代码耦合了,而且非常的不方便,因为每次我要进行一个事务操作都需要写一遍业务代码,非常的麻烦,下面我们就来看看声明式事务,就很好的解决了上述的问题:
2、声明式事务
优点:事务 Management 脱离业务逻辑,并且不难配置
缺点:需要spring进行代理,生成代理对象(反射),性能稍差
应用场景:项目中大量需要事务管理的场景(企业开发中常用)
来我们直接上代码:
2.1、 测试代码:
2.1.1、生成事务管理的xml文件配置:
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"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
https://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd
">
<!--1、加载数据库的配置信息 -->
<context:property-placeholder
location="database.properties" />
<!--2、datasource数据源 -->
<bean id="dataSource"
class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${driver}" />
<property name="url" value="${url}" />
<property name="username" value="${uName}" />
<property name="password" value="${password}" />
</bean>
<!-- 3、sqlSessionFactory -->
<bean id="sqlSessionFactory"
class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 别名 -->
<property name="typeAliasesPackage" value="entity"/>
<!-- mapper XML映射 -->
<property name="mapperLocations"
value="classpath*:mapper/*Mapper.xml"></property>
<!-- 数据源 -->
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--4、mapper接口的位置 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="mapper"></property>
</bean>
<!-- 1)、事务管理(增强/通知): -->
<bean id="txManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 第1步:定义一个通知 advice -->
<tx:advice id="gmAdvice" transaction-manager="txManager">
<tx:attributes>
<!-- 这个方法才会使用事务管理器 -->
<tx:method name="giveMoney*"/>
<!-- 其他任何方法,使用只读事务
isolation="DEFAULT" 事务隔离级别
propagation="REQUIRED" 事务传播特性
timeout="-1" 事务的超时时间
no-rollback-for="" 指定某种运行时异常不回滚
rollback-for="" 指定某种运行时异常才回滚
-->
</tx:attributes>
</tx:advice>
<!-- 第2步:将通知植入切点
public void giveMoney(int a){}
public void change.ChangeMoneyImpl_SM.giveMoney(..)
-->
<aop:config>
<!-- 1)切点-->
<aop:pointcut id="pointCut" expression="execution(* change.ChangeMoneyImpl_SM.*(..))" />
<!-- 2)植入 :将通知植入到切点中-->
<aop:advisor advice-ref="gmAdvice" pointcut-ref="pointCut"/>
</aop:config>
2.1.2、生成Mapper接口的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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<!-- 1、启动注解扫描-->
<context:annotation-config/>
<context:component-scan base-package="change"/>
<!-- 1)目标 -->
<bean id="target_SM" class="change.ChangeMoneyImpl_SM"/>
<!-- 2)黑客 -->
<bean id="proxy_SM" class="proxy.Proxy_SM"/>
<!--3)代理 -->
<bean id="changeMoney_sm" class="org.springframework.aop.framework.ProxyFactoryBean">
<!-- 接口-->
<property name="proxyInterfaces" value="change.ChangeMoney"/>
<!-- 1)注入目标对象 -->
<property name="target" ref="target_SM"/>
<!-- 2)黑客对象 -->
<property name="interceptorNames">
<array>
<value>proxy_SM</value>
</array>
</property>
</bean>
</beans>
2.1.3、ChangMoney接口的实现类:
/**
*@author Nical
*/
@Component
public class ChangeMoneyImpl_SM implements ChangeMoney {
@Autowired
private UserinfoMapper mapper;
@Override
public boolean giveMoney(int on, int to, int money) {
boolean result=giveMoneyOption(on,to,money);
return result;
}
public boolean giveMoneyOption(int on, int to, int money) {
Userinfo userinfo =mapper .selectByPrimaryKey(on);
int i=0;
if (userinfo!=null){
//设置转钱人的余额
userinfo.setMoney(userinfo.getMoney()-money);
//受影响的行数
i = mapper.updateByPrimaryKey(userinfo);
}
//被转钱人的信息
Userinfo userinfo2 =mapper .selectByPrimaryKey(to);
int j=0;
if (userinfo2!=null){
//设置转钱人的余额
userinfo2.setMoney(userinfo2.getMoney()+money);
//受影响的行数
j = mapper.updateByPrimaryKey(userinfo2);
}
if (i>0&&j>0){
System.out.println("转账成功!!");
return true;
}else {
//回滚事务
System.out.println("转账失败!!");
throw new RuntimeException("转账失败的异常");
}
}
}
2.1.4 、测试类代码:
/**
*@author Nical
*/
//声明式事务
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({
"classpath:beans_proxy_SM.xml","classpath:beans_SM.xml"})
//生成代理的 生成事务管理器(TransactionTemplate)的
public class Test_SM {
@Autowired
@Qualifier("changeMoney_sm")
private ChangeMoney changeMoney;
@Test
public void test2(){
boolean result = changeMoney.giveMoney(1, 3, 300);
System.out.println(result);
}
}
2.2 总结:
我们发现,比较编程式少了代码的侵入性,同时也避免了代码的耦合,事务相关的代码可以分开写,但是还有没有更加简单的写法呢,有的!就是下面的注解声明事务:
3、注解声明式事务
优点:在上述的优点基础上,可以直接在需要的方法上加上注解,非常的方便
缺点:同上
应用场景:同上(企业中常用的方法)
来我们直接上代码:
3.1 、测试代码:
3.1.1、生成事务管理的xml文件配置:
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"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
https://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd
">
<!--1、加载数据库的配置信息 -->
<context:property-placeholder
location="database.properties" />
<!--2、datasource数据源 -->
<bean id="dataSource"
class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${driver}" />
<property name="url" value="${url}" />
<property name="username" value="${uName}" />
<property name="password" value="${password}" />
</bean>
<!-- 3、sqlSessionFactory -->
<bean id="sqlSessionFactory"
class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 别名 -->
<property name="typeAliasesPackage" value="entity"/>
<!-- mapper XML映射 -->
<property name="mapperLocations"
value="classpath*:mapper/*Mapper.xml"></property>
<!-- 数据源 -->
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--4、mapper接口的位置 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="mapper"></property>
</bean>
<!-- 1)、事务管理(增强/通知): -->
<bean id="txManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 声明式事务注解方式:第1步:开启注解事务
proxy-target-class="true" 指定注解事务是使用cglib动态代理方式来实现
-->
<tx:annotation-driven transaction-manager="txManager"/>
3.1.2、生成Mapper接口的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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<!-- 1、启动注解扫描-->
<context:annotation-config/>
<context:component-scan base-package="change"/>
<!-- 1)目标 -->
<bean id="target_ZJSM" class="change.ChangeMoneyImpl_ZJSM"/>
<!-- 2)代理实例 -->
<bean id="proxy_ZJSM" class="proxy.Proxy_ZJSM"/>
<!--3)代理 -->
<bean id="changeMoney_zjsm" class="org.springframework.aop.framework.ProxyFactoryBean">
<!-- 接口-->
<property name="proxyInterfaces" value="change.ChangeMoney"/>
<!-- 1)注入目标对象 -->
<property name="target" ref="target_ZJSM"/>
<!-- 2)代理实例 -->
<property name="interceptorNames">
<array>
<value>proxy_ZJSM</value>
</array>
</property>
</bean>
</beans>
3.1.3、ChangMoney接口的实现类:
/**
*@author Nical
*/
@Component
public class ChangeMoneyImpl_ZJSM implements ChangeMoney {
@Autowired
private UserinfoMapper mapper;
@Override
@Transactional
public boolean giveMoney(int on, int to, int money) {
boolean result=giveMoneyOption(on,to,money);
return result;
}
public boolean giveMoneyOption(int on, int to, int money) {
Userinfo userinfo =mapper .selectByPrimaryKey(on);
int i=0;
if (userinfo!=null){
//设置转钱人的余额
userinfo.setMoney(userinfo.getMoney()-money);
//受影响的行数
i = mapper.updateByPrimaryKey(userinfo);
}
//被转钱人的信息
Userinfo userinfo2 =mapper .selectByPrimaryKey(to);
int j=0;
if (userinfo2!=null){
//设置转钱人的余额
userinfo2.setMoney(userinfo2.getMoney()+money);
//受影响的行数
j = mapper.updateByPrimaryKey(userinfo2);
}
if (i>0&&j>0){
System.out.println("转账成功!!");
return true;
}else {
//回滚事务
System.out.println("转账失败!!");
throw new RuntimeException("转账失败的异常");
}
}
}
2.1.4 、 测试类代码:
/**
*@author Nical
*/
//注解声明式事务
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({
"classpath:beans_proxy_ZJSM.xml", "classpath:beans_ZJSM.xml"})
//生成代理的 生成事务管理器(TransactionTemplate)的
public class Test_ZJSM {
//编程式事务,自己通过aop实现事务管理器
@Autowired
@Qualifier("changeMoney_zjsm")
private ChangeMoney changeMoney;
@Test
public void test2(){
boolean result = changeMoney.giveMoney(1, 3, 300);
System.out.println(result);
}
}
3.2、 总结:
是不是相比较于前两种,注解的方法特别的爽,所以强烈建议掌握该种事务管理的方法,下面还介绍一种另外的可以处理事务管理的方法,AspectJ和JAVA配置我们的事务管理
4、AspectJ面向切面,注解事务
4.1、介绍
AspectJ是一个面向切面的框架,它扩展了Java语言。AspectJ定义了AOP语法,它有一个专门的编译器用来生成遵守Java字节编码规范的Class文件。
4.2、 测试代码:
4.2.1、 AspectJ代码:
/*
* 日志通知(连接点(切点)+增强)
* @author Nical
*/
@Aspect
@Component
public class LogAspect {
// 1.定义一个切点
@Pointcut("execution(* change.Impls.ChangeMoneyImpl_Aspect.*(..) )")
public void pointCut() {
}
//2.前置通知
@Before("pointCut() ")
public void beforeAdvice(JoinPoint joinPoint) {
System.out.println("=====我是前置通知=====>"+joinPoint);
}
//3.@After在调用目标方法之后切入;切入点表达式(指定在哪个方法切入)
@After("pointCut() ")
public void afterAdvice(JoinPoint joinPoint) {
System.out.println("=====我是后置通知=====>"+joinPoint);
}
//4.环绕通知/增强(黑客)
//@Around("com.cc.dao.impl.UserDaoImpl2.add(..)")
@Around("pointCut()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("1.鉴权");
//调用目标方法
Object result = joinPoint.proceed();
System.out.println("1.日志留痕==》"+result);
return result;
}
//5.JoinPoint一定要出现在参数表的第一位
@AfterReturning(value="pointCut()",returning="result")
public Object logReturn(JoinPoint joinPoint, Object result){
System.out.println(""+joinPoint.getSignature().getName()+"正常返回。。。@AfterReturning:运行结果:{"+result+"}");
return result;
}
//6.异常通知
@AfterThrowing(value="pointCut()",throwing="exception")
public void logException(JoinPoint joinPoint, Exception exception){
System.out.println(""+joinPoint.getSignature().getName()+"异常。。。异常信息:{"+exception+"}");
}
}
4.2.2、 JAVA 注解配置的Bean工厂代码:
/*
* @author Nical
*/
@Configuration
@ComponentScan(value= {
"aspect","change.Impls"})
@EnableAspectJAutoProxy//启动aspectJ注解aop
@EnableTransactionManagement//启动事务管理
public class AspectJConfig {
//1.datasource
@Bean
public BasicDataSource getBasicDataSource() {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setUrl("jdbc:mysql://localhost:3306/test?useUnicode=true&&characterEncoding=utf-8");
dataSource.setUsername("root");
dataSource.setPassword("123456");
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
return dataSource;
}
//2.sqlSessionFactory
@Bean
public SqlSessionFactory getSessionFactoryBean() throws Exception {
SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean();
sessionFactoryBean.setDataSource(getBasicDataSource());
Resource[] resources = {
new ClassPathResource("mapper/UserinfoMapper.xml")};
sessionFactoryBean.setMapperLocations(resources );
return sessionFactoryBean.getObject();
}
//3.Mapper
@Bean
public UserinfoMapper userMapper() throws Exception {
// when using javaconfig a template requires less lines than a MapperFactoryBean
SqlSessionTemplate sqlSessionTemplate = new SqlSessionTemplate(getSessionFactoryBean());
return sqlSessionTemplate.getMapper(UserinfoMapper.class);
}
//4、事务 DataSourceTransactionManager
@Bean(name = "dataSourceTransactionManager")
public DataSourceTransactionManager getTransactionManager() {
DataSourceTransactionManager txManager = new DataSourceTransactionManager();
txManager.setDataSource(getBasicDataSource());
return txManager;
}
}
4.2.3、 接口的实现类:
/*
* @author Nical
*/
@Component
public class ChangeMoneyImpl_Aspect implements ChangeMoney {
@Autowired
private UserinfoMapper mapper;
@Transactional
@Override
public boolean giveMoney(int on, int to, int money) {
boolean result=giveMoneyOption(on,to,money);
return result;
}
public boolean giveMoneyOption(int on, int to, int money) {
Userinfo userinfo =mapper .selectByPrimaryKey(on);
int i=0;
if (userinfo!=null){
//设置转钱人的余额
userinfo.setMoney(userinfo.getMoney()-money);
//受影响的行数
i = mapper.updateByPrimaryKey(userinfo);
}
//被转钱人的信息
Userinfo userinfo2 =mapper .selectByPrimaryKey(to);
int j=0;
if (userinfo2!=null){
//设置转钱人的余额
userinfo2.setMoney(userinfo2.getMoney()+money);
//受影响的行数
j = mapper.updateByPrimaryKey(userinfo2);
}
if (i>0&&j>0){
System.out.println("转账成功!!");
return true;
}else {
//回滚事务
System.out.println("转账失败!!");
throw new RuntimeException("转账失败的异常");
}
}
}
4.2.4、 测试代码:
/*
* @author Nical
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = AspectJConfig.class)
public class AspectJTest {
@Autowired
ChangeMoney changeMoney;
@Test
public void Test1(){
changeMoney.giveMoney(1,2,300);
}
}
5、 总结:
-
以上方法中:编程式事务切点显而易见,麻烦,需要在业务代码中进行事务相关的代码拼接,代码重用性差,而且非常的费时间,声明式事务解决了代码耦合的问题,但是同时也要写相应的代码,而注解式事务则完美的解决了上述的问题,同时呢,AspectJ和JAVA注解可以完全不用写Xml文件,也值得推荐,小伙伴使用的时候注意区分哦
-
本篇文章中的数据库对象及mapper文件都是由逆向工程生成,如果有不清楚的同学请参考
https://blog.csdn.net/m0_50217781/article/details/111463605 -
欢迎小伙伴留言,评论,一起探讨相关的问题,博主看到会第一时间与您回复哦