什么是Spring
Spring简介
Spring框架是个轻量级的Java EE框架。所谓轻量级,是指不依赖于容器就能运行的。Struts、Hibernate也是轻量级的。
轻量级框架是相对于重量级框架而言的,重量级框架必须依赖特定的容器
Spring以IoC、AOP为主要思想,其中IoC,Inversion of Control 指控制反转或反向控制。在Spring框架中我们通过配置创建类对象,由Spring在运行阶段实例化、组装对象。AOP,Aspect Oriented Programming,面向切面编程,其思想是在执行某些代码前执行另外的代码,使程序更灵活、扩展性更好,可以随便地添加、删除某些功能。Servlet中的Filter便是一种AOP思想的实现。
Spring同时也是一个“一站式”框架,即Spring在JavaEE的三层架构[表现层(Controller层)、业务逻辑层(Service层)、数据访问层(DAO层)]中,每一层均提供了不同的解决技术
spring三层
- 表现层(Controller层):Spring MVC
- 业务逻辑层(Service层):Spring的IoC
- 数据访问层(DAO层):支持mybaits,hibernate,封装jdbc
Spring 的优势
- 低侵入 / 低耦合 (降低组件之间的耦合度,实现软件各层之间的解耦)
- 声明式事务管理(基于切面和惯例)
- 方便集成其他框架(如MyBatis、Hibernate)
- 降低 Java 开发难度
- Spring 框架中包括了 J2EE 三层的每一层的解决方案
spring的核心
- IOC:(
Inverse of Control 控制反转
):将对象的创建权,交由Spring完成- DI:依赖注入:依赖注入可以说是控制反转的一个具体实现例子,其在Spring中的体现在于组件之间的依赖关系由容器控制,我们通过简单的配置,不通过代码就可以得到指定的资源。
- AOP :
Aspect Oriented Programming
是 面向对象的功能延伸.不是替换面向对象,是用来解决OO中一些问题
spring IoC
控制反转 ,也叫依赖注入,是面向对象编程中的一种设计理念,用来降低程序代码之间的耦合度。将创建对象的权力交给容器。
使用的步骤
1. 通过maven导入spring核心jar
<!--spring start-->
<!-- spring-beans -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>5.1.9.RELEASE</version>
</dependency>
<!--spring-core -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.1.9.RELEASE</version>
</dependency>
<!-- spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.9.RELEASE</version>
</dependency>
<!-- spring-expression -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>5.1.9.RELEASE</version>
</dependency>
<!-- commons-logging -->
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
<!--spring end-->
2. 创建配置文件 spring-config.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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 定义第一个Bean实例:bean1 -->
<bean id="..." class="...">
</bean>
</beans>
-
spring-config.xml的元素
-
beans:
beans
元素是Spring配置文件的根元素 -
bean:
bean
元素是Spring配置文件的beans
元素的子元素,beans
元素可以包含多个bean
子元素,每个bean
元素相当于定义了一个实例,相当于容器创建了一个对象;定义bean
时通常需要指定两个属性- id:确定该Bean的唯一标识符,容器对Bean管理、访问、以及该Bean的依赖关系,都通过该属性完成。 Bean的id属性在Spring容器中是唯一的。
- class:指定该Bean的具体实现类。注意这里不能使接口。通常情况下,Spring会直接使用new关键字创建该Bean的实例,因此,这里必须提供Bean实现类的类名。
-
-
创建一个bean
-
创建一个bean类
package cn.pojo; import java.io.Serializable; import java.util.Date; public class News implements Serializable{ private Integer id;//ID private String title;//标题 private String content;//内容 private Date createTime;//创建时间 public News() {} public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } public Date getCreateTime() { return createTime; } public void setCreateTime(Date createTime) { this.createTime = createTime; } }
-
配置spring-config.xml文件
- 当我们在配置文件中通过方法配置一个Bean时,这样就需要该Bean实现类中必须有一个无参构造器。
<?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 https://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="news" class="cn.pojo.News"></bean> </beans>
- 在配置的时候我们还可以给这个Bean类中的属性赋值,通过
bean
的子元素property
实现spring中的setter注入方式
<bean id="news" class="cn.pojo.News"> <!-- 给名字为id的属性赋值 1 --> <!--(将nama中的值的前面加上set,然后将首字母变为大写 变成setId,从而找到id的set方法来给id赋值) --> <property name="id" value="1"/> <!-- 可通过ref 引入其余的bean 给对象属性赋值 --> <property name="属性名" ref="bean"/> </bean>
多种方式实现依赖注入
-
构造注入:
使用构造函数注入:添加构造函数(前提是这个构造函数存在)
//在News类中添加id的构造函数 public News(Integer id) { this.id = id; }
<!-- 使用构造函数配置 --> <bean id="news" class="cn.pojo.News"> <!-- 给构造函数的第一个参数赋值 1 --> <constructor-arg><value>345</value></constructor-arg> <!-- 也可以是通过index指定给构造函数的第几个参数赋值 1 --> <constructor-arg index='1'><value>345</value></constructor-arg> </bean>
给构造函数的参数赋值的顺序是根据前后顺序来的,也可通过参数index指定
-
p命名空间注入
先配置xml文件的beans的属性
<!-- 加在beans元素上 --> xmlns:p="http://www.springframework.org/schema/p"
<bean id="news" class="cn.pojo.News" p:id='1'></bean>
-
注入特殊符号
使用<![CDATA[值]]>:将值里的特殊字符转换成纯文字
-
3. 测试
public class TestNews {
@Test
public void test01()
{
//1.获取spring配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
//2.由配置文件返回对象,使用getBean方法指定id获取
News news = (News)context.getBean("news");
System.out.println(news.getId());
}
}
通过注解实现IoC的配置
1. 在Bean类上定义注解
package cn.biz.impl;
import cn.biz.OrderBiz;
import cn.mapper.order.OrderDetailMapper;
import cn.mapper.order.OrderMapper;
import cn.pojo.Order;
import cn.pojo.OrderDetail;
import com.github.pagehelper.PageHelper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@Service("orderBiz")
public class OrderBizImpl implements OrderBiz {
@Autowired
private OrderMapper orderMapper;
@Autowired
private OrderDetailMapper orderDetailMapper;
@Override
public Integer add(Order order, OrderDetail orderDetail) throws Exception {
orderMapper.add(order);
orderDetail.setOrderId(order.getId());
return orderDetailMapper.add(orderDetail);
}
public OrderMapper getOrderMapper() {
return orderMapper;
}
public void setOrderMapper(OrderMapper orderMapper) {
this.orderMapper = orderMapper;
}
}
@Component是定义任意层的注解
而Spring提供了三个特殊的注解
- @Repository:用于标注Dao类
- @Service:用于标注业务类
- @Controller:用于标注控制器类
使用这些注解来定义,将相当于在spring中定义了一个
<bean id="orderController" class="cn.Controller.OrderController"></bean>
注解后面的括号是用于指定bean的id
2. 配置spring-config.xml,扫描这些注解
-
首先将添加beans的context
-
定义扫描注解的范围
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 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"> <!-- 指定扫描的范围 --> <context:component-scan base-package="cn.biz,cn.aop,cn.controller"/> </beans>
3. 使用注解实现Bean组件的装配
-
spring注解完成装配
spring提供了@Autowired注解实现Bean的装配
若容器中有一个以上的类型相匹配的Bean时,则可以使用 @Qualifier()指定所需要的Bean名称package cn.controller; import cn.biz.OrderBiz; import cn.pojo.Order; import cn.pojo.OrderDetail; import org.omg.CORBA.INTERNAL; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import java.util.List; /** * 作者:weisen * 日期:2019/9/27 19:24 */ @Controller("orderController") public class OrderController { @Autowired @Qualifier("orderBiz") private OrderBiz orderBiz; public List<Order> getOrderList(Integer userId){ return orderBiz.getOrderList(userId); } }
-
使用Java标准注解完成装配
@Resource(name = “”)
@Resource的name属性,默认情况下,Spring将这个属性的值解释为要注入的Bean的名称package cn.controller; import cn.biz.OrderBiz; import cn.pojo.Order; import cn.pojo.OrderDetail; import org.omg.CORBA.INTERNAL; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import java.util.List; /** * 作者:weisen * 日期:2019/9/27 19:24 */ @Controller("orderController") public class OrderController { @Resource(name = "orderBiz") private OrderBiz orderBiz; public List<Order> getOrderList(Integer userId){ return orderBiz.getOrderList(userId); } }
4. 测试
public class Test {
@Test
public void test01()
{
//1.获取spring配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
//2.由配置文件返回对象,使用getBean方法指定id获取
OrderController news = (OrderController)context.getBean("orderController");
}
}
Spring AOP
什么是AOP
AOP 即 Aspect Oriented Program 面向切面编程 是一种面向切面编程的编程思路 但是spring AOP只是AOP的一种简化版
spring AOP 的目的
将那些与业务无关,却为业务模块所共同调用的逻辑或责任(例如事务处理、日志管理、权限控制等)封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可拓展性和可维护性。
spring AOP 当中的概念:
- 切面(Aspect)
切面 = 切入点 + 通知,通俗点就是:在什么时机,什么地方,做什么增强! - 连接点(Join Point):程序执行中的某个具体的执行点。
- 增强处理(Advice):切面在某个特定的连接点上执行的代码逻辑。
- 切入点(Pointcut)
在哪些类,哪些方法上切入(where) - 织入(Weaving)
把切面加入到对象,并创建出代理对象的过程。(由 Spring 来完成)
使用spring AOP的步骤
1. 导入jar
<!--spring-aop start-->
<!--aspectj weaver-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</version>
</dependency>
<!-- spring-aop -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.1.9.RELEASE</version>
</dependency>
<!--aopalliance -->
<dependency>
<groupId>aopalliance</groupId>
<artifactId>aopalliance</artifactId>
<version>1.0</version>
</dependency>
<!--spring-aop end-->
2.定义切面
创建类定义切面
public class beforeLogger {
private Logger log = Logger.getLogger(beforeLogger.class);
//定义切面
public void brfore(){
log.info("方法执行之前");
}
}
3. 配置spring-config.xml文件
<!--定义切面的Bean-->
<bean id="beforeLogger" class="aop.beforeLogger"></bean>
<!--配置切入信息-->
<aop:config>
<!--定义切入点-->
<aop:pointcut id="pointcut" expression="execution(* service.UserServiceImpl.*(..))"/>
<aop:aspect ref="beforeLogger">
<!--织入-->
<!--前置增强-->
<!--在执行方法之前会执行 brfore()方法-->
<aop:before method="brfore" pointcut-ref="pointcut" throwing="e"></aop:before>
<!--后置增强:在执行方法(正常执行完成后)后调用
returning 指定为名为result的参数注入返回值-->
<aop:after-returning method="afterReturning"
pointcut-ref="pointcut" returning="result">
</aop:after-returning>
<!--后置增强:在执行方法(正常执行完成后)后调用
returning 指定为名为result的参数注入返回值-->
<aop:after-returning method="afterReturning"
pointcut-ref="pointcut" returning="result">
</aop:after-returning>
<!-- 异常抛出增强:执行方法异常时执行
throwing 指定为名为e的异常注入返回值-->
<aop:after-throwing method="afterThrowing" pointcut-ref="pointcut" throwing="e">
</aop:after-throwing>
<!-- 最终增强:无论方法时正常还是异常退出都会执行
returning 指定为名为result的参数注入返回值-->
<aop:after method="afterReturning"
pointcut-ref="pointcut" returning="result"></aop:after>
</aop:aspect>
</aop:config>
除了之前的单个功能的增强,还有一种包含了多数的增强的 环绕增强
- 定义环绕增强切面
public class ArroundLogger {
private static final Logger log = Logger.getLogger(ArroundLogger.class);
public Object arroundLogger(ProceedingJoinPoint jp) throws Throwable {
log.info("调用" + jp.getTarget() + "的" + jp.getSignature().getName() + "方法。方法入参" + Arrays.toString(jp.getArgs()));
try {
Object result = jp.proceed();
log.info("调用" + jp.getTarget() + "的" + jp.getSignature().getName() + "方法。方法返回值" + result);
return result;
} catch (Throwable e) {
log.error(jp.getSignature().getName() + "方法发生异常:" + e);
e.printStackTrace();
throw e;
} finally {
log.info(jp.getSignature().getName() + "方法结束执行");
}
}
}
-
使用环绕增强
<aop:around method="arroundLogger" pointcut-ref="pointcut"></aop:around>
通过注解使用AOP
1. 定义注解
import org.apache.log4j.Logger;
import org.aspectj.lang.annotation.Aspect;
//使用 @Aspect 注解将beforeLogger定义为切面
@Aspect
public class beforeLogger {
private Logger log = Logger.getLogger(beforeLogger.class);
//前置增强注解
@Before("execution(* action.UserAction.*(..))")
public void brfore(){
log.info("方法执行之前");
}
//最终增强注解
@After("execution(* action.UserAction.*(..))")
public void afterLogger(JoinPoint jp){
log.info(jp.getSignature().getName()+"方法结束执行");
}
//后置增强注解
@AfterThrowing(pointcut = "execution(* action.UserAction.*(..))",throwing = "e")
public void afterThrowing(JoinPoint jp,RuntimeException e){
log.error(jp.getSignature().getName()+"犯法发生异常:"+e);
}
//环绕增强注解
@Around("execution(* action.UserAction.*(..))")
public Object arroundLogger(ProceedingJoinPoint jp) throws Throwable {
log.info("调用" + jp.getTarget() + "的" + jp.getSignature().getName() + "方法。方法入参" + Arrays.toString(jp.getArgs()));
try {
Object result = jp.proceed();
log.info("调用" + jp.getTarget() + "的" + jp.getSignature().getName() + "方法。方法返回值" + result);
return result;
} catch (Throwable e) {
log.error(jp.getSignature().getName() + "方法发生异常:" + e);
e.printStackTrace();
throw e;
} finally {
log.info(jp.getSignature().getName() + "方法结束执行");
}
}
//定义切入点
@Pointcut("execution(* action.UserAction.*(..))")
public void pointcut(){}
//通过引用定义的切入点,使用增强
@AfterReturning(pointcut = "pointcut()",returning = "result")
public void afterReturning01(JoinPoint jp,Object result){
log.info("调用"+jp.getTarget()+"的"+jp.getSignature().getName()+"方法。方法入参:"+result);
}
}
2. 配置xml文件 ,扫描注解,并且启动AOP注解
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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">
<!-- 扫描注解 -->
<context:component-scan base-package="cn.biz"></context:component-scan>
<!-- 启动AOP注解 -->
<aop:aspectj-autoproxy/>
</beans>
spring-mybatis整合
整合的步骤
1. 导入相关的jar
-
mybatis
<!--mybatis start--> <!--mysql jar--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.17</version> </dependency> <!-- mybatis --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.2</version> </dependency> <!--log4j--> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> <!--mybatis end-->
-
spring
<!--spring start--> <!-- spring-beans --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>5.1.9.RELEASE</version> </dependency> <!--spring-core --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>5.1.9.RELEASE</version> </dependency> <!-- spring-context --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.1.9.RELEASE</version> </dependency> <!-- spring-expression --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-expression</artifactId> <version>5.1.9.RELEASE</version> </dependency> <!-- commons-logging --> <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.2</version> </dependency> <!--spring end-->
-
数据源
<!-- commons-dbcp2 --> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-dbcp2</artifactId> <version>2.7.0</version> </dependency> <!-- commons-pool2 --> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> <version>2.7.0</version> </dependency>
-
spring-mybatis
<!--spring-mybatis end--> <!-- mybatis-spring --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>2.0.1</version> </dependency> <!-- spring-jdbc --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.1.9.RELEASE</version> </dependency> <!-- spring-tx --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>5.1.9.RELEASE</version> </dependency> <!--spring-mybatis end-->
2. 配置mybatis-config.xml文件
由于数据源的配置移入了spring中,所以mybatis-config.xml的文件变得很简约
<?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="LOG4J"></setting>
</settings>
<typeAliases>
<package name="cn.pojo"/>
</typeAliases>
</configuration>
3. 配置spring-config.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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">
<!-- 内部配置数据源 -->
<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"></property>
<property name="url">
<value><![CDATA[jdbc:mysql://127.0.0.1:3306/easybuy?serverTimezone=UTC&useUnicode=true&characterEncoding=UTF-8]]></value>
</property>
<property name="username" value="root"></property>
<property name="password" value="root"></property>
</bean>
<!--定义工厂-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="configLocation" value="classpath:myBatis-config.xml"/>
</bean>
<!-- 将mapper里的映射文件,全部通过工厂创建好bean 创建好的bean id命名就是类名首字母改成小写 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="cn.mapper" />
</bean>
<!--单个单个类的扫描 -->
<!--<bean id="classesMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
<property name="mapperInterface" value="mapper.classes.ClassesMapper" />
<property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>-->
<!-- 根据已存在的mappper的bean 定义biz层的bean -->
<bean id="classesService" class="service.impl.ClassesServiceImpl">
<property name="classesMapper" ref="classesMapper"></property>
</bean>
</beans>
4. 测试
@Test
public void testRole(){
ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
对象类型 对象名 = (对象类型)context.getBean("bean的id");
对象名.方法();
}
事务
1. 导入jar
由于在配置spring-mybatis和aop的时候就已经将jar导入,这里就不用导入jar了
2. 配置声明式事务
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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">
<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"></property>
<property name="url">
<value><![CDATA[jdbc:mysql://127.0.0.1:3306/easybuy?serverTimezone=UTC&useUnicode=true&characterEncoding=UTF-8]]></value>
</property>
<property name="username" value="root"></property>
<property name="password" value="root"></property>
</bean>
<!--定义切面-->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--设置事件的属性-->
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<!--tx:method可以有多个 name是必须的 用于指定匹配的方法-->
<tx:method name="add" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<!-- 定义切面 -->
<aop:config>
<!--定义切点-->
<aop:pointcut id="pointCut" expression="execution(* cn.biz..*.*(..))"/>
<!--将事务增强-->
<aop:advisor advice-ref="txAdvice" pointcut-ref="pointCut"></aop:advisor>
</aop:config>
</beans>
Propagation支持7种不同的传播机制:
REQUIRED
:如果存在一个事务,则支持当前事务。如果没有事务则开启一个新的事务。
SUPPORTS
: 如果存在一个事务,支持当前事务。如果没有事务,则非事务的执行。但是对于事务同步的事务管理器,PROPAGATION_SUPPORTS与不使用事务有少许不同。
NOT_SUPPORTED
:总是非事务地执行,并挂起任何存在的事务。
REQUIRESNEW
:总是开启一个新的事务。如果一个事务已经存在,则将这个存在的事务挂起。
MANDATORY
:如果已经存在一个事务,支持当前事务。如果没有一个活动的事务,则抛出异常。
NEVER
:总是非事务地执行,如果存在一个活动事务,则抛出异常
NESTED
:如果一个活动的事务存在,则运行在一个嵌套的事务中。如果没有活动事务,则按REQUIRED属性执行。
3. 通过注解定义事务
-
配置文件
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 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"> <context:component-scan base-package="cn.biz,cn.aop,cn.controller"/> <bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"></property> <property name="url"> <value><![CDATA[jdbc:mysql://127.0.0.1:3306/easybuy?serverTimezone=UTC&useUnicode=true&characterEncoding=UTF-8]]></value> </property> <property name="username" value="root"></property> <property name="password" value="root"></property> </bean> <!--定义切面--> <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean> <!-- 启用事务注解 --> <tx:annotation-driven transaction-manager="txManager"/> </beans>
-
使用事务注解
@Transactional(propagation = Propagation.REQUIRED) public Integer add(Order order, OrderDetail orderDetail) throws Exception { orderMapper.add(order); orderDetail.setOrderId(order.getId()); return orderDetailMapper.add(orderDetail); }
此方法就添加了事务增强