spring5总结

------------恢复内容开始------------

一、Spring框架概述

1、spring框架是一个轻量级的开源的java EE开发框架。

2、spring框架解决企业应用开发的复杂性。

3、spring有两个核心:IOC与AOP

(1) IOC:控制反转,把创建对象过程交给Spring管理。

(2) AOP:面向切面编程,不修改源代码情况下,进行功能增强。

1、Spring特点

(1)方便解耦,简化开发

(2)aop支持

(3)方便程序测试

(4)方便集成各种框架

(5)降低Java api使用难度

(6)方便进行事务处理

2、Spring版本选择

 

 

 

3、入门案例

  1. 下载spring
  2. idea 新建普通Java工程
  3. 导入spring 的jar包。(bean,core,context,core,expresstion+commons-logging)
  4. 写代码

 

 

 创建普通类,类里面创建普通方法。

public class user{
        public void add(){
               system.out.println("add ..............")
        }        
}

创建Spring配置文件,在配置文件中创建对象,新建base.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 http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!--配置user对象-->
    <bean id="user" class="com.sun.Entity.User" />
    
</beans>

测试类

 @org.junit.Test
    public void t1(){
        //1.加载spring的配置文件
        AbstractApplicationContext context = new ClassPathXmlApplicationContext("been.xml");
        //2.获取对象
        User user = context.getBean("user", User.class);
        System.out.println(user.toString());
        user.add();
    }

二、IOC容器

1、IOC底层原理

 控制反转,目的:降低耦合度,高内聚,低耦合。把对象创建和对象之间的调用过程,交给Spring进行管理。

​ xml解析、工厂模式,反射

 

 

 

 

 

 

 

 

 

2、IOC接口(BeanFactory)

  • ioc思想基于IOC容器完成,ioc容器底层就是对象工厂。
  • Spring提供了IOC容器实现的两种方式:两个接口
    • BeanFactory:IOC容器基本实现,是spring内部使用接口,不提供开发人员使用。加载配置文件时不会创建对象,使用对象时才会创建对象(懒汉式加载对象)。
    • ApplicationContext:BeanFatory的子接口,提供更多更强大的功能,一般供开发人员进行使用。加载配置文件时就创建对象(饥汉式加载对象)
  • ApplicationContext接口实现类
    • FileSystemXmlApplicationContext(“盘符路径(绝对路径)”)
    • ClassPathXmlApplicationContext(“src目录下类路径”)

3、IOC操作 Bean 管理

  1. 什么是Bean管理

  • Bean 管理指的是两个操作
    • Spring 创建对象
    • Spring 注入属性

      2. Bean 管理操作的两种方式

  

  • 基于xml配置文件方式实现
  • 基于注解方式实现

4、IOC操作 Bean 管理(基于xml)

  1. 基于xml方式创建对象

    (1) 在Spring配置文件中,使用Bean标签,标签里面添加对应属性,就可以实现对应对象创建
    (2) 在Bean标签有很多属性,常用的属性:id、class、name

    (3) 创建对象的时候,默认也是执行无参数构造方法

<!--配置user对象-->
    <bean id="user" class="com.sun.Entity.User" />
  1. 基于xml方式注入属性

    (1) DI:依赖注入,就是注入属性

  2. 第一种注入方式:使用set方法进行注入

    (1) 创建类,定义属性和对应的set方法

public class Book {
    private String bname;
    private String bauthor;

    public void setBname(String bname) {
        this.bname = bname;
    }

    public void setBauthor(String bauthor) {
        this.bauthor = bauthor;
    }

    @Override
    public String toString() {
        return "Book{" +
                "bname='" + bname + '\'' +
                ", bauthor='" + bauthor + '\'' +
                '}';
    }
}

  (2) 在Spring配置文件配置对象创建,配置属性注入

<!--配置文件通过set方法设置属性-->
    <bean id="book" class="com.sun.Entity.Book">
        <property name="bname" value="xhs"/>
        <property name="bauthor" value="zs"/>
    </bean>

 

 第二种注入方式:使用有参数构造进行注入

   (1) 创建类,定义属性,创建属性对应有参数构造方法

public class Orders {
    private String oname;
    private String addres;

