Spring学习笔记

  1. Bean的注入

    Spring的Ioc相当于容器,用来存放各个对象。

​ 对象的注入可以采用普通的Bean标签 也可以采用自动扫描包 但是要在类的前面加上注解 例如@Service

  • @Component

    value属性 : 用于指定 bean 的 id 。当我们不写时,他的默认值是当前类名,且首字母小写。

  • @Controller : 一般用于表现层的注解。

  • @Service : 一般用于业务层的注解。

  • @Repository: 一般用于持久层的注解。

如果需要对值初始化的话 可以直接在属性前面加@value()

  1. Bean的生命周期

​ bean 标签的 scope 属性就是用来指定 bean 的作用范围的

  • singleton : 默认值,单例的. (bean对象默认是单例模式) 创建容器的时候就创建了对象
  • prototype : 多例的. 可以在java类中直接配置 也可以在bean中配置属性 需要的时候就创建 不需要的时候java销毁
@Repository
@Scope("prototype")
public calss UserDao{
    public String hello(){
        return "hello";
    }
}

依赖注入

依赖注入也就是说当我们在一个类中需要使用另一个类的时候 就会用到

具体的注入方法:

  • 构造函数
  • set方法
  • 注解
  1. 构造函数注入的就是调用有参构造函数进行注入 使用的便签:constructor-arg
    <bean id = "accountService" class = "com.smallbeef.service.impl.AccountServiceImpl">
        <constructor-arg name="name" value="test"></constructor-arg>
        <constructor-arg name = "age" value="20"></constructor-arg>
        <constructor-arg name = "birthday" ref="now"></constructor-arg>
    </bean>

    <!--配置一个日期对象
        读取这个类名通过反射创建对象并存入spring容器中,我们可以通过id来使用它
    -->
    <bean id="now" class="java.util.Date"></bean>
  1. set注入 :这个就类似于前面的Bean中的属性赋值 就是将要注入的对象作为一个属性 在类中有set方法 在配置bean的时候就用ref进行注入 如果是普通的属性就value ,bean对象的话就用ref
    <bean id = "accountService" class = "com.smallbeef.service.impl.AccountServiceImpl">
        <property name="name" value="test"></property>
        <property name="age" value="20"></property>
        <property name="birthday" ref = "now"></property>
    </bean>

    <bean id="now" class="java.util.Date"></bean>
  1. 注解
@Autowired

作用: 自动按照类型注入。

出现位置:变量和方法上都可以

当使用注解注入属性时,set 方法可以省略。它只能注入其他 bean 类型。

在 Spring 容器查找,找到了注入成功。找不到 就报错。

当有多个类型匹配时,使用要注入的 对象变量名称 作为 bean 的 id

  • 只有一个相符合的bean时,直接匹配数据类型

  • 有多个相符合的bean时,先匹配数据类型,再将变量名称和bean的id进行匹配

    当变量名称找不到一样的 bean 的 id 的时候,就会报错。

    为解决变量名称和 bean 的 id 不匹配的情况,有了如下注解 Qualifier

@Qualifier

​ 作用: 在自动按照类型注入的基础之上,再按照 Bean 的 id 注入。

它在给成员变量注入时不能独立使用,必须和 @Autowire 一起使用;但是给方法参数注入时,可以独立使用

​ 属性: value:指定 bean 的 id。

@Resource

作用: 直接按照 Bean 的 id 注入。可以独立使用(相当于Autowired + Qualifier)。它也只能注入其他 bean 类型。

属性: name:指定 bean 的 id (可不写)。

集合类型的注入只能通过 XML 来实现

Spring的纯注解配置

  1. 可以使用==@configuration==注解,则可以让这个类代表XML文件
// 获取容器时需要使用 AnnotationApplicationContext(有 @Configuration 注解的类 .class)。 
ApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfiguration.class);
  1. 可以用标签==@componentScan==代替之前的xml文件中的自动扫描
