[开发框架]-Spring

概述

Spring是分层的Java SE/EE应用full-stack(全栈)轻量级开源框架,以IoCAOP为内核,提供了展现层Spring MVC 和持久层Spring JDBC以及业务层事务管理等众多的企业级应用技术,还能整合其它优秀的第三方框架和类库

依赖

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.3.9</version>
</dependency>

耦合与解耦

1. 耦合性-某度百科资料
简单来说,耦合就是程序间的依赖关系,包括类之间的依赖,方法间的依赖
2. 解耦就是降低程序间的依赖关系。我们应该做到,编译期不依赖,运行时才依赖
3. 解耦的思路
a. 使用反射来创建对象,而避免使用new关键字
JDBC中的第一步注册驱动的两种做法:

//这种做法依赖于具体的类,类如果找不到在编译期就会出错
DriverManager.registerDriver(new com.mysql.jdbc.Driver());

/*这种做法只依赖于一个字符串,编译器不会出错,但这种做法也有一个问题,
那就是在这里这个注册的字符串就写死在这里了,如果要更换驱动还是需要改源码*/
Class.forName("com.mysql.jdbc.Driver");

b. 通过读取配置文件来获取要创建的对象全限定类名
4.工厂模式 – 构造一个创建Bean对象的工厂
Bean在计算机英语中有可重用组件的含义,JavaBean就是用Java语言编写的可重用组件,因此JavaBean的涵盖范围要大于我们说的实体类
这样的工厂我们就可以用来创建service和dao对象,用配置文件配置这两种对象的bean名称全限定类名,然后读取配置文件,通过反射获取对象
再结合单例模式,在工厂类中定义一个Map集合,key值为String(bean的名称),value值为Object(bean对应的实例化对象),然后设置一个静态代码块,读取配置文件中所有的key,循环反射获取其实例化对象然后放入Map集合中,之后bean的获取直接在map集合中获取
思想:IoC,把创建对象的权利交给框架 某度百科资料

入门

1.导入依赖
2.创建bean.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">
    <!--把对象的创建交给spring来管理,id是bean的名称,class是对应的全限定类名 -->
    <bean id="userService" class="com.xxx.www.service.impl.UserServiceImpl"></bean>
    <bean id="userDao" class="com.xxx.www.dao.impl.UserDaoImpl"></bean>
</beans>

3.代码中使用

//1.获取核心容器对象
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");
//2,根据id获取bean对象(两种方式)
UserService userService = (UserService) applicationContext.getBean("userService");
UserDao userDao = applicationContext.getBean("userDao",UserDao.class);

ApplicationContext的三个实现类

ClassPathXmlApplicationContext:它可以加载类路径下的配置文件,要求配置文件必须在类路径下。不在的话就加载不了(与第二个相比更常用)
FileSystemXmlApplicationContext:它可以加载磁盘任意路径下的配置文件(必须有访问权限)
AnnotationConfigApplicationContext:它是用于读取注解创建容器的

与核心容器相关的两个接口

ApplicationContext:它在创建核心容器时,创建对象采取的策略是采用立即加载的方式,也就是说,只要一读取完配置文件就马上创建配置文件中配置的对象 ---- 单例对象适用 (该接口较常用)
BeanFactory:它在构建核心容器时创建对象采取的策略是采用延迟加载的方式,也就是说,什么时候根据id获取对象了,什么时候才真正地创建对象 ---- 多例对象适用

spring管理bean的细节

1. 创建bean对象的三种方式

<!--第一种方式:使用默认构造函数创建,使用bean标签,加上id和class属性,
且没有其它属性和标签时采用的就是默认构造函数创建bean对象,
此时如果类中没有默认构造函数则对象无法创建
这种情况下,如果我们声明了带参数的构造方法,必须显式声明无参构造方法-->
<bean id="userService" class="com.xxx.www.service.impl.UserServiceImpl"></bean>
<!--第二种方式:使用普通工厂中的方法创建对象(使用某个类中的某个方法创建对象并将其存入容器)
这里InstanceFactory是一个工厂类,其中有一个方法getAccountService()是用来创建并返回一个AccountService实现类的-->
<bean id="instanceFactory" class="com.xxx.www.factory.instanceFactory"></bean>
<bean id="accountSerice" factory-bean="instanceFactory" factory-method="getAccountService"></bean>
<!--第三种方式:使用工厂中的静态方法创建对象(使用某个类中的静态方法创建对象,并存入容器)
这里有一个StaticFactory工厂类,有一个静态方法getAccountService()用来创建并返回一个AccountService实现类-->
<bean id="accountSerice" class="com.xxx.www.factory.StaticFactory" factory-method="getAccountService"></bean>