    public Orders(String oname, String addres) {
        this.oname = oname;
        this.addres = addres;
    }

    @Override
    public String toString() {
        return "Orders{" +
                "oname='" + oname + '\'' +
                ", addres='" + addres + '\'' +
                '}';
    }
}

  (2) 在spring 配置文件中进行配置

<!--构造函数设置属性-->
    <bean id="orders" class="com.sun.Entity.Orders">
        <constructor-arg name="oname" value="bijiben"/>
        <constructor-arg name="addres" value="tianhe"/>
    </bean>

  (3) 测试

@org.junit.Test
    public void t3(){
        //1.加载spring的配置文件
        AbstractApplicationContext context = new ClassPathXmlApplicationContext("been.xml");
        //2.获取对象
        Orders orders = context.getBean("orders", Orders.class);
        System.out.println(orders.toString());
    }

      5、P名称空间注入(了解) 

  (1) 使用P名称空间注入,可以简化基于xml配置方式

  第一步 添加P名称空间在配置文件中

<?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:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!--p命名空间设置属性的方式-->
    <bean id="book" class="com.sun.Entity.Book" p:bname="xhs" p:bauthor="zs"/>
</beans>

6、IOC操作Bean管理(xml注入其他类型属性)

1、字面量

  (1) null值

    <bean id="book" class="com.sun.Entity.Book">
        <property name="bname" value="xhs"/>
        <property name="bauthor">
            <null></null>
        </property>
    </bean>

  (2) 属性值包含特殊符号

 <bean id="book" class="com.sun.Entity.Book">
        <property name="bname" value="&lt;北京&gt;"/>
        <property name="bauthor" >
            <value><![CDATA[<北京>]]></value>
        </property>
    </bean>

2、注入外部bean(使用引用,注入其他类的对象)

  (1) 创建两个类service类和dao类

  (2) 在service调用dao类的方法

  (3) 在spring配置文件中进行配置

 

public interface UserDao {
    public void add();
}

public class UserDaoImpl implements UserDao{
    @Override
    public void add() {
        System.out.println("UserDao add..............");
    }
}

public class UserService {
    private UserDao userDao;

    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    public void add(){
        System.out.println("UserService add........");
        userDao.add();
    }
}

been配置文件

<bean id="userService" class="com.sun.Entity.UserService">
        <property name="userDao" >
            <bean id="userDaoImpl" class="com.sun.Entity.UserDaoImpl"></bean>
        </property>
    </bean>

 

测试

@org.junit.Test
    public void t4(){
        //1.加载spring的配置文件
        AbstractApplicationContext context = new ClassPathXmlApplicationContext("been.xml");
        //2.获取对象
        UserService userService = context.getBean("userService", UserService.class);
        userService.add();
    }

7、IOC操作Bean管理(xml注入集合属性)

  1. 注入数组类型属性

  2. 注入List集合类型属性
  3. 注入Map集合类型属性

(1)创建类,定义数组、list、map、set类型属性,生成对应set方法

public class Stu {
    //数组
    private String[] courses;
    //集合
    private List<String> list;
    //Map
    private Map<String ,String> map;
    //set
    private Set<String> set;

    public void setCourses(String[] courses) {
        this.courses = courses;
    }

    public void setList(List<String> list) {
        this.list = list;
    }

    public void setMap(Map<String, String> map) {
        this.map = map;
    }

    public void setSet(Set<String> set) {
        this.set = set;
    }

    @Override
    public String toString() {
        return "Stu{" +
                "courses=" + Arrays.toString(courses) +
                ", list=" + list +
                ", map=" + map +
                ", set=" + set +
                '}';
    }
}

(2)在spring配置文件进行配置

<bean id="stu" class="com.sun.Entity.Stu">
        <property name="courses">
            <array>
                <value>java</value>
                <value>python</value>
            </array>
        </property>
        <property name="list">
            <list>
                <value>l</value>
                <value>v</value>
            </list>
        </property>
        <property name="map">
            <map>
                <entry key="key" value="val"/>
            </map>
        </property>
        <property name="set">
            <set>
                <value>1</value>
                <value>2</value>
            </set>
        </property>
    </bean>

测试