@Configuration 
@ComponentScan("com.smallbeef") 
public class JDBCConfiguration { 
} 
  1. @Bean用来代替之前的xml中bean标签

    作用: 该注解只能写在方法上,表明把当前方法的返回值作为 bean 对象存入 Spring 容器中。

    属性: name:给当前 @Bean 注解方法创建的对象指定一个名称(即 bean 的 id)。 默认值是当前方法的名称

    细节:当我们使用注解配置方法时,如果方法有参数,Spring 框架会去容器中查找有没有相匹配的 bean 对象,查找方法和 AutoWired 一样。

/**
 * 连接数据库的配置类  
 */ 
@Configuration 
@ComponentScan("com.smallbeef") 
public class JDBCConfiguration {
    /**
     * 创建一个数据源,并存入 spring 容器中   
     * * @return   
     * */  
    @Bean(name="dataSource")  
    public DataSource createDataSource() {   
        try {    
            ComboPooledDataSource ds = new ComboPooledDataSource();    
            ds.setUser("root");    
            ds.setPassword("1234");    
            ds.setDriverClass("com.mysql.jdbc.Driver");
            ds.setJdbcUrl("jdbc:mysql:///spring_day02");    
            return ds;   
        } catch (Exception e) {    
            throw new RuntimeException(e);   
        }  
    }
    /**
     * 创建一个 QuerryRunner对象,并且也存入 spring 容器中   
     * * @param dataSource   
     * * @return   
     * */  
    @Bean(name="dbAssit")  
    public  DBAssit createDBAssit(DataSource dataSource) {   
        return new  DBAssit(dataSource);  
    }  
} 
  1. 使用==@Import==注解导入其他的配置类

@Import 导入其他配置类

作用:用于导入其他配置类@Import 注解的类就是主配置类。在引入其他配置类时,其他子配置类可以不用再写 @Configuration 注解。当然写上也没问题。

属性: value[]:用于指定其他配置类的字节码。

举个例子:大的 SpringConfiguration 类利用 @Import 包含小的 JDBCConfiguration 配置类,这样 AnnotationConfigApplicationContext 直接加载大的配置类,就会把这些小的配置类也都加载进来

@Configuration //在 AnnotationConfigApplicationContext中做参数时可以不写该注解
@ComponentScan(basePackages = "com.smallbeef.spring") 
@Import({ JdbcConfig.class,xxxxxConfig.class, xxxxConfig.class}) 
public class SpringConfiguration { 

} 
 
public class JdbcConfig{ 

} 

-----------------------------------------------------

// 直接加载大配置类即可
ApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfiguration.class);
 
  1. @propertySouerce加载.pro文件配置

    作用:用于加载 .properties 文件中的配置。例如我们配置数据源时,可以把连接数据库的信息写到 properties 配置文件中,就可以使用此注解指定 properties 配置文件的位置。

    属性: value[]:用于指定 properties 文件位置。如果是在类路径下,需要写上 classpath:

@Configuration
@ComponentScan(basePackages = "com.smallbeef.spring") 
@Import(JdbcConfig.class) 
@PropertySource("classpath:jdbcConfig.properties")
public class SpringConfiguration { 

} 

纯注解实现Ioc

注解类

package com.swpu.configTest;
import com.sun.xml.internal.bind.v2.model.core.ID;
import com.swpu.Entity.Student;
import com.swpu.Entity.Teacher;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
/**
 * 功能描述:
 * @Author: ygq
 * @Date: 2021/6/29 21:02
 */
@Configuration
@ComponentScan("com.swpu.Entity")
public class TestAnnonation {
    @Bean(name = "student")
    public Student GetStu(){
        return new Student();
    }
    @Bean(name = "teacher")
    public Teacher GetTea(){
        return new Teacher();
    }
}

实体类:

package com.swpu.Entity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
/**
 * 功能描述:
 * @Author: ygq
 * @Date: 2021/6/29 20:59
 */
@Component
public class Student {
    @Value("zs")
    private String name;
    @Value("12")
    private int id;
    @Autowired
    private Teacher teacher;
    public Student() {
    }
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", id=" + id +
                ", teacher=" + teacher +
                '}';
    }
    public Student(String name, int id, Teacher teacher) {
        this.name = name;
        this.id = id;
        this.teacher = teacher;
    }
}

