Spring必知必会——一篇文章了解Spring原理和实现

Spring必知必会

本文通过总结Spring相关教学视频和面试题,从概念和实战简单的回顾了Spring学习过程,适合入门和复习。

1.概念

1.1 基本概念

1.1.1 什么是Spring
  • Spring是一个轻量级Java开发框架 。

  • 目的是解决企业级应用开发的业务逻辑层和其他各层的耦合问题,即解决企业级应用开发的复杂性。

  • 两个核心:控制反转(IOC)和面向切面编程(AOP)

1.1.2 Spring优点
  • 方便解耦,简化开发
  • 提供面向切面编程,方便实现对程序进行权限拦截、运行监控等功能
  • 内部提供了对各种优秀框架的直接支持
  • 降低JavaEE API的使用难度

1.2 控制反转

1.2.1 概念
  • 含义:控制反转把传统上由程序代码直接操控的对象的调用权交给容器,通过容器来实现对象组件的装配和管理。即对组件对象控制权的转移,从程序代码本身转移到了外部容器。

  • 作用:管理对象的创建和依赖关系的维护

  • 优点:降低代码量;易于测试;降低侵入性;支持加载服务时的饿汉式初始化和懒加载。

  • 依赖注入:是控制反转的实现方式,代码不直接组装你的组件和服务,而在配置文件里描述哪些组件需要哪些服务,由容器负责组装。

1.2.2 Spring IOC容器
  • 作用:负责创建对象,管理对象,装配对象, 配置对象,管理对象的生命周期。

1.3 面向切面编程

  • 详见第三章

2.Bean管理

2.1 xml方式

2.1.1 创建对象
  • 在spring配置文件中,使用bean标签创建对象。提供对象id和类路径和类名

    <bean id="ObjectName" class="package.ClassName"></bean>
    
2.1.2 注入基本属性
  • 根据set方法,设置各变量的值

    <bean id="ObjectName" class="package.ClassName">
        <property name="variableName" value="value"></property>
    </bean>
    
  • 根据构造器参数,设置各变量的值

    <bean id="ObjectName" class="package.ClassName">
        <constructor-arg name="variableName" value="value"></property>
    </bean>
    
  • 使用p名称空间,结合set方法方便注入

    <beans xmlns:p="http://www.springframework.org/schema/p">
        <bean id="ObjectName" class="package.ClassName" p:variableName="value"></bean>   
    </beans>
    
2.1.3 注入字面量
  • null

    <bean id="ObjectName" class="package.ClassName">
        <property name="name"><null/></property>
    </bean>
    
  • 特殊符号,使用<![CDATA[...]]>,将特殊符号包含

    <bean id="ObjectName" class="package.ClassName">
        <property name="name">
           <value><![CDATA[<<special>>]]></value>
        </property>
    </bean>
    
2.1.4 注入对象
  • 注入外部bean

    <bean id="ObjectName" class="package.ClassName">
        <property name="objectName2" ref="value"></property>
    </bean>
    <bean id="value" class="package.ClassName2"></bean>
    
  • 注入内部bean(一个bean仅被当做另一个bean的属性)

    <bean id="ObjectName" class="package.ClassName">
        <property name="variableName">
            <bean id="ObjectName2" class="package.ClassName2">
                <property name="variableName2" value="value2"></property>
            </bean>
        </property>
    </bean>
    
    
  • 级联赋值,即直接对关联对象的某个属性赋值,需要在本类中添加get方法返回关联对象

    private AsClass asObject;
    public AsClass getAsClass {return asObject;}
    
    <bean id="ObjectName" class="package.ClassName">
        <property name="asObject" ref="value"></property>
        <property name="asObject.variableName" value="value2"></property>
    </bean>
    <bean id="value" class="package.ClassName2"></bean>
    
  • 注入数组和集合

    • 数组

      <bean id="ObjectName" class="package.ClassName">
          <property name="arrayName">
              <array>
                  <value>value1</value>
                  <value>value2</value>
              </array>
          </property>
      </bean>
      
    • 列表list

      <bean id="ObjectName" class="package.ClassName">
          <property name="listName">
              <list>
                  <value>value1</value>
                  <value>value2</value>
              </list>
          </property>
      </bean>
      
    • 映射map

      <bean id="ObjectName" class="package.ClassName">
          <property name="mapName">
              <map>
                  <entry key="key1" value="value1"></entry>
                  <entry key="key2" value="value2"></entry>
              </map>
          </property>
      </bean>
      
    • 集合set

      <bean id="ObjectName" class="package.ClassName">
          <property name="setName">
              <set>
                  <value>value1</value>
                  <value>value2</value>
              </set>
          </property>
      </bean>
      
    • 集合中设置对象,例如list

      <bean id="ObjectName" class="package.ClassName">
          <property name="listName">
              <list>
                  <ref bean="object1"></ref>
                  <ref bean="object2"></ref>
              </list>
          </property>
      </bean>
      <bean id="object1" class="package.ClassName2"></bean>
      <bean id="object2" class="package.ClassName2"></bean>
      