@org.junit.Test
    public void t5(){
        //1.加载spring的配置文件
        AbstractApplicationContext context = new ClassPathXmlApplicationContext("been.xml");
        //2.获取对象
        Stu stu = context.getBean("stu", Stu.class);
        System.out.println(stu.toString());
    }

 

  4.在集合里设置对象类型值

public class Stu {

    //集合
    private List<Book> list;

    public void setList(List<Book> list) {
        this.list = list;
    }

    @Override
    public String toString() {
        return "Stu{" +
                "list=" + list +
                '}';
    }
}

public class Book {
    private String bname;
    private String bauthor;

    public void setBname(String bname) {
        this.bname = bname;
    }

    public void setBauthor(String bauthor) {
        this.bauthor = bauthor;
    }

    @Override
    public String toString() {
        return "Book{" +
                "bname='" + bname + '\'' +
                ", bauthor='" + bauthor + '\'' +
                '}';
    }
}
<bean id="stu" class="com.sun.Entity.Stu">
        <property name="list">
            <list>
                <ref bean="book1"/>
                <ref bean="book2"/>
            </list>
        </property>
    </bean>
    <!--配置文件设置属性-->
    <bean id="book1" class="com.sun.Entity.Book">
        <property name="bname" value="&lt;北京&gt;"/>
        <property name="bauthor" >
            <value><![CDATA[<北京>]]></value>
        </property>
    </bean>
    <bean id="book2" class="com.sun.Entity.Book">
        <property name="bname" value="&lt;深圳&gt;"/>
        <property name="bauthor" >
            <value><![CDATA[<深圳>]]></value>
        </property>
    </bean>

测试

@org.junit.Test
    public void t5(){
        //1.加载spring的配置文件
        AbstractApplicationContext context = new ClassPathXmlApplicationContext("been.xml");
        //2.获取对象
        Stu stu = context.getBean("stu", Stu.class);
        System.out.println(stu.toString());
    }

8、IOC操作Bean管理(FactotyBean)

Spring 有两种类型bean,一种普通bean,另外一种工厂bean(FactoryBean)

(1)普通bean在配置文件中,定义bean类型就是返回类型

(2)工厂bean在配置文件中定义bean类型可以和返回类型不一样

第一步创建类,让这个类作为工厂Bean,实现接口FactoryBean

第二步实现接口里的方法,在实现方法中定义返回的bean类型

public class Stu implements FactoryBean<Orders> {

    @Override
    public Orders getObject() throws Exception {
        Orders orders = new Orders();
        return orders;
    }

    @Override
    public Class<?> getObjectType() {
        return null;
    }

    @Override
    public boolean isSingleton() {
        return false;
    }
}
<bean id="stu" class="com.sun.Entity.Stu">

测试

@org.junit.Test
    public void t5(){
        //1.加载spring的配置文件
        AbstractApplicationContext context = new ClassPathXmlApplicationContext("been.xml");
        //2.获取对象
        Orders Orders = context.getBean("stu", Orders.class);
        System.out.println(Orders.toString());
    }

9、IOC操作Bean管理(bean作用域)

(1)在spring里,设置创建Bean实例是单实例还是多实例

(2)在spring里,默认设置创建Bean实例是单实例

(3)如何设置单实例还是多实例

spring配置文件bean标签里scope属性用于设置单实例还是多实例

scope属性值:第一个,默认值,singleton,表示单实例对象;第二个值:prototype,表示多实例对象

(4)singleton 与 prototype区别

  • 第一,singleton表示单实例,prototype表示多实例。
  • 第二,设置Scope是singleton时,加载spring配置文件时侯就会创建单实例对象;
  • 设置Scope是prototype时,不是加载spring配置文件时侯创建对象,而是在调用getBean方法时创建多实例对象

(5)​ request,表示一次请求,每次创建对象放到request域对象中。

(6)session,表示一次会话,每次创建对象放到session域对象中。

10、IOC操作Bean管理(生命周期)

  • 生命周期
  1. 从对象创建到对象销毁的过程
  • bean生命周期
  1. 通过构造器创建bean实例(无参数构造)
  2. 为bean的属性设置值和对其他bean引用(调用set方法)
  3. 调用bean的初始化的方法(需要进行配置)
  4. bean可以使用了(对象获取到了)
  5. 当容器关闭的时候,调用bean的销毁的方法(需要进行配置销毁的方法)