package com.swpu.Entity;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.stereotype.Component;
/*
 * 功能描述:
 * @Author: ygq
 * @Date: 2021/6/29 20:59
 */
@Component
public class Teacher {
    @Value("lisi")
    private String name;
    @Value("teacher")
    private String job;
    @Value("12")
    private int age;
    public Teacher() {
    }
    public void CheckWork(){
        System.out.println("检查作业");
    }
    public Teacher(String name, String job, int age) {
        this.name = name;
        this.job = job;
        this.age = age;
    }
    @Override
    public String toString() {
        return "Teacher{" +
                "name='" + name + '\'' +
                ", job='" + job + '\'' +
                ", age=" + age +
                '}';
    }
}




main方法

ApplicationContext applicationContext = new AnnotationConfigApplicationContext(TestAnnonation.class);
Teacher teacher = (Teacher)applicationContext.getBean("teacher");
Student bean = applicationContext.getBean(Student.class);
System.out.println(teacher);
System.out.println(bean);

Ioc源码分析

引言

spring-context 会自动将 spring-core、spring-beans、spring-aop、spring-expression 这几个基础 jar 包带进来。

public static void main(String[] args) {
    ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationfile.xml");
}

上面是启动一个Spring容器的语句,意思就是在类路径下寻找一个指定的xml文件,然后根据这个xml文件生成一个Ioc容器的实例

1

可以看到,ClassPathXmlApplicationContext 兜兜转转了好久才到 ApplicationContext 接口,同样的,我们也可以使用绿颜色的 FileSystemXmlApplicationContextAnnotationConfigApplicationContext 这两个类。基于注解的话就使用后面这个类

启动过程

Ioc的启动过程

img

SpringAop

面向切面编程 降低耦合度

不改变源代码实现新功能的添加

底层是基于动态代理实现,其中有两种情况的动态代理

  1. 有接口的动态代理(JDK)创建实现类的代理对象
image-20210630105338729
  1. 无接口的(CGLib)创建当前类的子类的代理对象
image-20210630105311898
JDK动态代理概述

JDK实现的动态代理是有接口的,所以我们需要创建一个接口类(这个类里面的方法需要被别人去实现),一个接口实现类。然后通过Proxy类中方法创建一个新的代理对象实例。代理对象可以增强方法

Object newProxyInstance(ClassLoader loader,   //类加载器 ClassLoader
                        Class<?>[] interfaces,//委托类实现的接口 数组,至少需要传入一个接口进去
                        InvocationHandler h)  //调用的 InvocationHandler 实例处理接口方法 也就是实现了invocationhandler的一个类(这个类中的invoke方法就是实现了对方法的增强的)

创建代理对象的时候需要强制转换 前面的类型就是接口的类型

重要的是实现invocationhandler接口的这个类,在这个类中首先应该传递过去一个委托类对象 因为代理就是要把原来的方法进行增强 ,这里一般采用构造方法传递

传递之后,在这个类中实现下面的方法

public Object invoke(Object proxy, Method method, Object[] args)
  //参数Method可以通过反射调用委托类中的方法
  //args是方法的参数

通过method.invoke(obj, args);方法可以直接调用委托类中的方法(注意 这里不是接口 实现类)这个方法的返回值就是源方法的返回值,对象就是源对象 参数就是方法的参数。