2.1.5 提取集合注入

可以将注入集合的部分抽取出来,方便使用。

  • 添加util名称空间

    <beans xmlns:util="http://www.springframework.org/schema/util"
           xsi:schemaLocation="http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
    
  • 提取集合

    <bean id="ObjectName" class="package.ClassName">
        <property name="listName" ref="listRef"></property>
    </bean>
    <util:list id="listRef">
        <value>value1</value>
        <value>value2</value>
    </util:list>
    
2.1.6 注入外部属性文件
  • 直接配置

    例如配置德鲁伊连接池

    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
        <property name="url" value="jdbc:mysql://localhost:3306/aDatabaseName"></property>
        <property name="username" value="aUsername"></property>
        <property name="password" value="aPassword"></property>
    </bean>
    
  • 通过properties文件

    <!--引入context名称空间-->
    <beans xmlns:util="http://www.springframework.org/schema/context"
           xsi:schemaLocation="http://www.springframework.org/schema/context 
                             http://www.springframework.org/schema/context/spring-context.xsd">
        <!--引入properties文件-->
        <context:property-placeholder location="classpath:druid.properties"/>
        <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
            <property name="driverClassName" value="${driverClassName}"></property>
            <property name="url" value="${url}"></property>
            <property name="username" value="${username}"></property>
            <property name="password" value="${password}"></property>
        </bean>
    </beans>
    
2.1.7 使用对象
  • 基本方法

    • 代码实现
    //加载配置文件
    ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
    //获取配置文件创建的对象
    ClassName objectName = context.getBean("objectName",ClassName.class);
    //调用方法
    objectName.aMethod();
    
    • ApplicationContext接口继承BeanFactory接口,与BeanFactory共为Spring的两大核心接口。
    • ApplicationContext的实现类
    类名描述
    FileSystemXmlApplicationContext参数为相对项目根路径
    ClassPathXmlApplicationContext参数为classpath路径
    WebXmlApplicationContext用于web应用的bean
  • 类的作用域(scope)

    • singleton:默认,即bean在每个IOC容器中只有一个实例,在加载配置文件时就会创建单实例对象。

    • prototype:一个bean的定义可以有多个实例,在加载配置文件时不创建对象,而是在调用getbean方法返回对象时创造对象。

    • 其他:request, session, global-session

    • 代码实现

      <bean id="ObjectName" class="package.ClassName" scope="prototype"></bean>
      
2.1.7 装配
  • 装备:在Spring容器中把bean组装到一起。

  • 自动装配:在Spring中,对象无需自己查找或创建关联的其他对象,而是由容器进行关联。

  • 自动装配的不足:

    • 基本数据类型、字面量、类字面量无法使用自动装配来注入。
    • 自动装配不如显示装配精确,装配依赖中若是出现匹配到多个bean,装配将会失败。
  • 自动装配类型

    • byType:通过参数类型自动装配(若有多个同类型的bean会报异常)
    • byName:通过bean名称进行装配(即property name与bean id匹配)
    • constructor:通过构造函数的参数根据byType装配
    • autodetect:自动探测,如果有构造方法,通过construct,否则使用byType。
    • no:默认方式,不进行自动装配
  • 代码实现

    <bean id="ObjectName" class="package.ClassName" autowire="byName"></bean>
    <!--若上类中有一属性名为propertyName则能够自动装配-->
    <bean id="propertyName" class="package.ClassName2"></bean>
    

2.2 注解方式

2.2.1 概念
  • 注解:代码特殊标记,可作用与类、方法和属性

  • 作用:通过注解的帮助进行Spring配置,简化xml配置。

  • 过程:

    1. 通过xml开启组件扫描,或创建配置类替代xml配置文件

    2. 在类上方添加对象注解

    3. 在类中需要装配的位置添加注解