bean的作用范围

bean标签的scope属性,用于指定bean的作用范围,取值有:
singleton:单例的(默认值)
prototype:多例的
request:作用于web应用的请求范围
session:作用于web应用的会话范围
global-session:作用于集群环境的会话范围(全局会话范围),当不是集群环境时,它就是session

bean的生命周期

单例对象
出生:当容器创建时对象出生
活着:只要容器还在,bean对象一直活着
死亡:容器销毁,对象消亡
所以单例对象的生命周期和容器相同
多例对象
出生:当我们使用对象时spring框架为我们创建
活着:对象只要是在使用过程中就一直活着
死亡:当对象长时间不用,且没有别的对象引用时,由java的垃圾回收器回收
ps:bean标签中的init-method用于指定bean对象被初始化后去调用的方法;destroy-method用于指定bean对象被销毁时去调用的方法

依赖注入

在运用IoC的思想之后,依赖关系的管理都交给spring来维护,在当前类需要用到其它类的对象时,由spring为我们提供,我们只需要在配置文件中说明。依赖关系的维护就称之为依赖注入
能注入的数据有三类:
基本数据类型和String
其它bean类型 (在配置文件或注解配置过的bean)
复杂类型/集合类型

注入的方式有三种:
使用构造函数提供
使用set方法提供
使用注解提供

使用构造函数注入

<!--使用的标签:constructor-arg,标签中的属性:
     type:用于指定要注入的数据类型,该数据类型也是构造函数中某个或某些参数的类型
     index:用于指定要注入的数据给构造函数中指定索引位置的参数赋值,索引从0开始
     name:用于指定给构造函数中指定名称的参数赋值 (常用的)
     value:用于提供基本类型和String类型的数据
     ref:用于指定其它的bean类型数据,指的就是在spring核心容器中出现过的bean对象
    优势:
     在获取bean对象时,注入数据是必须的操作,否则对象无法创建成功
    弊端:
     改变了bean对象的实例化方式,使我们在创建对象时如果用不到这些数据也必须提供-->

<bean id="accountService" class="com.xxx.www.service.impl.AccountServiceImpl">
    <constructor-arg name="name" value="test"></constructor-arg>
    <constructor-arg name="age" value="18"></constructor-arg>
    <constructor-arg name="birthday" ref="now"></constructor-arg>
</bean>
<!--配置一个日期对象-->
<bean id="now" class="java.util.Date"></bean>

使用set方法注入(更常用)

<!--使用的标签:property,标签中的属性:
     name:用于指定注入时所调用的set方法名称(set方法去掉set的后缀,同时首字母要改为小写)
     value:用于提供基本类型和String类型的数据
     ref:用于指定其它的bean类型数据,指的就是在spring核心容器中出现过的bean对象
    优势:
     创建对象时没有明确的限制,可以直接使用默认构造函数
    弊端:
     如果要某个成员必须有值,则获取对象时有可能set方法没有执行-->
<bean id="accountService" class="com.xxx.www.service.impl.AccountServiceImpl">
    <property name="name" value="test"></property>
    <property name="age" value="18"></property>
    <property name="birthday" ref="now"></property>
</bean>

集合类型/复杂类型的数据注入

<!--复杂类型/集合类型的注入只能用构造函数或者set方法的注入方式
    用于给list结构集合(list,set,array)注入的标签:
        list array set
    用于给map(map,properties)结构集合注入的标签:
        map props
    结构相同,标签可以互换-->
<bean id="accountService" class="java.xxx.www.service.impl.AccountServiceImpl">
    <!--字符串数组-->
    <property name="myStrings">
        <array>
            <value>AAA</value>
            <value>BBB</value>
            <value>CCC</value>
        </array>
    </property>
    <!--字符串list-->
    <property name="myList">
        <list>
            <value>AAA</value>
            <value>BBB</value>
            <value>CCC</value>
        </list>
    </property>
    <!--字符串map-->
    <property name="myMap">
        <map>
            <entry key="a" value="a"></entry>
            <entry key="b">
                <value>b</value>
            </entry>
        </map>
    </property>
    <!--properties-->
    <property name="myProp">
        <props>
            <prop key="a">aaa</prop>
            <prop key="b">bbb</prop>
        </props>
    </property>