public class Orders {
    private String oname;
    private String addres;

    public Orders() {
        System.out.println("第一步:通过无参构造实例化been");
    }

    public void setOname(String oname) {
        this.oname = oname;
        System.out.println("第二步:通过set方法设置been属性");
    }

    public void init(){
        System.out.println("第三步:调用been的初始化方法");
    }

    public void destroy(){
        System.out.println("第五步:调用been的销毁方法");
    }
    public void setAddres(String addres) {
        this.addres = addres;
    }

    @Override
    public String toString() {
        return "Orders{" +
                "oname='" + oname + '\'' +
                ", addres='" + addres + '\'' +
                '}';
    }
}
<bean id="orders" class="com.sun.Entity.Orders" init-method="init" destroy-method="destroy">
        <property name="addres" value="aa"/>
        <property name="oname" value="bb"/>
    </bean>
@org.junit.Test
    public void t6(){
        //1.加载spring的配置文件
        ApplicationContext context = new ClassPathXmlApplicationContext("been.xml");
        //2.获取对象
        Orders orders = context.getBean("orders", Orders.class);
        System.out.println("第四步:获取到been对象:");
        System.out.println(orders.toString());
        ((ClassPathXmlApplicationContext) context).close();
    }
  • bean的后置处理器,bean生命周期有七步

 

  1. 通过构造器创建bean实例(无参数构造)
  2. 为bean的属性设置值和对其他bean引用(调用set方法)
  3. 把bean实例传递bean后置处理器的方法postProcessBeforeInitialization
  4. 调用bean的初始化的方法(需要进行配置)
  5. 把bean实例传递bean后置处理器的方法postProcessAfterInitialization
  6. bean可以使用了(对象获取到了)
  7. 当容器关闭的时候,调用bean的销毁的方法(需要进行配置销毁的方法)

11、IOC操作Bean管理(xml自动装配)

  • 什么是自动装配
  1. 根据指定装配规则(属性名称或者属性类型),Spring自动将匹配的属性值进行注入
  • 演示自动装配过程

<bean id="user" class="com.sun.Entity.User" autowire="byType" />

12、IOC操作Bean管理(基于注解方式)

  • 什么是注解
    • 格式:@注解名称(属性名=属性值,属性名=属性值)
    • 使用注解:注解作用在类(方法,属性)上
    • 使用目的:简化xml配置
  • Spring针对Bean管理中创建对象提供注解

    • @Component 普通用法
    • @Service 用于service业务逻辑层
    • @Controller 用于web层

     

 

    • @Repository 用于DAO持久层
  • 基于注解方式实现对象创建例子

 

 

@Controller(value = "us")
public class UserControler {
}
 <!--开启组建扫描-->
    <context:component-scan base-package="com.sun.Entity"/>
 @org.junit.Test
    public void t7(){
        ApplicationContext context = new ClassPathXmlApplicationContext("been.xml");
        UserControler userControler = context.getBean("us", UserControler.class);
        System.out.println(userControler);
    }
  • 基于注解方式显示属性注入
    • @AutoWired:根据属性类型进行自动装配
      1. 把service 和dao对象创建,在service和dao类添加创建对象注解
      2. 在service 注入dao对象,在service 类添加dao类型属性,在属性上面使用注解

 

public interface UserDao {
    public void add();
}

@Repository
public class UserDaoImpl implements UserDao{
    @Override
    public void add() {
        System.out.println("UserDao add..............");
    }
}

@Service
public class UserService {
   @Autowired
   private UserDao userDao;

    public void add(){
        System.out.println("UserService add........");
        userDao.add();
    }
}

@org.junit.Test
    public void t4(){
        //1.加载spring的配置文件
        AbstractApplicationContext context = new ClassPathXmlApplicationContext("been.xml");
        //2.获取对象
        UserService userService = context.getBean("userService", UserService.class);
        userService.add();
    }
    • @Qualifier:根据属性名称进行注入

      需要和@Autowired配合使用

    • @Resource:可以根据类型注入,可以根据名称注入
    • @Value
  • 完全注解开发

    以上部分除了xml配置中的组件扫描配置外,其他实例化been和属性注入都实现了注解化,接下来就是用注解将xml配置中的组件扫描取代

