当前位置: 首页 > 图灵资讯 > 技术篇> Spring笔记

Spring笔记

来源:图灵教育
时间:2023-05-31 09:16:30

一、初识1. 架构演变

  • 单一应用架构 ORM 数据访问框架
  • 将垂直应用架构拆分成几个不相关的应用程序,放置在不同的服务器中 MVC WEB框架
  • 分布式服务架构提取核心业务作为独立服务 RPC 集群间通信协议
  • 基于访问压力实时管理集群容量,增加流动计算架构的调度中心,提高利用率 SOA
2. 框架演变
  • JSP+Servlet+JavaBean
  • JSP: Java Server Page
  • Servlet: Server Applet 服务器端的小应用程序
  • servlet生命周期
  • jsp作用域
  • JavaBean: 有些对象包括setter getter 属性等
  • MVC三层架构
  • Controller 接受客户端请求,查询Model,接受Model数据
  • Model 数据库中的表
  • View 前段框架、html等,用于渲染controller的结果
  • EJB 重量级框架,借口太多,依赖性太强,侵入性太强(写代码需要继承或者实现很多父亲的借口),使用麻烦
  • SSH Structs1/Structs2+Hibernate+Spring
  • Struts2框架安全存在隐患,Restful模式的流程度逐渐普及
  • SpringMVC以Spring为扩展,完成了Structs的工作,并结合web容器推出了SpringBoots
  • Ibatis等Hibernate有很多替代品, Mybatis, JPA等
  • SSM Spring+SprinvMVC+Mybatis
  • SpringBoot
二、Spring1. 生态

大部分所需的功能都在Spring全家桶中

2. 核心解释
  • 开源框架
  • 为了简化企业发展,使发展更加优雅
  • IOC和AOP的容器框架
  • IOC 控制反转
  • AOP 面向切面编程
  • 容器 包括和管理应用对象的生命周期,桶与水的关系,spring是桶,管理对象是水
3. 优点
  • Spring通过DI通过DI、简化AOP和消除样板的开发
  • 巨大的生态系统构建在Spring上,将Spring扩展到各个领域
  • 低侵入设计
  • 基于Spring的应用,write once,run anywhere
  • IOC容器降低了业务对象替换的复杂性,提高了组件之间的莲藕
  • AOP允许集中管理安全、事务、日志等一些通用任务,以便更好地重用
  • Spring的ORM和DAO与第三光持久层框架集成良好,简化了数据库访问
  • 不强制应用依赖于Spring
4. IOC 控制反转

保存对象,每次使用都不需要重新创建,从保存的地方,即从自己创建到他人创建,IOC是一种设计理念,具体实现称为DI,IOC容器是放置对象的地方,IOC不是spring,只是实现,

  • 谁控制谁:IOC容器控制对象
  • 控制什么:所需的对象和依赖的对象 userservice需要依赖userdao
  • 逆转是什么:IOC容器创建后依赖对象注入对象,从主动创建到被动接受
  • 需要逆转的是什么:依赖的对象
5. 总结
  • 莲藕IOC容器可以节藕
  • 生态
三、搭建1. 导包

构建Spring项目只需导入以下包即可commonsns-logging-1.2.jar 日志spring-beans-5.2.3.RELEASE.jar Beansspring-context-5.2.3.RELEASE.jar Contextspring-core-5.2.3.RELEASE.jar Corespring-expression-5.2.3.RELEASE.jar SpEL

2. 创建ioc.xml

ioc.xml

<beans><bean id="person" class="com.xxx.Person">    <property name="id" value="1"></property>    </bean></beans>

Main.java

ApplicationContext ctx = new ClassPathXmlApplicationContext("ioc.xml");ctx.getBean("person", Person.class);ctx.getBean("person");ctx.getBean(Person.class);

ioc.name一般用于xml,但也有value和index用于构造器赋值,但在工作中不常用,认为容易出现问题

  • p命名空间

<beans xmlns:p="http://www.springframework.org/schema/p'><bean id="person" class="com.xxx.Person" p:id="1" p:name="zhangsan">    </bean></beans>