</bean>

注解开发

ioc常用注解

1.用于创建对象的,他们的作用就跟在xml配置文件中编写一个 <bean>标签是一样的。要在spring的xml文件中告知spring在创建容器时要扫描的包,配置所需要的标签不是在beans的约束中,而是在一个名称为context名称空间的约束中:

<context:component-scan base-package="com.xxx"></context:component-scan>
  • @Component,用于把当前类对象存入spring容器中,属性:value,用于指定bean的id,如果没有写则id默认是当前类名的小驼峰形式
  • @Controller,@Service,@Mapper (或者 @Repository,推荐 Mapper),这三个注解和@Component的作用和属性是完全一样的,只是为了让我们的三层对象更加清晰,所以分别用于表现层,业务层,以及持久层

2.用于注入数据的,他们的作用就跟配置文件中<bean>标签中的<properties>标签是一样的

  • @Autowired ,自动 按照类型注入,只要容器中有唯一一个bean对象类型和要注入的变量类型相匹配就可以注入成功,可以用于变量上,也可以用于方法上(调用方法时,以Autowired的方式为方法参数注入再执行方法)。如果有多个bean类型匹配,会找id与变量的名称相同的bean进行注入,如果没有bean的id与变量名称相同,则报错

    要注意的是,@Autowired 对静态变量是不适用的,即不能对标记为 static 的变量进行注入

  • @Qualifier,在按照bean类型与变量类型匹配的基础上再按照名称注入,它在给类成员注入时不能单独使用要跟@Autowired一起使用,但是在给方法参数注入时可以。属性:value,用于指定注入bean的id

  • @Resource直接按照bean的id注入,可以独立使用,使用name属性指定bean的id

以上三个注解都只能注入其它bean类型的数据,而基本数据类型和String无法使用上述注解实现,另外,集合类型的注入只能通过xml来实现

  • @Value,用于注入基本类型和String类型的数据,使用属性value指定数据的值,它可以使用spring中的SpEL,也就是spring中的EL表达式(${表达式})

3.用于改变作用范围的,作用就跟在<bean>标签中的scope标签一样

  • @Scope,用于指定bean的作用范围,使用属性value指定范围的取值,常用取值:singleton,prototype,不写默认是singleton单例

4.和生命周期相关的,作用就跟<bean>标签中使用init-methoddestroy-method属性一样

  • @PreDestory,用于指定销毁方法
  • @PostConstruct,用于指定初始化方法

其他注解

  • @Configuration,指定当前类是一个配置类,当配置类作为 AnnotationConfigApplicationContext对象构造方法的参数时,该注解可以不写
  • @ComponentScan,指定spring在创建容器时要扫描的包,使用属性valuebasePackages进行指定
    借此,我们可以创建一个spring的配置类使其完成bean.xml的功能,移除xml文件
  • @Bean,用于把当前方法的返回值作为bean对象存入容器中,属性:name用于指定bean的id,默认值是当前方法的名称。当我们使用注解配置方法时,如果方法有参数,spring会去容器中查找有没有可用的bean对象,查找的方式和@Autowired的方式是一样的,此时如果匹配的bean有多个且id也无法匹配,就可以使用@Qualifier注解指定要注入的bean的id
    使用注解完成spring的配置后,此时核心容器的获取就不能使用xml文件了:
//不能用new ClassPathXmlApplicationContext("bean.xml");
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfiguration.class);
applicationContext.getBean(...);
  • @Import, 用于导入其它的配置类,使用value属性指定。用在我们的主配置类上,导入其它小配置类。当我们使用@Import注解后,有该注解的类就成为父配置类,而导入的就是子配置类
  • @PropertySource,用于指定properties文件的位置,属性value指定文件的名称和路径,使用classpath关键字表示在类路径下,多级目录用/隔开。我们可以在jdbc的配置类中引用这些数据:
public class JdbcConfig {
    @Value("${jdbc.driver}")
    private String driver;
}

在父配置类引入properties文件:

@PropertySource("classpath:jdbc.properties")
@Import(JdbcConfig.class)
public class SpringConfiguration {
}
  • @Primary,多个接口多个实现类都加了@Component注解,此时对该接口类型的bean进行@Autowired注入时就会出现多个bean匹配的情况导致无法装配并报错,使用@Primary注解在其中一个实现类上,可以让spring在有多个bean匹配的情况下优先选择含@Primary注解的bean进行装配

AOP

概述

某度百科资料
简单地说,就是把我们程序中重复的代码抽取出来,在需要执行的时候,使用动态代理的技术,在不修改源码的基础上,对我们已有的方法进行增强,可以减少重复代码,提高开发效率以及维护方便。核心技术:动态代理(基于接口的以及基于子类的)
连接点(Joinpoint) :可以被增强的方法
切入点(Pointcut) :被增强了的方法
通知/增强(advice) :拦截(invoke()方法拦截)到切入点后要做的事就是通知,分为前置通知后置通知异常通知最终通知环绕通知
引介(Introduction) :一种特殊的通知,在不修改类代码的前提下,Introduction可以在运行期为类动态地添加一些方法或者Field
目标对象(Target) : 代理的目标对象(被代理对象)
织入(Weaving) :指把增强应用到目标对象来创建新的代理对象的过程
代理(Proxy) :一个类被AOP织入增强后就产生一个结果代理类
切面(Aspect) :是切入点和通知(引介)的结合

运用AOP要明确的事

我们需要做到的:熟悉业务需求,编写核心业务代码;把公用代码抽取出来,制作成通知;在配置文件中声明切入点与通知间的关系,即切面
spring做到的:spring监控切入点方法的执行,一旦监控到切入点方法被执行,使用代理机制,动态创建目标对象的代理对象,根据通知类别,在代理对象的对应位置,将通知对应的功能织入,完成完整的代码逻辑运行

基于XML配置AOP

1.把通知的bean也交给spring来管理
2.使用aop:config标签表明开始AOP的配置
3.使用aop:aspect标签表明配置切面(id属性是给切面提供一个唯一标识,ref属性是指定通知类bean的id)
4.在aop:aspect标签的内部使用对应标签来配置通知的类型

<!--这里Logger类作为通知类,打印日志作为一段公共代码(前置通知)-->
<bean id="logger" class="com.xxx.www.utils.Logger"></bean>
<aop:config>
   <aop:aspect id="logAdvice" ref="logger">
       <!--method属性用于指定通知类中哪个方法是(前置)通知
           pointcut属性用于指定切入点表达式,该表达式的含义是对哪些方法增强
             切入点表达式写法:execution(切入点表达式)
             	1.标准写法:访问修饰符 返回值 包名.包名...类名.方法名(参数列表)
             	2.访问修饰符可以省略
             	3.全通配写法:* *..*.*(..)
             	4.返回值可以用通配符,表示任意返回值
             	5.包名可以用通配符,表示任意包,但是有几级包就需要写几个*.
             	  包名可以使用..表示当前包及其子包(因此当使用*..时就表示任意包)
             	6.类名和方法名都可以使用*来实现通配
             	7.参数列表可以直接写数据类型:基本数据类型直接写名称(int);
             							  引用类型写包名.类名的方式(java.lang.String)
             			可以使用通配符表示任意类型,但必须有参数
             			可以使用..表示有无参数皆可
            --实际开发中切入点表达式的通常写法:
            	切到业务层实现类下的所有方法,即* com.xxx.www.service.impl.*.*(..) -->
       <aop:before method="printLog" pointcut="execution(* com.xxx.www.service.impl.*.*(..))"></aop:before>
       <aop:after-returning method="afterReturningPrintLog" pointcut-ref="pt1"></aop:after-returning>
   	   <!--配置切入点表达式 id属性用于指定表达式的唯一标识 expression用于指定表达式内容,在配置通知的标签中用pointcut-ref属性引用这个表达式
   	       此标签写在aop:aspect标签内部只能当前切面使用;还可以写在aop:aspect外面此时就变成了所有切面可用,但要注意,必须写在aop:aspect整个标签之前,不能之后,否则就会报错-->
       <aop:pointcut id="pt1" expression="execution(* com.xxx.www.service.impl.*.*(..))"/>
   </aop:aspect>
</aop:config>

切入点表达式的解析需要借助依赖:

<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.1</version>
</dependency>

四种常用通知类型

<!--前置通知:在切入点方法执行之前执行-->
<aop:before method="beforePrintLog" pointcut="execution(* com.xxx.www.service.impl.*.*(..))"></aop:before>
<!--后置通知:在切入点方法正常执行后执行,它和异常通知永远只能有一个执行
			 (事务要么提交要么回滚)-->
<aop:after-returning method="afterReturningPrintLog" pointcut="execution(* com.xxx.www.service.impl.*.*(..))"></aop:after-returning>
<!--异常通知:在切入点方法执行产生异常之后执行,与后置通知互斥-->
<aop:after-throwing method="afterThrowingPrintLog" pointcut="execution(* com.xxx.www.service.impl.*.*(..))"></aop:after-throwing>
<!--最终通知:无论切入点方法是否正常执行他都会在其后面执行-->
<aop:after method="afterPrintLog" pointcut="execution(* com.xxx.www.service.impl.*.*(..))"></aop:after>

环绕通知

<aop:around method="aroundPrintLog" pointcut-ref="pt1"></aop:around>

配置了环绕通知之后,如果在环绕通知中没有明确的切入点方法调用,那么切入点方法不会执行而环绕通知方法会执行,也就是说,虽然在代码中调用了切入点方法,但执行效果是切入点方法没有被执行而环绕通知方法有被执行
spring为我们提供了一个接口:ProceedingJoinPoint,该接口有一个方法proceed()此方法就相当于明确调用切入点方法该接口可以作为环绕通知的方法参数,在程序执行时,spring会为我们提供该接口的实现类供我们使用:

public Object aroundPrintLog(ProceedingJoinPoint proceedingJoinPoint){
    Object returnValue = null;
    try {
    	//得到切入点方法执行所需参数
        Object args = proceedingJoinPoint.getArgs();
        //System.out.println("aroundPrintLog执行");  -----增强代码写在这就是前置通知
        returnValue = proceedingJoinPoint.proceed();
        //                                          -----写在这就是后置通知
        return returnValue;
    //这里catch的必须是Throwable。Exception是拦不住的
    } catch (Throwable throwable) {
        //                                          -----写在这就是异常通知
        throw new RuntimeException(throwable);
    } finally {
        //                                          -----写在这就是最终通知
    }
}

由此看出,前面四种通知我们是通过配置的方式实现通知,而环绕通知是spring提供给我们的一种可以在代码中手动控制增强方法何时执行的方式

基于注解配置AOP

首先要开启对AOP相关注解的扫描:如果是xml文件,需加上一行<aop:aspectj-autoproxy></aop:aspectj-autoproxy>;如果使用注解,在spring的配置类加上@EnableAspectJAutoProxy
@Aspect注解在类上表示当前类是一个切面类;还要加上@Component注解
@Pointcut在切面类中设置切入点:

@Pointcut("execution(* com.xxx.www.service.impl.*.*(..))")
private void pt(){}

可以用 && / || 连用多个切入点表达式表示且和或;也可以用 ! 表示非
@annotation用于指定切入点为含某个注解的方法
@within表示匹配带有指定注解的类(中的方法)