@Configuration
@ComponentScan(basePackages = "com.sun.Entity")
public class SpringConfig {
}

@Component
public class User {
    public void add(){
        System.out.println("add ......");
    }

}

@org.junit.Test
    public void t1(){
        //1.加载spring的配置文件
        AbstractApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
        //2.获取对象
        User user = context.getBean("user", User.class);
        System.out.println(user.toString());
        user.add();
    }

 

2、AOP(底层原理)

  1. AOP底层使用动态代理
    • 第一种 有接口情况,使用JDK动态代理(创建接口实现类代理对象,增强类的方法)

 

 

    • 第二种 没有接口情况,使用CGLIB动态代理

 

 

 

3、AOP(JDK动态代理)

  1. JDK动态代理,使用Proxy类,java.lang.reflect.Proxy代理类

    ​ newProxyInstance(Classloader loader, 类<?>[ ]… interfaaces,InvocationHandler h)

    ​ 返回指定接口的代理类实例:(类加载器,增强方法所在的类,这个类实现的接口,支持多个接口,实现这个接口InvocationHandler,创建代理对象,写增强方法)

  2. 编写JDK动态代理代码
public interface UserDao {
    public int add(int a,int b);
}

@Repository
public class UserDaoImpl implements UserDao{

    @Override
    public int add(int a, int b) {
        return a+b;
    }
}


/**
 * 创建InvocationHandler接口的实现类
 * 在invoke方法中写增强逻辑
 */
public class JDKProxy implements InvocationHandler {

    private Object target;
    public JDKProxy(Object target) {
        this.target = target;
    }

    /**
     * 获取被代理接口实例对象
     * @param <T>
     * @return
     */
    public <T> T getProxy() {
        return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("方法执行之前:" + method.getName() + "传递的参数:" + Arrays.toString(args));
        Object res = method.invoke(target, args);
        System.out.println("方法执行之后:" );
        return res;
    }


}

@org.junit.Test
    public void t9(){
        JDKProxy jdkProxy = new JDKProxy(new UserDaoImpl());
        UserDao proxy = jdkProxy.getProxy();
        int add = proxy.add(1, 2);
        System.out.println(add);
        
    }

4、AOP(术语)

  • 连接点:类里面可以被增强的方法。
  • 切入点:实际被增强的方法。
  • 通知(增强):实际增加的逻辑部分。( 通知有多种类型)
    • 前置通知
    • 后置通知
    • 环绕通知
    • 异常通知
    • 最终通知(finally)
  • 切面:把通知应用到切入点的过程。

5、AOP操作(准备)

  1. Spring 框架中一般都是基于AspectJ实现AOP操作
  2. AspectJ,本身是单独的框架,不属于Spring组成部分,独立于AOP框架,一般把AspectJ和Spring框架一起使用,进行AOP操作。
  3. 基于AspectJ实现AOP操作
    • 基于xml配置文件实现
    • 基于注解方式实现
  4. 切入点表达式
    • 切入点表达式作用:知道对哪个类的哪个方法进行增强

    • 语法结构:execution([权限修饰符] [返回类型] [类全路径] [方法名称] ([参数列表]))
      • 举例1:对com.zhh.dao.BookDao类里的add进行增强     execution(* com.zhh.dao.BookDao.add(…))
      • 举例2:对com.zhh.dao.BookDao类里的所有方法进行增强      execution(* com.zhh.dao.BookDao.*(…))
      • 举例3:对com.zhh.dao包里的所有类,类里的所有方法进行增强       execution(* com.zhh.dao..(…))

 

6、AOP操作(Aspectj注解)

  (1)创建类、在类里面定义方法

    (2)创建增强类(编写增强逻辑)

      (3)进行通知的配置

  (4)在增强类上面添加注解@Aspect

  (5)在spring配置文件中开启生成代理对象

  (6)配置不同类型通知

 

/**
 * 创建需增强的类
 */
@Component
public class Demo {
    /*创建需增强的方法*/
    public void add(){
        int i = 1/0;
        System.out.println("add........");
    }
}