注意点

  • Applicationcontext表示,IOC容器的入口必须创建此类对象
  • 读取配置文件的实现有两个类别
  • ClassPathXmlApplicationContext
  • FileSystemXmlApplicationContext
  • 默认情况下,容器启动后创建了容器中的对象,只对单例模式有效
  • 默认为单例
  • 通过setter/getter实现对象赋值的创建
  • FactoryBean 当继承FactoryBean创建的对象交给Spring进行管理时,无论是否为单例,都只会在使用时创建;一般不需要
  • 当对象获取和容器关闭时,spring容器可以指定相应的方法,多例不会调用destroy-mothod (一般不需要)

<bean id="person" class=" com. mashibing. bean. Person" init-method-"init" destroy-mothod="destory"></bean>

  • 通过实现BeanPostProcesor,指定的Bean可以在创建前后执行额外的操作
3. 创建第三方Bean对象的spring
  • 与导入自定义Bean对象相同,将导入Jar包所需的类别写入例子:

<bean id "dataSource" class=" com. alibaba. druid. pool. DruidDataSource"><property name="username" value="root"></property>    <property name="password" value="root"></property>    <property name="url" value="jdbc:mysql://localhost:3306/demo"></property>    <property name="driverClassName" value="com.mysql.jdbc.Driver"></property></bean>

这样,德鲁伊的数据源就交给了Spring容器控制

  • 引入外部配置文件赋值dataSource
  1. 导入context命名空间
  2. <context: property-placeholder location="classpath:db.properties"></context: property-placeholder>
  3. 修改Bean对象value
  • 命名空间

<?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">    <context:component-scan base-package="org.example"/></beans>

  • 修改Bean对象的导入方法

<bean id "dataSource" class=" com. alibaba. druid. pool. DruidDataSource"><property name="username" value="${jdbc.username}"></property>    <property name="password" value="${password}"></property>    <property name="url" value="${url}"></property>    <property name="driverClassName" value="${driver}"></property></bean>

  • tips: 属性可以重名,如username,可以是计算机名称,添加前缀区分
4. 基于xml的spring自动组装

autowire

Mode

Explanation

default/no

不注入

byName

按id组装 通过setter方法后面的单词决定,而不是参数列表

byType

根据属性类型在容器中查询相应的bean,在多个相同类型中会出现异常

constructor

按结构装配,若有多种类型相同,则按id装配

5. SpEL

可在ioc.通过xmlbean属性的value#{}一些算术操作或方法调用的方法,应用场景不多,可以知道

四、注解1. 几个注解

@Component: 可以在任何类别中添加组件@Controller: 放在控制层,接受用户请求@Service: 放在业务逻辑层@Repository: 放在数据访问层

在spring运行中,不区分这四个注释,只用于提高代码可读性tips: 偷懒,都用Componentt