@Around("@annotation(com.xxx.config.annotation.Token) || @within(com.xxx.config.annotation.Token)")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {...

@Before,@AfterReturning,@AfterThrowing,@After,@Around分别为前置通知,后置通知,异常通知,最终通知和环绕通知,在括号中指定切入点如:

//pt后面的括号必须要写
@Before("pt()")
public Object beforePrint(){}

需要注意的是,使用四种基本通知的注解情况下,最终通知会在后置通知以及异常通知前面被执行(如果有配置的话);如果不使用四种基本通知类型的注解而使用环绕通知的注解自己用代码控制通知的发生的话就不会出现最终通知在后置通知以及异常通知之前执行的情况。所以如果要用注解配置通知,推荐使用环绕通知自己配置

JdbcTemplate

概述

JdbcTemplate是spring提供的一个对象,是对原始的Jdbc API对象的简单封装,用于和数据库交互,实现对表的CRUD操作。spring提供了很多的操作模板类:
操作关系型数据库的:JdbcTemplate,HibernateTemplate
操作nosql数据库的:RedisTemplate
操作消息队列的:JmsTemplate

入门

依赖

<!--JdbcTemplate的所在-->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>5.2.15.RELEASE</version>
</dependency>
<!--与事务相关,在导JdbcTemplate依赖时同时导入-->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-tx</artifactId>
    <version>5.2.15.RELEASE</version>
</dependency>

基本使用

public static void main(String[] args) throws Exception{
	//准备数据源,使用spring内置的数据源
    DriverManagerDataSource driverManagerDataSource = new DriverManagerDataSource();
    driverManagerDataSource.setDriverClassName("com.mysql.jdbc.Driver");
    driverManagerDataSource.setUrl("jdbc:mysql://localhost:3306/xxx");
    driverManagerDataSource.setUsername("root");
    driverManagerDataSource.setPassword("root");
	//1.创建JdbcTemplate对象
    JdbcTemplate jdbcTemplate = new JdbcTemplate();
    //2.设置数据源(也可以在上面的构造函数中直接传入数据源)
    jdbcTemplate.setDataSource(driverManagerDataSource);
    //3。执行操作
    jdbcTemplate.execute("insert into account(name,money)values ('ccc',1000)");
}

结合IoC:

<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    <property name="dataSource" ref="dataSource"></property>
</bean>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
    <property name="url" value="jdbc:mysql://localhost:3306/xxx"></property>
    <property name="username" value="root"></property>
    <property name="password" value="root"></property>
</bean>
ApplicationContext applicationContext = new ClassPathXmlApplicationContext();
JdbcTemplate jdbcTemplate = applicationContext.getBean("jdbcTemplate", JdbcTemplate.class);
jdbcTemplate.execute("insert into account(name,money)values ('ccc',1000)");

…(剩余内容以后更新)

spring提供的关于事务控制的API

基于XML的声明式事务控制配置

1. 配置事务管理器
2. 配置事务的通知
需要导入事务的约束 tx命名空间和约束,同时也需要aop的
使用tx:advice标签配置事务通知,id属性用于给事务通知起一个唯一标识,transaction-manager用于给事务提供一个事务管理器引用
3. 配置通用切入点表达式
4. 建立事务通知和切入点表达式的对应关系
5. 配置事务的属性
tx:advice标签内的tx:attributes标签
事务的属性:
isolation:用于配置事务的隔离级别,缺省值是DEFAULT,表示使用数据库的默认隔离级别
propagation:用于指定事务的传播行为,缺省值是REQUIRED,表示一定会有事务,增删改的选择。查询方法可以选择SUPPORTS
read-only:用于指定事务是否只读。只有查询方法才能设置为true。默认值是false,表示读写
timeout:用于指定事务的超时时间,默认值是-1,表示永不超时。如果指定了数值,以秒为单位
rollback-for:用于指定一个异常,当该异常产生时,事务回滚,产生其它异常时,事务不回滚。没有默认值,表示任何异常都回滚
no-rollback-for:用于指定一个异常,当产生该异常时,事务不回滚,产生其它异常时,事务回滚,没有默认值,表示任何异常都回滚

<!--数据源-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
    <property name="url" value="jdbc:mysql://localhost:3306/xxx"></property>
    <property name="username" value="root"></property>
    <property name="password" value="root"></property>
</bean>
<!--事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"></property>
</bean>
<!--配置事务通知-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
    <!--配置事务属性-->
    <tx:attributes>
    	<!--指定切入点中的方法-->
        <tx:method name="transfer" propagation="REQUIRED" read-only="false"></tx:method>
        <!--通配符,匹配所有方法-->
        <tx:method name="*" propagation="REQUIRED" read-only="false"></tx:method>
        <!--匹配所有find..的方法,由于这个写法符合条件的方法比上一个只有一个*的要少,所以这个优先级更高
            这样就实现了查询方法和增删改方法不同的配置-->
        <tx:method name="find*" propagation="SUPPORTS" read-only="true"></tx:method>
    </tx:attributes>
</tx:advice>
<!--配置aop-->
<aop:config>
    <!--切入点表达式-->
    <aop:pointcut id="pointcut" expression="execution(* com.xxx.www.service.impl.*.*(..))"></aop:pointcut>
    <!--建立切入点表达式和事务通知的对应关系-->
    <aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut"></aop:advisor>
</aop:config>

基于注解的声明式事务控制配置

…(剩余内容以后更新)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值