Spring 使用Druid数据源 整合 Mybatis
AOP技术应用实现
1) 创建事务管理类工具,即手动开启事务,手动提交事务,手动回滚事务的方法
package com.roger.core.utils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Component;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;
@Component
@Scope("prototype")//设置成原型状态,避免线程安全问题
public class TransactionUtil {
private TransactionStatus transactionStatus = null;
@Autowired
private DataSourceTransactionManager transactionManager;
public void begin(){
System.out.println("方法上有事务注解,使用手动的方式开启事务...");
transactionStatus = transactionManager.getTransaction(new DefaultTransactionDefinition());
}
public void commit(){
if(transactionStatus != null){
System.out.println("提交事务...");
transactionManager.commit(transactionStatus);
}
}
public void rollback(){
if(transactionStatus != null) {
System.out.println("回滚事务...");
transactionManager.rollback(transactionStatus);
}
}
}
2) 创建编程式事务管理的切面类
package com.roger.core.aspect;
import com.roger.core.utils.TransactionUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
//一定要把切面交给Spring管理
//在测试声明式事务的时候,需要从Spring的容器中收回编程式事务的切面
//@Component
@Aspect
public class ProgramTransactionAspect {
@Autowired(required = false)
private TransactionUtil transactionUtil;
@Pointcut("execution(* com.roger.biz.service.impl..*.*(..))")
public void addTransaction(){
}
//异常通知:给添加事务的方法回滚事务,当方法抛出异常时
@AfterThrowing("addTransaction()")
public void rollbackTransaction(){
//获取当前事务,然后回滚
transactionUtil.rollback();
}
//环绕通知:给需要添加事务的方法,手动开启事务和提交事务
@Around("addTransaction()")
public void around(ProceedingJoinPoint joinPoint) throws Throwable{
transactionUtil.begin();
joinPoint.proceed();
transactionUtil.commit();
}
}
3).创建测试接口以及测试接口实现类
package com.roger.biz.service;
import com.roger.core.model.User;
public interface UserService {
void save(User user);
}
package com.roger.biz.service.impl;
import com.roger.biz.dao.UserDao;
import com.roger.biz.service.UserService;
import com.roger.core.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class UserServiceImpl implements UserService {
@Autowired(required = false)
private UserDao userDao;
@Override
public void save(User user) {
userDao.insert(user);
//利用最简单的构造异常来验证事务的回滚操作
//通过回滚操作来和事务提交作对比
// int i = 1 / 0 ;
}
}
4.创建junit4测试类 --测试基类
package com.roger;
import com.roger.core.config.DataSourceConfig;
import com.roger.core.config.SpringConfig;
import com.roger.core.config.mybatis.SqlSessionConfig;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {DataSourceConfig.class, SqlSessionConfig.class,SpringConfig.class})
public class SpringBaseTestSuit {
}
5.具体测试接口的junit4测试类
package com.roger.biz.service.impl;
import com.roger.SpringBaseTestSuit;
import com.roger.biz.service.UserService;
import com.roger.core.model.User;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import static org.junit.Assert.*;
public class UserServiceImplTest extends SpringBaseTestSuit {
@Autowired(required = false)
private UserService userService;
@Test
public void save() {
User user = new User();
user.setUserName("Jackson");
user.setAge(38);
user.setPhone("15498756489");
userService.save(user);
}
}
6.通过观察数据库操作表的记录来观察结果,这里没有写太多的测试方法,来直接用Junit验证测试结果
package com.roger.core.annotaion;
import java.lang.annotation.*;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CustomTransactional {
String value() default "";
}
package com.roger.core.aspect;
import com.roger.core.annotaion.CustomTransactional;
import com.roger.core.utils.TransactionUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
在测试编程式事务的时候,需要从Spring的容器中收回声明式事务的切面
@Component//一定要把切面交给Spring管理
@Aspect
public class DeclareTransactionAspect {
@Autowired(required = false)
private TransactionUtil transactionUtil;
@Pointcut("execution(* com.roger.biz.service.impl..*.*(..))")
public void addTransaction() {
}
//异常通知:给添加事务的方法回滚事务,当方法抛出异常时
@AfterThrowing("addTransaction()")
public void rollbackTransaction() {
transactionUtil.rollback();
}
//环绕通知:给需要添加事务的方法,手动开启事务和提交事务
@Around("addTransaction()")
public void around(ProceedingJoinPoint joinPoint) throws Throwable {
Class> targetCls = joinPoint.getTarget().getClass();
//获取即将要执行方法
Method method = getInvokedMethod(targetCls, joinPoint);
if (method == null) {
joinPoint.proceed();
return;
}
//判断执行方法是否有事务注解
Annotation customTransAnno = method.getAnnotation(CustomTransactional.class);
if (customTransAnno == null) {
System.out.println("方法上没有事务注解,直接开始执行方法...");
joinPoint.proceed();
return;
}
transactionUtil.begin();
joinPoint.proceed();
transactionUtil.commit();
}
private Method getInvokedMethod(Class targetCls, ProceedingJoinPoint pJoinPoint) {
List> clazzList = new ArrayList<>();
Object[] args = pJoinPoint.getArgs();
for (Object arg : args) {
clazzList.add(arg.getClass());
}
Class[] argsCls = (Class[]) clazzList.toArray(new Class[0]);
String methodName = pJoinPoint.getSignature().getName();
Method method = null;
try {
method = targetCls.getMethod(methodName, argsCls);
} catch (NoSuchMethodException e) {
//不做任何处理,这个切面只处理事务相关逻辑
//其他任何异常不在这个切面的考虑范围
}
return method;
}
}