具体实例
  1. 接口类

    package com.swpu.JDKProxy;
    /**
     * 功能描述:
     * 接口类 包含了两个方法
     * @Author: ygq
     * @Date: 2021/6/30 10:59
     */
    public interface UserDao {
        public int add(int a,int b);
        String update(String id);
    }
    
  2. 实现类

    package com.swpu.JDKProxy;
    /**
     * 功能描述:
     *
     * @Author: ygq
     * @Date: 2021/6/30 11:00
     */
    public class UserDaoImpl implements UserDao {
        @Override
        public int add(int a, int b) {
            return a+b;
        }
        @Override
        public String update(String id) {
            return id;
        }
    }
    
  3. 实现了invocationHandler接口的类

    class UserDaoProxy implements InvocationHandler {
        //创建的是谁的代理对象 就把谁的对象传递过来 这里就是UserDaoImpl 因为是要把它的方法进行增强
        // 有参构造传递
        private Object obj;
    
        public UserDaoProxy(Object obj) {
            this.obj = obj;
        }
        // 增强的逻辑
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            //方法之前
            System.out.println("Before method" + method.getName() + "传递的参数" + Arrays.toString(args));
            //被增强的方法执行  invoke方法返回值就是源方法的返回值
            Object invoke = method.invoke(obj, args);
            System.out.println("增强方法之后执行" + obj);
            System.out.println("invoke的值是:" + invoke);
            return invoke; //将原来的方法的返回值返回(如果有就返回)
        }
    
  4. 代理类

    public class JdkProxy {
        public static void main(String[] args) {
            UserDaoImpl userDao = new UserDaoImpl(); //委托类的实例对象 不是接口 接口不可以实例化
            Class[] interfaces = {UserDao.class};//委托类的数组
           // 将生成的代理对象强制转换成委托类 
            UserDao o = (UserDao) Proxy.newProxyInstance(JdkProxy.class.getClassLoader(), interfaces, new UserDaoProxy(userDao));
            System.out.println(o.add(1, 2));
            System.out.println(o.update("Hello"));
        }
    }
    

    AOP术语

    1. 连接点 :类里面的哪些方法可以被增强 这些方法就是连接点
    2. 切入点: 实际被真正增强的方法就是切入点 要增强谁谁就是切入点
    3. 通知(增强):实际增强的逻辑部分就是通知
      • 前置通知:方法前面要执行的
      • 后置通知:方法后面要执行的
      • 环绕通知:方法前后都要执行的
      • 异常通知:出现异常要执行的通知
      • 最终通知:类似于try catch finally中的finally 无论怎样都会执行
    4. 切面:是动作, 把通知应用到切面的过程
    AOP操作

    在Spring框架中一般基于AspectJ实现AOP操作

    AspectJ是一个独立于Spring框架的AOP框架,一般两个结合进行·AOP操作

    可以使用XML实现 也可以使用基于注解 大多数是使用注解

    切入点表达式

    • 作用:知道对哪个类的那个方法进行增强
    • 语法结构:execution(【权限修饰符】【返回类型】【类全路径】【方法名称】(【参数列表】))

例如 对com.swpu.dao.UserDao中的Add方法进行增强 权限修饰符可以用*代替

execution(*com.swpu.dao.UserDao.Add(…)) 方法中(…)代表参数

对com.swpu.dao.UserDao中的所有方法进行增强

execution(❤com.swpu.dao.UserDao.*(…))

AspectJ注解方式实现AOP

进行通知的配置:

  1. 在Spring配置文件中,开启注解扫描
  2. 使用注解创建User和UserProxy
  3. 在增强类上面添加注解@Aspect
  4. 在Spring配置文件中开启生成的代理对象
实例
  1. Spring.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:context="http://www.springframework.org/schema/context"
       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-4.2.xsd
    http://www.springframework.org/schema/aop
    http://www.springframework.org/schema/aop/spring-aop.xsd">  <!--这个必须是偶数个-->
<bean id="user" class="com.swpu.pojo.User" scope="prototype">
   <property name="name" value="zs"></property>
   <property name="pwd" value="z123"></property>
   <property name="id" value="1"></property>
</bean>
<!--开启注解扫描-->
<context:component-scan base-package="com.swpu.AOPTest"></context:component-scan>
<!--   开启AspectJ生成代理对象-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>

</beans>
  1. UserTest类 记得加注解
package com.swpu.AOPTest;

import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
/**
 * 功能描述:
 * @Author: ygq
 * @Date: 2021/6/30 14:58
 */