2. 配置包扫描
  • 告诉spring应该从哪个包开始扫描注释,需要提前导入context命名空间<context:component-scan base-package="com.mashibing"></context:component-scan>
  • 使用注释时,需要根据类名首字母小写从容器中取出@Controller(value="xxx在IOC容器中指定bean的id
  • 确定要扫描的包后,可以控制和排除更细粒度的PersonServicee<context:exclude-filter type="assignable" expression="com.mashibing.service.PersonService"/>排除注解@Controller<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>include-exclude几乎不使用
3. @Autowired

即context.getBean()自动注入可通过@Autowired直接完成,默认情况下按类型进行装配规则

  • 如果只有一个,直接赋值
  • 如果没有发现,抛出异常,即使有,但不在Spring容器中
  • 如果找到多个,继续按照变量名作为id匹配,即在ioc.xml中添加了几个或被继承的类别,在容器中,必须注意变量名必须是多个类别中的一个,以及首字母小写
  • 直接组装匹配,注意,此时可以在变量名上添加注释@Qualifier()手动指定放入容器后的id名
  • 匹配不能抛出异常

此注释也可以放在方法上。此时,在创建对象时,该方法将自动调用,方法中的参数将自动组装 @Resource具有与@Autowired相同的功能

  • @resource由jdk提供,可以在更多的框架中使用,@autowired由spring提供,只能在spring中使用
  • @Resource按名称组装,@Autowired按类型组装
  • @使用@Resouce时,Qualifier将不再生效
五、AOP

AOP Aspect Oriented Programming OOP面向切面编程 Object Oritented Programming 面向对象编程解释:在程序运行过程中,将代码动态切入指定方法的指定位置:在程序运行过程中,当动态获取方法名称、参数和结果等相关信息时,动态代理可以实现流行的编程方法,即在程序运行过程中将代码动态切入指定方法的指定位置。

1. JDK中的动态代理

CalculatorProxy.java

/** * 帮助calculator生成代理对象的类别 */public class CalculatorProxy {    /**     *     *  为输入的参数对象创建动态代理对象     * @param calculator 被代理对象     * @return     */    public static Calculator getProxy(final Calculator calculator){        ///代理对象的类加载器        ClassLoader loader = calculator.getClass().getClassLoader();        ////代理对象的界面        Class<?>[] interfaces = calculator.getClass().getInterfaces();        //方法执行器,执行被代理对象的目标方法        InvocationHandler h = new InvocationHandler() {            /**             *  实施目标方法             * @param proxy 代理对象,使用jdk,任何时候都不要操作这个对象             * @param method 目前将执行的目标对象的方法             * @param args 该方法调用外界传入的参数值             * @return             * @throws Throwable             */            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {                //使用反射执行目标方法,实施目标方法后的返回值///                System.out.println(“这是动态代理执行的方法”);                Object result = null;                try {                    System.out.println(method.getName()+开始执行方法,参数是:"+ Arrays.asList(args));                    result = method.invoke(calculator, args);                    System.out.println(method.getName()完成+方法执行,结果是:"+ result);                } catch (Exception e) {                    System.out.println(method.getName()+”方法异常:"+ e.getMessage());                } finally {                    System.out.println(method.getName()+”方法的执行已经结束...");                }                ///返回结果                return result;            }        };        Object proxy = Proxy.newProxyInstance(loader, interfaces, h);        return (Calculator) proxy;    }}

按上面的代码,通过CalculatorProxy获取的Calculator对象,在执行任何方法时,都会输出相应的日志信息。注:Calculator它是一个接口,在使用时应该引入特定的实现对象CalculatorProxy.getProxy(new MyCalculator());

PS: 这种动态代理的实现调用了jdk的基本实现,不能为没有任何接口的类别创建代理对象。

2. Spring中的动态代理
  1. pom依赖

<!-- https://mvnrepository.com/artifact/cglib/cglib -->        <dependency>            <groupId>cglib</groupId>            <artifactId>cglib</artifactId>            <version>3.3.0</version>        </dependency>        <!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->        <dependency>            <groupId>org.aspectj</groupId>            <artifactId>aspectjweaver</artifactId>            <version>1.9.5</version>        </dependency>        <!-- https://mvnrepository.com/artifact/aopalliance/aopalliance -->        <dependency>            <groupId>aopalliance</groupId>            <artifactId>aopalliance</artifactId>            <version>1.0</version>        </dependency>        <!-- https://mvnrepository.com/artifact/org.springframework/spring-aspects -->        <dependency>            <groupId>org.springframework</groupId>            <artifactId>spring-aspects</artifactId>            <version>5.2.3.RELEASE</version>        </dependency>

  1. applicationContext.xml

<context:component-scan base-package="com.mashibing"></context:component-scan>

  1. 添加组件注释
  • 在logutil添加@Component注释
  • 给Mycalculator添加@Service注释
  1. 在程序中设置切面类, Logutil.在java中添加@aspect注释
  2. 什么时候在哪里执行设置切面类的方法, execution中的参数支持正则表达式和条件表达式

@Component@Aspectpublic class LogUtil {    /*    什么时候设置以下方法?        @Before:在目标方法之前运行:预通知        @After:操作后的目标方法:后置通知        @AfterReturning:正常返回目标方法后:返回通知        @AfterThrowing:在目标方法抛出异常后开始运行:异常通知        @Around:环绕:环绕通知        编写注释后需要设置哪些方法来执行?使用表达式        execution(访问修饰符  返回值类型 方法全称)     */    @Before("execution( public int com.mashibing.inter.MyCalculator.*(int,int))")    public static void start(){//        System.out.println(XXX方法开始执行,使用的参数为:"+ Arrays.asList(objects));//        System.out.println(method.getName()+开始执行方法,参数是:"+ Arrays.asList(objects));        System.out.println(”方法开始执行,参数为:");    }    @AfterReturning("execution( public int com.mashibing.inter.MyCalculator.*(int,int))")    public static void stop(){//        System.out.println(XXX方法执行结束,结果是:"+ Arrays.asList(objects));//        System.out.println(method.getName()+执行方法结束,结果是:"+ Arrays.asList(objects));        System.out.println()完成方法执行,结果是:");    }    @AfterThrowing("execution( public int com.mashibing.inter.MyCalculator.*(int,int))")    public static void logException(){//        System.out.println(method.getName()+”方法异常:"+ e.getMessage());        System.out.println(方法异常:");    }    @After("execution( public int com.mashibing.inter.MyCalculator.*(int,int))")    public static void end(){//        System.out.println(method.getName()+”方法的执行已经结束...");        System.out.println(”方法的执行已经结束...");    }}

  1. 打开基于注释的AOP功能

<context:component-scan base-package="com.mashibing"></context:component-scan>    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

  • PS: 在spring容器中,如果有接口,则使用jdk自带的动态代理,如果没有接口,则使用cglib动态代理。 早期cglib比jdk快,目前差不多

执行顺序2. 执行顺序

  • 1、正常执行:@BeforeSpring笔记_System@AfterSpring笔记_System@AfterReturning
  • 2、异常执行:@BeforeSpring笔记_System@AfterSpring笔记_System@AfterThrowing
  1. 获取方法名、参数和结果
  1. 方法名和参数

@Before("execution( public int com.mashibing.inter.MyCalculator.*(int,int))")public static void start(JoinPoint joinPoint){    Object[] args = joinPoint.getArgs();    String name = joinPoint.getSignature().getName();    System.out.println(name+该方法开始实施,参数是:"+ Arrays.asList(args));}

  1. 结果值

@AfterReturning(value = "execution( public int com.mashibing.inter.MyCalculator.*(int,int))",returning = "result")public static void stop(JoinPoint joinPoint,Object result){    String name = joinPoint.getSignature().getName();    System.out.println(name+“方法执行完成,结果是:”+result);}

  1. 异常

@AfterThrowing(value = "execution( public int com.mashibing.inter.MyCalculator.*(int,int))",throwing = "exception")public static void logException(JoinPoint joinPoint,Exception exception){    String name = joinPoint.getSignature().getName();    System.out.println(name+“方法异常:”+exception);}

  1. 使用Spring AOP时,可修改方法的修改符和返回值,不能修改参数类型
  2. AOP示例基于配置:aop.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: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/aop       http://www.springframework.org/schema/aop/spring-aop.xsd">    <bean id="logUtil" class="com.mashibing.util.LogUtil"></bean>    <bean id="securityUtil" class="com.mashibing.util.SecurityUtil"></bean>    <bean id="myCalculator" class="com.mashibing.service.MyCalculator"></bean>    <!--配置aop-->    <aop:config>        <aop:pointcut id="globalPoint" expression="execution( Integer com.mashibing.service.MyCalculator.*(..))"/>        <!--声明切面-->        <aop:aspect ref="logUtil">            <!--提取通用表达式-->            <aop:pointcut id="myPoint" expression="execution( Integer com.mashibing.service.MyCalculator.*(..))"/>            <!--使用哪些方法来定义通知?-->            <aop:before method="start" pointcut-ref="myPoint"></aop:before>            <aop:after method="logFinally" pointcut-ref="myPoint"></aop:after>            <aop:after-returning method="stop" pointcut-ref="myPoint" returning="result"></aop:after-returning>            <aop:after-throwing method="logException" pointcut-ref="myPoint" throwing="e"></aop:after-throwing>            <aop:around method="around" pointcut-ref="myPoint"></aop:around>        </aop:aspect>        <aop:aspect ref="securityUtil">            <aop:before method="start" pointcut-ref="globalPoint"></aop:before>            <aop:after method="logFinally" pointcut-ref="globalPoint"></aop:after>            <aop:after-returning method="stop" pointcut-ref="globalPoint" returning="result"></aop:after-returning>            <aop:after-throwing method="logException" pointcut-ref="globalPoint" throwing="e"></aop:after-throwing>            <aop:around method="around" pointcut-ref="globalPoint"></aop:around>        </aop:aspect>    </aop:config></beans>

3.一些相关概念1. AOP的核心概念和术语

名称

解释

Join连接点 point

在每种方法中可以填写额外代码的地方,在方法中可以嵌入的地方\*方法的数量

Pointcut切入点

该方法实际切入代码的地方是连接点的子集

切面Aspect

将要嵌入的代码包装成单独的类别,并添加@Aspect注释,称为切面

通知Advice

在截面上的某个特定点执行动作

2. 通知类型

前置通知 Before Advice: 执行方法前执行后返回通知 After returning advice: 方法返回结果后执行 后置异常通知(程序终端将无法执行) After throwing advice: 方法抛出异常后,执行后置通知 After (finally) advice: 方法执行完成后执行 环绕通知(无论如何均匀执行) (Around Advice): 方法前后执行

3. AOP应用场景
  • 日志管理
  • 权限认证
  • 安全检查
  • 事务控制
4. 通知执行顺序:

@Before -> @After -> @Afterreturning或@Before -> @After -> @AfterThrowing

若使用环绕通知@Around,则

  • 正常结束:环绕前置通知: -> @Before -> 后置通知环绕 -> 环绕返回通知 -> @After -> @AfterReturning
  • 异常结束:环绕前置通知: -> @Before -> 围绕异常通知 -> 环绕返回通知 -> @After -> @AfterReturning
  • 如果要收到普通通知,需要异常抛出/br>执行顺序改为:环绕前置通知 -> @Before -> 围绕异常通知 -> 环绕返回通知 -> @After -> @Afterthrowin示例:

@Around("execution(public Integer com.mashibing.service.MyCalculator.*(Integer,Integer))")    public Object around(ProceedingJoinPoint pjp) throws Throwable {        Signature signature = pjp.getSignature();        Object[] args = pjp.getArgs();        Object result = null;        try {            System.out.println("log---通知start周围:"+signature.getName()+开始执行方法,参数为:"+Arrays.asList(args));            ///通过反射调用目标的方法相当于执行method.invoke(),可自行修改结果值            result = pjp.proceed(args);            System.out.println("log---stop环绕通知”+signature.getName()+执行方法结束);        } catch (Throwable throwable) {            System.out.println("log---围绕异常通知:"+signature.getName()+“异常”);            throw throwable;        }finally {            System.out.println("log---环绕返回通知:"+signature.getName()+方法返回结果为:"+result);        }        return result;    }

5. 多切面执行顺序:

根据首字母的排序,可以在切面类中添加注释@Order()注明指定顺序。理解

六、AOP声明事务1. 事务类型
  1. 编程事务直接在代码中添加处理事务的逻辑,可能需要显式调用begintranscation()、commit()、rollback()等事务管理方法
  2. 在配置文件中添加注释或直接定义声明式事务,将事务管理代码与业务方法分离,并以声明的形式管理事务
2. 简单使用
  1. 将事务管理引入xml
  1. 添加数据源

<context:component-scan base-package="com.mashibing"></context:component-scan><context:property-placeholder location="classpath:db.properties"></context:property-placeholder><bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">    <property name="username" value="${jdbc.username}"></property>    <property name="password" value="${jdbc.password}"></property>    <property name="driverClassName" value="${jdbc.driverName}"></property>    <property name="url" value="${jdbc.url}"></property></bean>

  1. 将事务管理引入容器

<!--配置事务管理器的bean对象--><bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">    <property name="dataSource" ref="dataSource"></property></bean><!--打开基于注释的事务管理器的配置--><tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>

  1. 在需要异常回滚的方法上添加注释@Transactional

@Transactional(isolation = Isolation.SERIALIZABLE)public void buyBook() throws FileNotFoundException {    map.put(1, 2);    bookDao.getPrice(1);    bookDao.updateBalance("zhangsan", 100);    bookDao.updateStock(1);    int i = 1/0;    new FileInputStream("aaa.txt");}

3. @Transcational注释详细信息
  1. 传播事务的特点 propagation表示不同事务之间的关系,即事务套事务

传播特性

描述

示例 M1 {M2();M3();}

REQUIRED

如果外层有正在运行的事务,内部事务将由外部事务管理。如果内部事务中有一个回滚,所有事务都将回滚;如果没有事务在运行,则启动新事务并在自己的事务中运行

情形1:

M2、M3: REQUIRED/br>M1被默认事务类型调用;M3出错时,M2也会回滚

情形2:

如果M1不是事务,那么M2、M3相互独立,如果M3出错回滚,M2不会回滚

REQUIRES_NEW

如果有事务在运行,挂起正在运行的事务,然后开始新的事务,在自己的事务中运行

情形1:

M1:事务 M2:REQUIRES_NEW M3:REQUIRED 如果M3出错,M2不会回滚

情形2:

M2:REQUIRED M3:REQUIRES_NEW 如果M3异常回滚,M2回滚

情形3:

M2:REQUIRES_NEW M3:REQUIRES_NEW 即使M3出错回滚,M2也不会回滚

SUPPORTS

若有事务运行,则在事务中运行,否则不能在事务中运行

情形1:

M1 非事务 M2:SUPPORTS 如果M2出错,M2不会回滚

情形2:

M1 事务 M2:SUPPORTS 如果M2出错,M2回滚

NOT_SUPPORTED

当前的方法不在事务中运行。如果有正在运行的事务,则将事务挂起

M1 事务 M2 NOT_SUPPORTED 如果M2出错,M2不会回滚

NEVER

当前的方法不能在事务中运行,如果有,则抛出异常

M1 事务 M2 NEVER 立即抛出异常

MANDATORY

必须在事务内运行,否则抛出异常

M1 非事务 M2 MANDATORY 异常

NESTED

如果有事务在运行,当前的方法应该在嵌套事务中运行,否则将启动新的事务

M1 {try{M2}; M3 }

情形1

M1 事务 M2 REQUIRED M3 事务, M2异常回滚,M3也回滚

情形2

M1 事务 M2 REQUIRES_NEW M3 事务, 即使M2异常回滚 M3也正常执行,不回滚

情形3

M1 事务 M2 NESTED M3 事务, 即使M2异常回顾,M3也正常执行不回滚

情形4

M1 事务 M2 REQUIRES_NEW M3 事务, M1异常(M3执行后), 则 M2不回滚 M3回滚

情形5

M1 事务 M2 NESTED M3 事务, M3实施后M1出现异常,M2回滚,M3回滚

  1. 事务隔离等级 isolation
  • DEFAULT 使用数据库中设置的隔离级别
  • READ_COMMITTED 读已提交
  • READ_UNCOMMITTED 读未提交
  • REPEATABLE_READ 可重复读
  • SERIALIZABLE 可序列化
  1. 事务的超时间 timeout默认单位秒,一旦方法执行超过此时间,抛出异常并触发事务的回滚
  2. 只读事务 在readonly事务执行过程中,其他事务(或自己)不得修改数据库中的数据,否则会抛出异常
  3. 设置什么异常不回滚数据? rollBackFor / rollbackForclasname示例: 如除0异常rollBackFor = {ArithmeticException.class}rollBackForClassName = {"java.lang.ArithmeticException"}
  4. 设置哪些异常回滚 noRollBackFor / norollbackForclasname默认显式抛出的异常不会回滚

基于配置模式的声明事务

<!--事务的配置-->  <!--声明一个事务管理器-->  <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">  <property name="dataSource" ref="dataSource"></property>  </bean>  <aop:config>  <aop:pointcut id="txPointcut" expression="execution(* com.mashibing.service.*.*(..))"/>  <!--事务建议-->  <aop:advisor advice-ref="myAdvice" pointcut-ref="txPointcut"></aop:advisor>  </aop:config>  <tx:advice id="myAdvice" transaction-manager="transactionManager">  <!--配置事务的属性-->  <tx:attributes>  <!--什么方法可以添加事务?-->  <tx:method name="*" propagation="REQUIRED" read-only="true" isolation="DEFAULT"/>  <tx:method name="updatePrice" propagation="REQUIRED"></tx:method>  <tx:method name="update*" propagation="REQUIRED"></tx:method>  </tx:attributes>  </tx:advice>

上一篇:

throw 和 throws 的区别

下一篇:

css Less基础