/**
 * 创建增强类
 */
@Component
@Aspect
public class DemoProxy {
    //创建增强方法
    /*@Before(value = "execution(* com.sun.Aop.Demo.add(..))")
    public void before(){
        System.out.println("前置通知。。。。。。。");
    }*/
    /*@AfterReturning(value = "execution(* com.sun.Aop.Demo.add(..))")
    public void afterReturning(){
        System.out.println("后置通知。。。。。。。");
    }*/
    /*@Around(value = "execution(* com.sun.Aop.Demo.add(..))")
    public void around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("环绕通知前。。。。。。。");
        joinPoint.proceed();
        System.out.println("环绕通知后。。。。。。。。。");
    }*/

    @After(value = "execution(* com.sun.Aop.Demo.add(..))")
    public void after(){
        System.out.println("最终通知。。。。");
    }

    @AfterThrowing(value = "execution(* com.sun.Aop.Demo.add(..))")
    public void afterThrowing(){
        System.out.println("异常通知。。。。");
    }
}
<context:component-scan base-package="com.sun"/>
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
@org.junit.Test
    public void t10(){
        ApplicationContext context = new ClassPathXmlApplicationContext("been.xml");
        Demo demo = context.getBean("demo", Demo.class);
        demo.add();
    }

 (7)相同接入点抽取

/**
 * 创建增强类
 */
@Component
@Aspect
public class DemoProxy {
    /**
     * 如下都是对execution(* com.sun.Aop.Demo.add(..))进行增强,可进行提取
     */
    @Pointcut(value = "execution(* com.sun.Aop.Demo.add(..))")
    public void pointCut(){

    }
    //创建增强方法
    @Before(value = "pointCut()")
    public void before(){
        System.out.println("前置通知。。。。。。。");
    }
    @AfterReturning(value = "pointCut()")
    public void afterReturning(){
        System.out.println("后置通知。。。。。。。");
    }
    @Around(value = "pointCut()")
    public void around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("环绕通知前。。。。。。。");
        joinPoint.proceed();
        System.out.println("环绕通知后。。。。。。。。。");
    }

    @After(value = "pointCut()")
    public void after(){
        System.out.println("最终通知。。。。");
    }

    @AfterThrowing(value = "pointCut()")
    public void afterThrowing(){
        System.out.println("异常通知。。。。");
    }
}

(8)完全使用注解开发

@Configuration
@ComponentScan(basePackages = "com.sun")
@EnableAspectJAutoProxy
public class SpringConfig {
}

7、AOP操作(Aspectj配置文件)

  • 创建增强类和被增强类
public class Book1 {
    public void buy(){
        System.out.println("buy........");
    }
}

public class BookProxy {
    public void before(){
        System.out.println("before...........");
    }
}
  • 在配置文件中配置been,并配置切点和切面
<bean id="book1" class="com.sun.AopXML.Book1"></bean>
    <bean id="bookProxy" class="com.sun.AopXML.BookProxy"></bean>
    <aop:config>
        <aop:pointcut id="p" expression="execution(* com.sun.AopXML.Book1.buy(..))"/>
        <aop:aspect ref="bookProxy">
            <aop:before method="before" pointcut-ref="p"/>
        </aop:aspect>
    </aop:config>

四、事务概念

1、什么是事务

  • 事务是数据库操作最近本单元,逻辑上一组操作,要么都成功,如果有一个失败所有操作都失败
  • 典型场景:银行转账

 

2、事物的四个特性(ACID)

  • 原子性(要么都成功,要么都失败)
  • 一致性(操作之前和操作之后总量不变)
  • 隔离性(事物之间彼此隔离,互不影响)
  • 持久性(事物提交之后会被保存起来)

 

3、事务操作(Spring事务管理介绍)

(1)事务添加到JavaEE三层结构里面Service层(业务逻辑层)

(2)在Spring进行事务管理操作

 

  • 编程式事务管理
  • 声明式事务管理(使用)
  • (3)声明式事务管理
  • 基于注解方式(使用)
  • 基于xml配置文件方式
  • (4)在Spring进行声明式事务管理,底层使用AOP原理
  • (5)Spring事务管理API
  1. 提供一个接口,代表事务管理器,这个接口针对不同的框架提供不同的实现类

 

 

 

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