@Component
public class UserTest {
    public void add(){
        System.out.println("Add方法执行");
    }
}
  1. UserProxy类

    package com.swpu.AOPTest;
    
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.After;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    import org.springframework.stereotype.Component;
    
    /**
     * 功能描述:
     *
     * @Author: ygq
     * @Date: 2021/6/30 14:59
     */
    @Component
    @Aspect
    public class UserProxy {
        @Before(value = "execution(* com.swpu.AOPTest.UserTest.add(..))")
        public void Before(){
            System.out.println("Before执行");
        }
    
        @After("execution(* com.swpu.AOPTest.UserTest.add(..))")
        public void After(){
            System.out.println("After");
        }
    
        @Around("execution(* com.swpu.AOPTest.UserTest.add(..))")
        public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
            System.out.println("环绕前");
            proceedingJoinPoint.proceed();
            System.out.println("环绕之后");
        }
    }
    
  2. main方法 这里获取的对象是原来的委托类 而不是代理类

    public class Test {
        public static void main(String[] args) {
            ApplicationContext applicationContext= new ClassPathXmlApplicationContext("spring.xml");
            UserTest bean = applicationContext.getBean(UserTest.class);
            bean.add();
        }
    }
    

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-u9lkgWt9-1625053852172)(C:\Users\25699\AppData\Roaming\Typora\typora-user-images\image-20210630153654623.png)]

SpringAOP相同的切入点抽取

相同的切入点可以抽取出来 用pointCut注解表示 写在方法上面

package com.swpu.AOPTest;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
/**
 * 功能描述:
 *
 * @Author: ygq
 * @Date: 2021/6/30 14:59
 */
@Component
@Aspect
@Order(1) //设置优先级 多个增强类的时候要设置优先级的时候使用这个注解
public class UserProxy {
     //抽取相同的切入点
    @Pointcut(value ="execution(* com.swpu.AOPTest.UserTest.add(..))" )
    public void pointDemo(){}
    
    @Before(value = "pointDemo()")
    public void Before(){
        System.out.println("Before执行");
    }

    @After(value = "pointDemo()")
    public void After(){
        System.out.println("After");
    }

    @Around(value = "pointDemo()")
    public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("环绕前");
        proceedingJoinPoint.proceed();
        System.out.println("环绕之后");
    }
}

jdbcTemplate

什么是jdbcTemplate:Spring框架对jdbc的模板 可以很方便的实现对数据的增删改操作

准备工作

  1. 导入依赖

    <!--    数据库连接-->
        <dependency>
          <groupId>mysql</groupId>
          <artifactId>mysql-connector-java</artifactId>
          <version>8.0.19</version>
        </dependency>
    <!--    事务-->
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-tx</artifactId>
          <version>5.2.4.RELEASE</version>
        </dependency>
    <!--    jdbc依赖-->
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-jdbc</artifactId>
          <version>5.2.4.RELEASE</version>
        </dependency>
        <!-- 数据库连接池 -->
        <dependency>
          <groupId>com.mchange</groupId>
          <artifactId>c3p0</artifactId>
          <version>0.9.5.2</version>
        </dependency>
    
  2. 在Spring配置文件中配置好数据库连接池

    <context:property-placeholder location="classpath:db.properties"/>
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
       <!-- 配置连接池属性 -->
       <property name="driverClass" value="${jdbc.driver}"/>
       <property name="jdbcUrl" value="${jdbc.url}"/>
       <property name="user" value="${jdbc.username}"/>
       <property name="password" value="${jdbc.password}"/>
       <!-- c3p0连接池的私有属性 -->
       <property name="maxPoolSize" value="30"/>
       <property name="minPoolSize" value="10"/>
       <!-- 关闭连接后不自动commit -->
       <property name="autoCommitOnClose" value="false"/>
       <!-- 获取连接超时时间 -->
       <property name="checkoutTimeout" value="10000"/>
       <!-- 当获取连接失败重试次数 -->
       <property name="acquireRetryAttempts" value="2"/>
    </bean>
    
  3. 创建jdbcTemplate对象

    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
      <property name="dataSource" ref="dataSource"></property>
    </bean>
    
  4. 创建Service类,创建Dao类,在Dao类注入jdbcTemplate对象 注意SQL语句中?用来占位 前面是语句 后面就是这个语句中的参数

    package com.swpu.Dao;
    import com.swpu.bookEn.Book;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.jdbc.core.JdbcTemplate;
    import org.springframework.stereotype.Repository;
    
    /**
     * 功能描述:
     *  Dao
     * @Author: ygq
     * @Date: 2021/6/30 15:56
     */
    @Repository
    public class bookDaoImpl implements bookDao {
    
        @Autowired
        private JdbcTemplate jdbcTemplate;
    
        @Override
        public void add(Book book) {
            jdbcTemplate.update("insert into book values(?,?,?)",book.getName(),book.getId(),book.getDetail());
        }
    }
    
    
    package com.swpu.Service;
    import com.swpu.Dao.bookDaoImpl;
    import com.swpu.bookEn.Book;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    
    /**
     * 功能描述:
     *
     * @Author: ygq
     * @Date: 2021/6/30 15:56
     */
    @Service
    public class bookService {
        @Autowired
        private bookDaoImpl bookDaoImpl;
        public void add(Book book){
            bookDaoImpl.add(book);
        }
    }
    
    public class jdbcTest {
        public static void main(String[] args) {
            ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");
            bookService bean = ac.getBean(bookService.class);
            bean.add(new Book("java",1,"testJava"));
        }
    }
    
    