2.2.2 组件扫描
  • 作用:对某个包或类启用注解

  • 基本实现:

    <context:component-scan base-package="anno"></context:component-scan>
    
  • filter:可设置仅扫描或不扫描哪些注解

    <context:component-scan base-package="anno" use-default-filters="false">		<context:include-filter type="annotation" expression="org.springframework.stereotype.Component"/>
    	<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>
    
2.2.3 配置类
  • 基本实现

    @Configuration
    @ComponentScan(basePackages={"anno"})
    public class SpringConfig{
        
    }
    
2.2.4 对象注解
  • 作用:把类标注为可以进行自动装配的类

  • 类型

    类型描述
    Component将类标记为bean,是任何Spring管理组件的通用构造型
    Controller将类标记为SpringMVC控制器
    Service适用与服务层类
    Repository适用于持久层(DAO)
2.2.5 属性注入
  • 类型

    类型描述
    AutoWired根据属性类型自动装配,
    Resource默认按照名称装配,找不到再根据类型装配
    Qualifier当有多个同类型的bean时,与AutoWired一同使用指定名称
    Value注入普通类型
  • 代码实现

    @Service
    public class UserService
    {
        @Autowired
        private UserDao userDao;
      
        @Resource(name="userDaoImpl")
        private UserDao userDao2;
        
        @Autowired
        @Qualifier(value = "userDaoImpl")
        private UserDao userDao2;
    
        @Value(value = "valueFromAnnotation")
        private String name;
    
2.2.6 其他注解
类型描述
Required表明bean属性必须在配置的时候设置,即决定是否强制注入,通常修饰set方法。
Scope声明bean的作用域

2.3 bean的生命周期

2.3.1 概念
  • 理解bean的生命周期可以帮助利用Spring提供的扩展点来自定义bean的创建过程。
2.3.2 过程
顺序过程描述
1bean实例化Spring启动,查找并加载需要被Spring管理的bean,进行bean的实例化
2bean属性注入Spring将值和bean的引用注入到对应的属性
3调用BeanNameAware.setBeanName()若实现该接口,将id传递给该方法
4调用BeanFactortyAware.setBeanFactory()若实现该接口,将BeanFactory容器传入
5调用ApplicationContextAware.setApplicationContext()若实现该接口,将bean所在应用上下文传入
6调用BeanPostProcessor.postProcessBeforeInitialization()若实现该接口,调用前置处理方法
7调用InitializingBean.afterPropertiesSet()若实现该接口,调用该方法
8调用自定义初始化方法(init-method)bean内声明的初始化方法
9调用BeanPostProcessor.postProcessAfterInitialization()若实现该接口,调用后置处理方法
bean可以使用了,直到被应用上下文销毁
10调用DisposableBean.destroy()若实现该接口,调用该方法
11调用自定义销毁方法(destroy-method)bean内声明的销毁方法
2.3.3 自定义方法
  • xml实现:在xml定义bean中的某个方法为初始化或销毁方法

    <bean id="ObjectName" class="package.ClassName"
          init-method="theInitMethod"
          destroy-method="theDestroyMethod"></bean>
    
  • 注解实现:在初始化和销毁方法前分别使用@PostConstruct@Predestroy

3.面向切面编程AOP

3.1 基本概念

3.1.1 名词解释
  • 连接点:指方法,是切面能够织入的位置,即能够被增强的方法。
  • 切入点:切面具体织入的位置
  • 通知:切面的工作,即增强的部分。
  • 切面:把通知引用到切入点的过程
  • 织入:将切面代码插入到目标对象的过程
3.1.2 面向切面编程
  • 含义:在运行时,动态地将代码切入到类的指定方法、指定位置上的编程思想。

  • 使用:把与业务无关但却对多个对象产生影响的公共行为和逻辑,抽取并封装为一个可重用的模块 。

  • 优点:减少系统中的重复代码,降低了模块间的耦合度,提高了系统的可维护性。

  • 用途:权限认证,日志,事务处理等。

3.2 动态代理

3.2.1 与AOP
  • Spring AOP基于动态代理实现

  • 动态代理表明AOP框架不会修改字节码,而是每次运行时在内存中临时为方法生成一个代理对象,这个代理对象包含了目标对象的全部方法,并且在切点做了增强处理,并回调原对象的方法。

  • 动态代理有JDK动态代理和CGLIB动态代理

3.2.2 JDK动态代理
  • 当目标对象是基于接口实现的,AOP框架会采用JDK动态代理。

  • 过程:

    1. 创建接口和实现类
    2. 通过实现InvocationHandler接口,并重写invoke方法创建代理对象
    3. 使用Proxy.newProxyInstance()返回增强的对象。
  • 简单实现

    public interface Addition
    {
        public int add(int a, int b);    
    }
    
    public class AdditionImpl implements Addition
    {
        @Override
        public int add(int a, int b)
        {
            return a + b;
        }
    }
    
    class AdditionProxy implements InvocationHandler{
        private Object obj;
        public AdditionProxy(Object obj){
            this.obj = obj;
        }
        @Override
        public Object invoke(Object proxy, Method method, Object[] args)  throws Throwable
        {
            System.out.println("在原方法之前执行");
            Object res = method.invoke(obj, args);
            System.out.println("在原方法之后执行");
            return res;
        }
    
    public class JDKProxy
    {
        public static void main(String[] args)
        {
            Class[] interfaces = {Addition.class};
            Addition addition = (Addition)Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new AdditionProxy(Addition));
           int result = addition.add(2,3);
           System.out.println("result: " + result);
        }
    }
    
3.2.3 CGLIB动态代理
  • 如果代理类没有实现接口,那么框架会选择使用CGLIB来动态代理目标类。
  • CGLIB是一个代码生成的类库,在运行时生成指定类的一个子类对象,并覆盖其中特定方法并添加增强代码,从而实现AOP。
3.2.4 动态代理与静态代理
  • 静态代理
    • 静态代理在编译阶段生成代理类,即在编译阶段将切面织入到字节码中,运行时就是增强之后的对象。
    • 优点:效率高
    • 代表:AspectJ
  • 动态代理
    • 每次运行时在内存中临时为方法生成一个代理对象
    • 代表:Spring AOP

3.3 使用

3.3.1 Spring AOP与AspectJ
  • Spring AOP:通过Spring IoC提供一个简单的AOP实现,以解决常见问题。但并不是完整的AOP解决方案,它只能用于Spring容器管理的bean。只支持方法连接点。

  • AspectJ:EcLipse发起的一个面向切面的框架,AspectJ定义了AOP语法,它有一个专门的编译器用来生成遵守Java字节编码规范的Class文件。支持多种连接点。

  • AspectJ独立于Spring,但是Spring使用了AspectJ样式的注解。

3.3.2 xml与注解实现
  1. 在xml中打开注解扫描,开启AspectJ生成代理对象

    <!--添加context和aop命名空间-->
    <beans xmlns:context="http://www.springframework.org/schema/context"
           xmlns:aop="http://www.springframework.org/schema/aop"
           xsi:schemaLocation="http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
    http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
    
        <!--注解扫描-->
        <context:component-scan base-package="aop"></context:component-scan>
        <!--生成代理对象-->
        <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
    </beans>
    
  2. 创建目标对象,并添加注解

    @Component
    public class User
    {
        public void create(){
            System.out.println("Create a user.");
        }
    }
    
  3. 创建代理对象,并添加通知

    @Component
    @Aspect
    public class UserProxy
    {
        @Before(value = "execution(* aop.User.create(..))")
        public void before(){
            System.out.println("before");
        }
    }
    
3.3.3 execution表达式
  • 作用:用于匹配方法执行的连接点

  • 完整格式

    execution(modifiers-pattern? ret-type-pattern declaring-type-pattern?name-pattern(param-pattern) throws-pattern?)

    类型是否必填内容
    修饰符public等,*表示任意
    返回值类型*表示所有类型
    类型声明
    名称包.类.方法
    参数列表()表示没有参数,(…)任意参数
    异常列表
3.3.4 通知类型
  • 五种类型

    注解类型作用
    @Before前置通知在目标方法执行前调用
    @AfterReturning后置通知在目标方法执行后调用,除非抛出异常
    @After最终通知在目标方法执行后调用
    @AfterThrowing异常通知在目标方法异常后调用
    @Around环绕通知在目标方法执行前后调用
  • 环绕通知实现

    @Around(value = "execution(* aop.User.create(..))")
    public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable
    {
        //执行前调用
        System.out.println("before around");
        //执行目标方法
        proceedingJoinPoint.proceed();
        //执行后调用
        System.out.println("after around");
    }
    
3.3.5 其他注解
  • Pointcut

    • 作用:对相同的切入点进行抽取,减少重复。

    • 内容:表达式和签名(方法)

    • 代码实现:

      @Pointcut(value = "execution(* aop.User.create(..))")
      public void  aPointCut(){
      }
      @Before(value = "aPointCut()")
      public void before(){
          System.out.println("before");
      }
      @After(value = "aPointCut()")
      public void after(){
          System.out.println("after");
      }
      
  • Order:在代理类上使用@order(int)可以表示代理类的执行顺序

3.3.6 纯注解实现
  • 通过创建配置类替代xml配置文件

    @Configuration
    @ComponentScan(basePackages={"aop"})
    @EnableAspectJAutoProxy(proxyTargetClass=true)
    public class SpringConfig{   
    }
    
3.3.7 xml实现
  • 在xml中创建类对象,并配置切入点和切面

    <bean id="user" class="aop.User"></bean>
    <bean id="userProxy" class="aop.UserProxy"></bean>
    
    <aop:config>
        <aop:pointcut id="aPointCut" expression="execution(* aop.User.create(..))"/>
        <aop:aspect ref="userProxy">
            <aop:before method="before" pointcut-ref="aPointCut"/>
        </aop:aspect>
    </aop:config>
    

4. JDBC

4.1 概念

4.1.1 Spring JDBC
  • Spring JDBC是Spring框架的模块之一,用于简化JDBC编程。
  • Spring JDBC负责数据库资源管理和错误处理。开发者只需声明 SQL 语句、调用合适的 Spring JDBC框架 API、处理结果集即可。
4.1.2 JDBCTemplate
  • JdbcTemplate 类是 Spring JDBC 的核心类,提供了一组操作 SQL 语句的 API。

4.2 使用

4.2.1 相关jar包
  • 数据库相关:druid, mysql-connector-java
  • Spring相关:spring-jdbc, spring-orm, spring-tx
4.2.2 配置文件
  1. 配置druid连接池

    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
        <property name="url" value="jdbc:mysql://localhost:3306/aDatabaseName"></property>
        <property name="username" value="aUsername"></property>
        <property name="password" value="aPassword"></property>
    </bean>
    
  2. 将数据源注入JdbcTemplate

    <bean id ="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">		<property name="dataSource" ref="dataSource"></property>
    </bean>
    
  3. 在DAO类中使用注解注入JdbcTemplate对象,进行增删改查等操作

4.2.3 JDBCTemplate基础操作
  • 类型

    方法名返回值(参数)描述
    executevoid(String sql)一般执行数据定义语言(DDL)
    execute<T> T (StatementCallback<T> action)
    updateint(String sql, Object…args)一般执行数据操作语言(DML),返回影响的行数
    batchUpdateint[](String sql, List<Object[]> batchArgs)添加多条记录
    queryForObject<T> T(String sql, RowMapper<T> rowMapper, Object…args)查询单条数据,并使用返回数据创建对象
    query<T> List<T>(String sql, RowMapper<T> rowMapper, Object…args)查询多条数据,并使用返回数据创建对象列表
  • 简单实现

    //添加数据
    String sql = "insert into `users` values(?,?,?)";
    int update = jdbcTemplate.update(sql, user.getUserId(), user.getUsername(), 	user.getPassword());
    //查询数据
    String sql = "select count(*) from `users`";
    Integer num = jdbcTemplate.queryForObject(sql,Integer.class);
    //通过查询返回对象
    String sql = "select * from `users` where id = ?";
    int id = 1;
    User user = jdbcTemplate.queryForObject(sql,new BeanPropertyRowMapper<User>(User.class),id);
    //批量操作
    List<Object[]> batchArgs = new ArrayList<>();
    batchArgs.add(new Object[]{1,"Amy","123"});
    batchArgs.add(new Object[]{2,"Bob","456"});
    String sql = "insert into `users` values(?,?,?)";
    int[] affected = jdbcTemplate.batchUpdate(sql,batchArgs);
    

4.3 事务

4.3.1 概念
  • Spring支持的事物管理类型

    • 编程式事务管理:通过编程方式管理事务。灵活性强但可维护性低。
    • 声明式事务管理:用注解和xml配置文件管理事务,即业务代码和事务管理分离。
  • Spring事务实现原理

    • Spring并不直接管理事务,而是提供了多种事务管理器,本质其实就是数据库对事务的支持 。
    • Spring事务管理器的接口是PlatformTransactionManager,为各个平台如JDBC、Hibernate等提供了对应的事务管理器。
  • 核心接口

    名称描述
    PlatformTransactionManager按照给定的规则执行提交回滚等操作
    TransactionDefinition定义了事务属性
    TransactionStatus事务运行状态,如是否提交、是否有保存点等
4.3.2 Spring事务属性

事务属性是事务的基本配置,描述了事务策略如何应用到方法上。主要定义在TransactionDefinition接口。

属性描述
传播行为(propagation behavior)当多事务同时存在时,Spring处理事务的行为。
主要解决业务层方法之间的相互调用的问题
隔离级别(isolation level)若干个并发的事务之间的隔离程度
是否超时(timeout)一个事务所允许执行的最长时间,超时则自动回滚事务
是否只读(read only)对事务性资源进行只读操作或者是读写操作
回滚规则出现异常时的回滚规则
4.3.3 传播行为
名称描述
PROPAGATION_REQUIRED0当前方法必须运行在事务中。如果当前事务存在,方法将会在该事务中运行,否则启动一个新的事务
PROPAGATION_SUPPORTS1如果当前存在事务,就加入该事务,如果当前不存在事务,就以非事务执行。
PROPAGATION_MANDATORY2该方法必须在事务中运行,如果当前事务不存在,则抛出异常。
PROPAGATION_REQUIRES_NEW3无论当前存不存在事务,都创建新事务。
PROPAGATION_NOT_SUPPORTED4以非事务方式执行操作,如果存在当前事务,就把当前事务挂起。
PROPAGATION_NEVER5以非事务方式执行,如果当前存在事务,则抛出异常。
PROPAGATION_NESTED6如果当前已经存在一个事务,那么该方法将会在嵌套事务中运行。嵌套的事务可以独立于当前事务进行单独地提交或回滚。如果当前事务不存在,那么其行为与REQUIRED一样。
4.3.4 隔离级别
名称描述
ISOLATION_DEFAULT-1默认值,使用底层数据库的默认隔离级别
ISOLATION_READ_UNCOMMITTED1读未提交。事务未提交前就可被其他事务读取(会出现幻读、脏读、不可重复读)
ISOLATION_READ_COMMITTED2读已提交。事务提交后才可被其他事务读取(会出现幻读和不可重复读)
ISOLATION_REPEATABLE_READ4可重复读。对同一字段的多次读取结果都是一致的(会出现幻读)
ISOLATION_SERIALIZABLE8序列化。
4.3.5 声明式事务管理实现
  1. 配置事务管理器

    • 使用xml配置文件配置

      <!--引入tx名称空间(此处省略其他已经引入的)-->
      <beans xmlns:tx="http://www.springframework.org/schema/tx"
             xsi:schemaLocation="http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
          <!--创建事务管理器-->
          <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></tx:annotation-driven>
      
      </beans>
      
    • 或使用配置类配置

      @Configuration
      @ComponentScan(basePackages="jdbcTemplate")
      @EnableTransactionManagement
      public class Config
      {
          //创建数据库连接池
          @Bean
          public DruidDataSource getDruidDataSource()
          {
              DruidDataSource dataSource = new DruidDataSource();
              dataSource.setDriverClassName("com.mysql.jdbc.Driver");
              dataSource.setUrl("jdbc:mysql://localhost:3306/xxxx");
              dataSource.setUsername("xxx");
              dataSource.setPassword("xxx");
              return dataSource;
          }
          
          //创建JdbcTemplate对象
          @Bean
          public JdbcTemplate getJdbcTemplate(DataSource dataSource)
          {
              JdbcTemplate jdbcTemplate = new JdbcTemplate();
              jdbcTemplate.setDataSource(dataSource);
              return jdbcTemplate;
          }
      
          //创建事务管理器
          @Bean
          public DataSourceTransactionManager getDataSourceTransactionManager(DataSource dataSource){
              DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
              transactionManager.setDataSource(dataSource);
              return transactionManager;
          }
      }
      
  2. 事务操作

    • 基于注解

      @Service
      @Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.REPEATABLE_READ)
      public class UserService
      {
          @Autowired
          private UserDao userDao;
      
          public void transfer(){
              userDao.out();
              userDao.in();
          }
      }
      
    • 或使用xml

      <!-- 配置事务通知 -->
       <tx:advice id="txAdvice" transaction-manager="transactionManager">
      	<tx:attributes>
            <tx:method name="transfer" propagation="REQUIRED"/>
          </tx:attributes>
      </tx:advice>
      
      <aop:config>
          <!-- 配置切入点 -->
          <aop:pointcut expression="execution(* jdbcTemplate.*(..))" id="pointCut"/>
          <!-- 配置切面 -->
          <aop:advisor advice-ref="txAdvice" pointcut-ref="pointCut"/>
      </aop:config>
      
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值