(1)在Spring配置文件配置事务管理器

<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="url" value="jdbc:mysql://localhost:3306/test"/>
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="username" value="root"/>
        <property name="password" value="root"/>
    </bean>
   
    <context:component-scan base-package="com.sun"/>
    <!--创建事物管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>

(2)在Spring配置文件,开启事务注解

  • 在Spring配置文件引入名称空间tx

<?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:p="http://www.springframework.org/schema/p"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       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.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">

</beans>
  • 开启事务注解

 

<!--开启spring事物注解-->
    <tx:annotation-driven transaction-manager="transactionManager"/>

(3)在Service类上面(获取service类里面方法上面)添加事务注解

  • @Transactional 这个注解添加到类上面,也可以添加方法上面
  • 如果把这个注解添加到类上面,这个类里面所有的方法都添加事务
  • 如果把这个注解添加到方法上面,为这个方法添加事务
@Service
@Transactional
public class AccountService {
    @Autowired
    private AccountDao accountDao;
    public void account(){
        accountDao.addMoney();
        int i =1/0;
        accountDao.reduceMoney();
    }
}

6、事务操作(声明式事务管理参数配置)

(1)在service类上面添加注解@Transactional,在这个注解里面可以配置事务相关参数

  • propagation:事务传播行为

 

 

 

 

 

 

  • 多事务方法直接进行调用,这个过程中事务是如何进行管理的
  • ioslation:事务隔离级别

第一种隔离级别:Read uncommitted(读未提交)

如果一个事务已经开始写数据,则另外一个事务不允许同时进行写操作,但允许其他事务读此行数据,该隔离级别可以通过“排他写锁”,但是不排斥读线程实现。这样就避免了更新丢失,却可能出现脏读,也就是说事务B读取到了事务A未提交的数据

 

第二种隔离级别:Read committed(读提交)

如果是一个读事务(线程),则允许其他事务读写,如果是写事务将会禁止其他事务访问该行数据,该隔离级别避免了脏读,但是可能出现不可重复读。事务A事先读取了数据,事务B紧接着更新了数据,并提交了事务,而事务A再次读取该数据时,数据已经发生了改变。

 

第三种隔离级别:Repeatable read(可重复读取)

可重复读取是指在一个事务内,多次读同一个数据,在这个事务还没结束时,其他事务不能访问该数据(包括了读写),这样就可以在同一个事务内两次读到的数据是一样的,因此称为是可重复读隔离级别,读取数据的事务将会禁止写事务(但允许读事务),写事务则禁止任何其他事务(包括了读写),这样避免了不可重复读和脏读,但是有时可能会出现幻读。(读取数据的事务)可以通过“共享读镜”和“排他写锁”实现

幻读:

在一个事务中使用相同的 SQL 两次读取,第二次读取到了其他事务新插入的行

 

第四种隔离级别:Serializable(可序化)

 

提供严格的事务隔离,它要求事务序列化执行,事务只能一个接着一个地执行,但不能并发执行,如果仅仅通过“行级锁”是无法实现序列化的,必须通过其他机制保证新插入的数据不会被执行查询操作的事务访问到。序列化是最高的事务隔离级别,同时代价也是最高的,性能很低,一般很少使用,在该级别下,事务顺序执行,不仅可以避免脏读、不可重复读,还避免了幻读

 

 解决:通过设置事务隔离级别,解决读问题

 

 

 

  • timeout:超时时间
  • 事务需要在一定时间内进行提交,如果不提交进行回滚
  • 默认值:-1,设置时间以秒单位进行计算
  • readOnly:是否只读
  • 读:查询操作,写:添加修改删除操作
  • readOnly默认值false,表示可以查询,可以添加修改删除操作
  • 设置readOnly值为true后,只能查询
  • rollbackFor:
  • 设置出现哪些异常进行事务回滚
  • noRollbackFor
  • 设置出现哪些异常不进行事务回滚

 

(1)创建两个类,增强类和被增强类,创建方法

posted @ 2021-10-27 16:58  VBNS  阅读(111)  评论(0)    收藏  举报