Spring中的事务操作

什么是事务:事务是数据操作的最基本单元,逻辑上的一组操作,要么都成功,要么都失败

典型场景:银行转账

事务的特性(ACID)

  • 原子性 :不可分割,要么成功要么失败
  • 一致性 :操作前后数量不变(转账的时候前后钱不变)
  • 隔离性 :多事务操作不会相互产生影响
  • 持久性:修改之后会不会改变
事务操作场景搭建
  1. 创建数据库表

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-k6j0Mtx9-1625053852191)(C:\Users\25699\AppData\Roaming\Typora\typora-user-images\image-20210630164205386.png)]

  2. 创建Service Dao 对象和注入关系

package com.swpu.Dao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
/**
 * 功能描述:
 *
 * @Author: ygq
 * @Date: 2021/6/30 16:45
 */
@Repository
public class UserDaoImpl implements UserDao {

    @Autowired
    private UserDao userDao;
    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Override
    public void addMoney() {
        String sql = "update account set money = money+? where username = ?";
        jdbcTemplate.update(sql,100,"mary");
    }

    @Override
    public void subMoney() {
        String sql = "update account set money = money-? where username = ?";
        jdbcTemplate.update(sql,100,"lucy");
    }

}



package com.swpu.Service;
import com.swpu.Dao.UserDaoImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * 功能描述:
 *
 * @Author: ygq
 * @Date: 2021/6/30 16:44
 */
@Service
public class UserService {
    @Autowired
    private UserDaoImpl userDao;
    public void changeMoney(){
        userDao.subMoney();
        userDao.addMoney();
    }
}

  1. 出错

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sZP0p09e-1625053852195)(C:\Users\25699\AppData\Roaming\Typora\typora-user-images\image-20210630165513362.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1UeAtIqm-1625053852208)(C:\Users\25699\AppData\Roaming\Typora\typora-user-images\image-20210630165524633.png)]

  1. 开启事务

有两种方式开启事务 编程式 声明式(常用) 事务一般在Service中

声明式事务管理:

  • 注解
  • xml

在Spring进行声明式事务管理 底层使用AOP原理

Spring事务管理API:

  1. 提供一个接口 代表事务管理器 这个接口针对不同的框架有不同的实现类

    事务操作(注解声明式事务管理)

    <!--   创建事务管理器实例对象-->
       <bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager" id="dataSourceTransactionManager">
          <property name="dataSource" ref="dataSource"></property>
       </bean>
    

​ 在xml中添加配置 开启事务注解 xmlns:tx=“http://www.springframework.org/schema/tx”

http://www.springframework.org/schema/tx
http://www.springframework.org/schema/beans/spring-tx.xsd



<!--   开启事务注解-->
   <tx:annotation-driven transaction-manager="dataSourceTransactionManager"></tx:annotation-driven>
  1. 添加注解 可以在方法(带表该方法添加事务 加到类就是整个类的所有事务加方法)
@Service
@Transactional
public class UserService {
    @Autowired
    private UserDaoImpl userDao;
    public void changeMoney(){
            userDao.subMoney();
            //模拟异常
            int i = 100/0;
            userDao.addMoney();
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值