概述
AspectJ 主要是使用 XML 配置顾问方式自动为每个符合切入点表达式的类生成事务代理。创建测试操作步骤如下:
创建测试项目
创建一个名为 aspectj-aop 项目,pom.xml
文件如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 <?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 > hello-spring-transaction</groupId > <artifactId > aspectj-aop</artifactId > <version > 1.0.0-SNAPSHOT</version > <packaging > jar</packaging > <properties > <project.build.sourceEncoding > UTF-8</project.build.sourceEncoding > <project.reporting.outputEncoding > UTF-8</project.reporting.outputEncoding > <java.version > 1.8</java.version > <log4j.version > 1.2.17</log4j.version > <slf4j.version > 1.7.25</slf4j.version > <spring.version > 4.3.17.RELEASE</spring.version > <alibaba-druid.version > 1.1.6</alibaba-druid.version > <mysql.version > 5.1.46</mysql.version > <mybatis.version > 3.2.8</mybatis.version > <mybaits-spring.version > 1.3.1</mybaits-spring.version > <junit.version > 4.12</junit.version > <lombok.version > 1.16.18</lombok.version > </properties > <dependencies > <dependency > <groupId > org.springframework</groupId > <artifactId > spring-test</artifactId > <version > ${spring.version}</version > </dependency > <dependency > <groupId > junit</groupId > <artifactId > junit</artifactId > <version > ${junit.version}</version > </dependency > <dependency > <groupId > org.springframework</groupId > <artifactId > spring-context</artifactId > <version > ${spring.version}</version > </dependency > <dependency > <groupId > org.springframework</groupId > <artifactId > spring-aspects</artifactId > <version > ${spring.version}</version > </dependency > <dependency > <groupId > org.slf4j</groupId > <artifactId > slf4j-api</artifactId > <version > ${slf4j.version}</version > </dependency > <dependency > <groupId > org.slf4j</groupId > <artifactId > slf4j-log4j12</artifactId > <version > ${slf4j.version}</version > </dependency > <dependency > <groupId > org.slf4j</groupId > <artifactId > jcl-over-slf4j</artifactId > <version > ${slf4j.version}</version > </dependency > <dependency > <groupId > org.slf4j</groupId > <artifactId > jul-to-slf4j</artifactId > <version > ${slf4j.version}</version > </dependency > <dependency > <groupId > log4j</groupId > <artifactId > log4j</artifactId > <version > ${log4j.version}</version > </dependency > <dependency > <groupId > com.alibaba</groupId > <artifactId > druid</artifactId > <version > ${alibaba-druid.version}</version > </dependency > <dependency > <groupId > mysql</groupId > <artifactId > mysql-connector-java</artifactId > <version > ${mysql.version}</version > </dependency > <dependency > <groupId > org.mybatis</groupId > <artifactId > mybatis</artifactId > <version > ${mybatis.version}</version > </dependency > <dependency > <groupId > org.mybatis</groupId > <artifactId > mybatis-spring</artifactId > <version > ${mybaits-spring.version}</version > </dependency > <dependency > <groupId > org.springframework</groupId > <artifactId > spring-jdbc</artifactId > <version > ${spring.version}</version > </dependency > <dependency > <groupId > org.projectlombok</groupId > <artifactId > lombok</artifactId > <version > ${lombok.version}</version > </dependency > </dependencies > </project >
主要依赖: org.springframework:spring-aspects
创建实体类
TbContentCategory
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 package com.hello.spring.transaction.aspectsj.aop.domain;import lombok.Data;import java.util.Date; * 分类管理 * <p>Title: TbContentCategory</p> * <p>Description: </p> * * @author Lusifer * @version 1.0 .0 * @date 2018 /6 /25 9 :14 */ @Data public class TbContentCategory { private Long id; private String name; private Integer status; private Integer sortOrder; private Boolean isParent; private Date created; private Date updated; private TbContentCategory parent; }
TbContent
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 package com.hello.spring.transaction.aspectsj.aop.domain;import lombok.Data;import java.util.Date; * 内容管理 * <p>Title: TbContent</p> * <p>Description: </p> * * @author Lusifer * @version 1.0 .0 * @date 2018 /6 /25 14 :02 */ @Data public class TbContent { private Long id; private String title; private String subTitle; private String titleDesc; private String url; private String pic; private String pic2; private String content; private Date created; private Date updated; private TbContentCategory tbContentCategory; }
创建数据访问层
TbContentCategoryDao
1 2 3 4 5 6 7 8 9 package com.hello.spring.transaction.aspectsj.aop.dao;import com.hello.spring.transaction.aspectsj.aop.domain.TbContentCategory;import org.springframework.stereotype.Repository;@Repository public interface TbContentCategoryDao { void insert (TbContentCategory tbContentCategory) ; }
TbContentDao
1 2 3 4 5 6 7 8 9 package com.hello.spring.transaction.aspectsj.aop.dao;import com.hello.spring.transaction.aspectsj.aop.domain.TbContent;import org.springframework.stereotype.Repository;@Repository public interface TbContentDao { void insert (TbContent tbContent) ; }
创建业务逻辑层
TbContentCategoryService接口
1 2 3 4 5 6 7 8 package com.hello.spring.transaction.aspectsj.aop.service;import com.hello.spring.transaction.aspectsj.aop.domain.TbContent;import com.hello.spring.transaction.aspectsj.aop.domain.TbContentCategory;public interface TbContentCategoryService { void save (TbContentCategory tbContentCategory, TbContent tbContent) ; }
实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 package com.hello.spring.transaction.aspectsj.aop.service.impl;import com.hello.spring.transaction.aspectsj.aop.dao.TbContentCategoryDao;import com.hello.spring.transaction.aspectsj.aop.domain.TbContent;import com.hello.spring.transaction.aspectsj.aop.domain.TbContentCategory;import com.hello.spring.transaction.aspectsj.aop.service.TbContentCategoryService;import com.hello.spring.transaction.aspectsj.aop.service.TbContentService;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;@Service public class TbContentCategoryServiceImpl implements TbContentCategoryService { @Autowired private TbContentCategoryDao tbContentCategoryDao; @Autowired private TbContentService tbContentService; public void save (TbContentCategory tbContentCategory, TbContent tbContent) { tbContentCategoryDao.insert(tbContentCategory); tbContentService.save(tbContent); } }
TbContentService接口
1 2 3 4 5 6 7 package com.hello.spring.transaction.aspectsj.aop.service;import com.hello.spring.transaction.aspectsj.aop.domain.TbContent;public interface TbContentService { void save (TbContent tbContent) ; }
实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 package com.hello.spring.transaction.aspectsj.aop.service.impl;import com.hello.spring.transaction.aspectsj.aop.dao.TbContentDao;import com.hello.spring.transaction.aspectsj.aop.domain.TbContent;import com.hello.spring.transaction.aspectsj.aop.service.TbContentService;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;@Service public class TbContentServiceImpl implements TbContentService { @Autowired private TbContentDao tbContentDao; public void save (TbContent tbContent) { tbContentDao.insert(tbContent); } }
创建 Spring 配置
spring-context.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 <?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:tx="http://www.springframework.org/schema/tx" 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/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <context:annotation-config /> <context:component-scan base-package ="com.hello.spring.transaction.aspectsj.aop" > <context:exclude-filter type ="annotation" expression ="org.springframework.stereotype.Controller" /> </context:component-scan > <bean id ="transactionManager" class ="org.springframework.jdbc.datasource.DataSourceTransactionManager" > <property name ="dataSource" ref ="dataSource" /> </bean > <tx:advice id ="myAdvice" transaction-manager ="transactionManager" > <tx:attributes > <tx:method name ="save*" propagation ="REQUIRED" /> </tx:attributes > </tx:advice > <aop:config > <aop:pointcut id ="myPointcut" expression ="execution(* com.hello.spring.transaction.aspectsj.aop.service.*.*(..))" /> <aop:advisor advice-ref ="myAdvice" pointcut-ref ="myPointcut" /> </aop:config > </beans >
spring-context-druid.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 <?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 http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <context:property-placeholder ignore-unresolvable ="true" location ="classpath:jdbc.properties" /> <bean id ="dataSource" class ="com.alibaba.druid.pool.DruidDataSource" init-method ="init" destroy-method ="close" > <property name ="driverClassName" value ="${jdbc.driverClass}" /> <property name ="url" value ="${jdbc.connectionURL}" /> <property name ="username" value ="${jdbc.username}" /> <property name ="password" value ="${jdbc.password}" /> <property name ="initialSize" value ="${jdbc.pool.init}" /> <property name ="minIdle" value ="${jdbc.pool.minIdle}" /> <property name ="maxActive" value ="${jdbc.pool.maxActive}" /> <property name ="maxWait" value ="60000" /> <property name ="timeBetweenEvictionRunsMillis" value ="60000" /> <property name ="minEvictableIdleTimeMillis" value ="300000" /> <property name ="validationQuery" value ="${jdbc.testSql}" /> <property name ="testWhileIdle" value ="true" /> <property name ="testOnBorrow" value ="false" /> <property name ="testOnReturn" value ="false" /> <property name ="filters" value ="stat" /> </bean > </beans >
spring-context-mybatis.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 <?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 http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <bean id ="sqlSessionFactory" class ="org.mybatis.spring.SqlSessionFactoryBean" > <property name ="dataSource" ref ="dataSource" /> <property name ="typeAliasesPackage" value ="com.hello.spring.transaction.aspectsj.aop.domain" /> <property name ="mapperLocations" value ="classpath:/mapper/**/*.xml" /> <property name ="configLocation" value ="classpath:/mybatis-config.xml" > </property > </bean > <bean class ="org.mybatis.spring.mapper.MapperScannerConfigurer" > <property name ="basePackage" value ="com.hello.spring.transaction.aspectsj.aop.dao" /> </bean > </beans >
创建 MyBatis 配置和映射文件
mybatis-config.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd" > <configuration > <settings > <setting name ="logImpl" value ="STDOUT_LOGGING" /> <setting name ="cacheEnabled" value ="false" /> <setting name ="lazyLoadingEnabled" value ="true" /> <setting name ="aggressiveLazyLoading" value ="true" /> <setting name ="multipleResultSetsEnabled" value ="true" /> <setting name ="useColumnLabel" value ="true" /> <setting name ="useGeneratedKeys" value ="false" /> <setting name ="autoMappingBehavior" value ="PARTIAL" /> <setting name ="defaultExecutorType" value ="SIMPLE" /> <setting name ="mapUnderscoreToCamelCase" value ="true" /> <setting name ="localCacheScope" value ="SESSION" /> <setting name ="jdbcTypeForNull" value ="NULL" /> </settings > </configuration >
TbContentCategoryMapper.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > <mapper namespace ="com.hello.spring.transaction.aspectsj.aop.dao.TbContentCategoryDao" > <insert id ="insert" > INSERT INTO tb_content_category ( `parent_id`, `name`, `status`, `sort_order`, `is_parent`, `created`, `updated` ) VALUES ( #{parent.id}, #{name}, #{status}, #{sortOrder}, #{isParent}, #{created}, #{updated} ); </insert > </mapper >
TbContentMapper.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > <mapper namespace ="com.hello.spring.transaction.aspectsj.aop.dao.TbContentDao" > <insert id ="insert" > INSERT INTO tb_content ( `category_id`, `title`, `sub_title`, `title_desc`, `url`, `pic`, `pic2`, `content`, `created`, `updated` ) VALUES ( #{tbContentCategory.id}, #{title}, #{subTitle}, #{titleDesc}, #{url}, #{pic}, #{pic2}, #{content}, #{created}, #{updated} ) </insert > </mapper >
创建系统配置文件
log4j.properties
1 2 3 4 5 6 7 8 9 10 11 12 log4j.rootLogger =INFO, console, file log4j.appender.console =org.apache.log4j.ConsoleAppender log4j.appender.console.layout =org.apache.log4j.PatternLayout log4j.appender.console.layout.ConversionPattern =%d %p [%c] - %m%n log4j.appender.file =org.apache.log4j.DailyRollingFileAppender log4j.appender.file.File =logs/log.log log4j.appender.file.layout =org.apache.log4j.PatternLayout log4j.appender.A3.MaxFileSize =1024KB log4j.appender.A3.MaxBackupIndex =10 log4j.appender.file.layout.ConversionPattern =%d %p [%c] - %m%n
jdbc.properties
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 jdbc.driverClass =com.mysql.jdbc.Driver jdbc.connectionURL =jdbc:mysql://192.168.75.134:3306/myshop?useUnicode=true&characterEncoding=utf-8&useSSL=false jdbc.username =root jdbc.password =123456 jdbc.pool.init =1 jdbc.pool.minIdle =3 jdbc.pool.maxActive =20 jdbc.testSql =SELECT 'x' FROM DUAL
创建测试类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 package com.hello.spring.transaction.aspectsj.aop.service.test;import com.hello.spring.transaction.aspectsj.aop.domain.TbContent;import com.hello.spring.transaction.aspectsj.aop.domain.TbContentCategory;import com.hello.spring.transaction.aspectsj.aop.service.TbContentCategoryService;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:spring-context.xml", "classpath:spring-context-druid.xml", "classpath:spring-context-mybatis.xml"}) public class TestSpringTransaction { @Autowired private TbContentCategoryService tbContentCategoryService; @Test public void test () { TbContentCategory tbContentCategory = new TbContentCategory(); tbContentCategory.setId(1L ); tbContentCategory.setName("测试事务分类" ); TbContent tbContent = new TbContent(); tbContent.setTbContentCategory(tbContentCategory); tbContent.setTitle("测试事务内容" ); tbContentCategoryService.save(tbContentCategory, tbContent); } }
运行观察事务效果:
有事务:数据插入成功则两张表都存在数据,只要出现异常则两张表都没有数据
无事务:如果第一张表数据插入成功,但第二张表报错则第一张表的数据不会回滚
If you like this blog or find it useful for you, you are welcome to comment on it. You are also welcome to share this blog, so that more people can participate in it. If the images used in the blog infringe your copyright, please contact the author to delete them. Thank you !