2021年最详细的Spring5知识点

IOC(接口)

  • 1.IOC思想基于IOC容器完成,IOC容器底层就是对象工厂。
  • 2.Spring提供IOC容器实现的两种方式:(两个接口)
    • (1)BeanFactory:IOC容器基本实现,是Spring内部的使用接口,不提供开发人员进行使用。
      • 特点:加载配置文件的时候不会创建对象,在获取对象(使用)才去创建对象。
    • (2)ApplicationContext:BeanFactory接口的子接口,提供更多更强大的功能,一般是由开发人员进行使用。
      • 特点:加载配置文件时就会把配置文件对象进行创建。

IOC操作Bean管理(概念)

  • 1.什么是Bean管理?
    • (0)Bean管理指的是两个操作
    • (1)Spring 创建对象
    • (2)Spring 注入对象
  • 2.Bean管理操作有两种方式
    • (1)基于xml配置文件方式实现
      <!--(1)在Spring配置文件中,使用Bean标签,标签里面添加对应属性,就可以实现对象创建-->
      <!--配置User对象创建-->
      <bean id="User" class="com.Gby.pojo.User"></bean>
      
      • 在bean标签有很多属性,介绍常用的属性

        id属性:唯一标识

        class属性:类全路径(包类路径)

        name属性:唯一标识(可以使用特殊符号,如:"/")

      • 创建对象时候,默认也是执行无参数构造方法,完成对象创建

    • (2)基于注解方式实现
      • (1)DI:依赖注入,就是注入属性
        • 第一种注入方式:使用set方法进行注入
          • 注入方式:在Spring配置文件配置对象创建,配置属性注入
               <!--1.创建对象-->
              <bean id="Book" class="com.Gby.pojo.Book">
                  <!--2.注入属性-->
                  <property name="username" value="易筋经"/>
                  <property name="author" value="悟空"/>
              </bean>
          
        • 第二种注入方式:使用有参构造进行注入
          • 注入方式:在Spring配置文件配置对象创建,配置属性注入
              <!--2.有参构造-->
              <bean id="Book" class="com.Gby.pojo.Book">
                  <constructor-arg name="author" value="wukong"/>
                  <constructor-arg name="username" value="yijinjing"/>
                  <!--也可以通过索引值进行注入-->
                  <!--<constructor-arg index="0" value="111"/>-->
              </bean>
          
    • (3)p名称空间注入
      • (1)使用p名称空间注入,可以简化基于xml配置方式
        • 第一步添加p名称空间在配置文件中
            <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">
            </beans>
          
        • 第二步,进行属性注入,在bean标签里面进行操作
              <bean id="Book" class="com.Gby.pojo.Book" p:author="wuyu" p:username="mieshiwuxiu"/>
          

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

  • 1.字面量

    • (1)null值
          <property name="author">
          <null/>
          </property>
      
    • (2)属性值包括特殊符号
           <property name="author">
               <!--属性值包括特殊符号
                   1.把<>进行转义 &lt , &gt
                   2.把带有特殊符号内容写到CDATA
               -->
               <value><![CDATA[<<南京>>]]></value>
           </property>
      
  • 2.注入属性-外部Bean

    • (1)创建两个类service类和dao类
           public class UserService {
           private UserDao userDao;
       
           public void setUserDao(UserDao userDao) {
               this.userDao = userDao;
           }
       
           public void add(){
               System.out.println("service add ....");
       
               /*//创建UserDao对象
               UserDao userDao = new UserDaoImpl();
               userDao.updata();*/
           }
      }
      
           public class UserDaoImpl implements UserDao{
           @Override
           public void updata() {
               System.out.println("Dao updata .....");
           }
       }
      
           public interface UserDao {
           public void updata();
           }
      
    • (2)在service调用dao里面的方法
    • (3)在Spring配置文件中进行配置
        <!--1.service和dao对象创建-->
           <bean id="UserService" class="com.Gby.Service.UserService">
               <!--注入UserDao对象
                   name属性值:类里面属性名称
                   ref:创建userdao对象Bean标签id值-->
               <property name="UserDao" ref="UserDaoImpl"/>
           </bean>
           <bean id="UserDaoImpl" class="com.Gby.Dao.UserDaoImpl"/>
      
      
  • 3.注入属性-内部Bean和级联赋值

    • (1)一对多关系:部门和员工,一个部门有多个员工,一个员工属于一个部门,部门是一,员工是多
    • (2)在实体类之间表示一对多的关系
                       //部门类
           public class Dept {
           private String name;
           
               public Dept(String name) {
                   this.name = name;
               }
           
               public Dept() {
               }
           
               public String getName() {
                   return name;
               }
           
               public void setName(String name) {
                   this.name = name;
               }
           
               @Override
               public String toString() {
                   return "Dept{" +
                           "name='" + name + '\'' +
                           '}';
               }
           }
      
                   //员工类
       public class Emp {
       private String ename;
       private String gender;
       private Dept dept;
       
           public void setDept(Dept dept) {
               this.dept = dept;
           }
       
           public void setEname(String ename) {
               this.ename = ename;
           }
       
           public void setGender(String gender) {
               this.gender = gender;
           }
       
           public Emp() {
           }
       
           @Override
           public String toString() {
               return "Emp{" +
                       "ename='" + ename + '\'' +
                       ", gender='" + gender + '\'' +
                       ", dept=" + dept +
                       '}';
           }
           public void add(){
               System.out.println(11111);
           }
       }
      
    • (3)在Spring配置文件中进行配置
        <!--内部Bean-->
        <bean id="Emp" class="com.Gby.Bean.Emp">
            <!--现设置两个普通的属性-->
            <property name="ename" value="luck"/>
            <property name="gender" value=""/>
            <!--设置对象类型属性-->
            <property name="dept">
                <bean id="dept" class="com.Gby.Bean.Dept">
                    <property name="name" value="安保部"></property>
                </bean>
            </property>
        </bean>
      
  • 4.注入属性-级联赋值

    • (1)第一种写法
          <!--级联赋值-->
      <bean id="Emp" class="com.Gby.Bean.Emp">
          <!--现设置两个普通的属性-->
          <property name="ename" value="luck"></property>
          <property name="gender" value=""></property>
          <!--级联赋值-->
          <property name="dept" ref="dept"></property>
      </bean>
      <bean id="dept" class="com.Gby.Bean.Dept">
          <property name="name" value="财务部"></property>
      </bean>
      
    • (2)第二种写法
      <!--级联赋值-->
      <bean id="Emp" class="com.Gby.Bean.Emp">
          <!--现设置两个普通的属性-->
          <property name="ename" value="luck"></property>
          <property name="gender" value=""></property>
          <!--级联赋值-->
          <property name="dept" ref="dept"></property>
          <!--需要在Emp类中生成一下dept的get方法-->
          <property name="dept.name" value="技术部"/>
      </bean>
      <bean id="dept" class="com.Gby.Bean.Dept">
          <property name="name" value="财务部"></property>
      </bean>
      

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

  • 1.注入数组类型属性

  • 2.注入List集合类型属性

  • 3.注入Map集合类型属性

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

          public class Stu {
          //数组类型属性
          private String[] courses;
          //list集合类型属性
          private List<String> list;
          //map集合类型属性
          private Map<String,String> map;
          //set集合类型属性
          private Set<String> sets;
      
             public void setSets(Set<String> sets) {
                 this.sets = sets;
             }
         
             public void setMap(Map<String, String> map) {
                 this.map = map;
             }
         
             public void setList(List<String> list) {
                 this.list = list;
             }
         
             public void setCourses(String[] courses) {
                 this.courses = courses;
             }
         
             public Stu() {
             }
          }
      
      
    • (2)在spring配置文件进行配置

      <!--集合类型属性的注入-->
      <bean id="Stu" class="com.Gby.collectiontype.Stu">
          <!--数组类型属性注入-->
          <property name="courses">
              <array>
                  <value>java</value>
                  <value>Mysql</value>
              </array>
          </property>
          <!--list集合类型属性注入-->
          <property name="list">
              <list>
                  <value>zhangsan</value>
                  <value>xiaosan</value>
              </list>
          </property>
          <!--map类型属性注入-->
          <property name="map">
              <map>
                  <entry key="JAVA" value="java"/>
                  <entry key="PHP" value="php"/>
              </map>
          </property>
          <!--set类型属性注入-->
          <property name="sets">
              <set>
                  <value>Mysql</value>
                  <value>VUE</value>
              </set>
          </property>
      </bean>
      
      
  • 4.在集合里面设置对象类型值

       <!--创建多个course对象-->
       <bean id="course1" class="com.Gby.collectiontype.Course">
           <property name="name" value="spring5"/>
       </bean>
       <bean id="course2" class="com.Gby.collectiontype.Course">
           <property name="name" value="Mybatis"/>
       </bean>
    
       <!--注入list集合类型,值是对象-->
       <property name="courseList">
           <list>
               <ref bean="course1"></ref>
               <ref bean="course2"></ref>
           </list>
       </property>
    
  • 5.把集合注入部分提取出来

    • (1)在spring配置文件中引入名称空间 util
          <?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:util="http://www.springframework.org/schema/util"
          xsi:schemaLocation="http://www.springframework.org/schema/beans
          http://www.springframework.org/schema/beans/spring-beans.xsd
          http://www.springframework.org/schema/util
          http://www.springframework.org/schema/util/spring-util.xsd">        
      
    • (2)使用util标签完成list集合注入提取
          <!--1.提取list集合类型属性注入-->
          <util:list id="bookList">
              <value>1</value>
              <value>2</value>
              <value>3</value>
          </util:list>
      
          <!--2.提取list集合类型属性注入使用-->
          <bean id="book" class="com.Gby.collectiontype.Book">
              <property name="book" ref="bookList"></property>
          </bean>
      

IOC操作Bean管理(FactoryBean)

  • 1.Spring有辆各种类型bean,一种普通bean,另外一种工厂Bean(FactoryBean)
  • 2.普通Bean:在配置文件中定义bean类型就是返回类型
  • 3.工厂Bean:在配置文件定义Bean类型可以和返回类型不一样
    • 第一步创建类,让这个类作为工厂bean,实现接口FactoryBean

           public class mybean implements FactoryBean<Course> {
       
           //定义返回bean
           @Override
           public Course getObject() throws Exception {
               Course course = new Course();
               course.setName("abc");
               return course;
           }
       
           @Override
           public Class<?> getObjectType() {
               return null;
           }
       
           @Override
           public boolean isSingleton() {
               return false;
           }
       }
      
      
    • 第二步实现接口里面的方法,在实现的方法中定义返回的bean类型

          public void Stu3(){
      ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
      Course course = context.getBean("mybean", Course.class);
      System.out.println(course);
      }
      
      

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

  • 1.在Spring里面,设置创建bean实例是单实例还是多实例

  • 2.在Spring里面,默认情况下,bean是单实例对象

        @Test
       public void Stu3(){
           ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
           Course course = context.getBean("mybean", Course.class);
           System.out.println(course);
           System.out.println(course);
       }
    
       com.Gby.collectiontype.Course@3cb1ffe6
       com.Gby.collectiontype.Course@3cb1ffe6
    
    
  • 3.如何设置单实例还是多实例

    • (1)在spring配置文件bean标签里面有属性(scope)用于设置单实例还是多实例

      • 1.默认值,singleton,表示单实例对象
      • 2.多实例,prototype,表示多实例对象
           <bean id="Student" class="com.Gby.Pojo.Student" scope="prototype">
           <property name="student" value="1231"/>
           </bean>
        
        @Test
           public void test(){
               ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean2.xml");
               Student student = context.getBean("Student", Student.class);
               Student student1 = context.getBean("Student", Student.class);
               System.out.println(student);
               System.out.println(student1);
        
           }
        
           com.Gby.Pojo.Student@6043cd28
           com.Gby.Pojo.Student@cb51256
        
        
    • (2).singleton和prototype区别

      • (1)设置scope的值是singleton时,加载配置文件时候就会创建单实例对象。

        设置scope值是prototype的时候,在调用getBean方法的时候创建多实例对象

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

  • 1.生命周期

    • (1)从对象创建到对象销毁的过程
  • 2.bean的生命周期

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

            public class Student {
        private String student;
    
        public Student() {
            System.out.println("第一步,执行无参数构造创建bean实例");
        }
    
        public void setStudent(String student) {
            this.student = student;
            System.out.println("第二步,调用set方法设置属性值");
        }
        //创建初始化方法
        public void initMethod(){
            System.out.println("第三步,调用初始化方法");
        }
        //创建销毁方法
        public void distroyMethod(){
            System.out.println("第五步,销毁方法");
        }
    
    }
    
        <!--init-method:初始化方法,destroy-method:销毁方法-->
        <bean id="Student" class="com.Gby.Pojo.Student" init-method="initMethod" destroy-method="distroyMethod">
            <property name="student" value="1231"/>
        </bean>
    
        public void test1(){
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean2.xml");
        Student student = context.getBean("Student", Student.class);
        System.out.println("第四步获取对象");
        System.out.println(student);
        //手动销毁Bean实例
        context.close();
      }
    
  • 4.bean的后置处理器

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

    • (1)创建类,实现接口BeanPostProcessor,创建后置处理器
      public class MyBeanPost implements BeanPostProcessor {
            @Override
            public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
                System.out.println("在初始化之前执行的方法");
                return bean;
            }
        
            @Override
            public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
                System.out.println("在初始化之后执行的方法");
                return bean;
            }
        }
    
        <!--配置后置处理器-->
        <bean id="MyBeanPost" class="com.Gby.Pojo.MyBeanPost"></bean>
    
    第一步,执行无参数构造创建bean实例
    第二步,调用set方法设置属性值
    在初始化之前执行的方法
    第三步,调用初始化方法
    在初始化之后执行的方法
    第四步获取对象
    com.Gby.Pojo.Student@46daef40
    第五步,销毁方法
    

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

  • 1.什么是自动装配
    • (1)根据指定装配规则(属性名称或者属性类型),Spring自动将匹配的属性值进行注入
  • 2.演示自动装配过程
    • (1)根据属性名称自动注入
            <!--实现自动装配
            bean标签属性autowire,配置自动装配
            autowire属性常用两个值
                byName根据属性名称注入
                byType根据属性类型注-->
        <bean id="Emp" class="com.Gby.autowire.Emp" autowire="byName">
        <!--<property name="dept" ref="Dept"></property>-->
        </bean>
        <bean id="Dept" class="com.Gby.autowire.Dept"></bean>
      
    • (2)根据属性类型自动注入
        <bean id="Emp" class="com.Gby.autowire.Emp" autowire="byType">
        <!--<property name="dept" ref="Dept"></property>-->
        </bean>
        <bean id="Dept" class="com.Gby.autowire.Dept"></bean>
      

IOC操作Bean管理(外部属性文件)

  • 1.直接配置数据库信息
    • (1)引入德鲁伊连接池依赖jar包
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.6</version>
        </dependency>
      
    • (2)配置德鲁伊数据库
        <!--直接配置连接池-->
        <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
            <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
            <property name="url" value="jdbc:mysql://localhost:3306/user"/>
            <property name="username" value="root"/>
            <property name="password" value="***"/>
        </bean>
      
  • 2.引入外部属性文件配置数据库连接池
    • (1)创建外部属性文件,properties格式文件,数据库信息
        prop.driverClass=com.mysql.jdbc.Driver
        prop.url=jdbc:mysql://localhost:3306/user
        prop.username=root
        prop.password=***
      
    • (2)把外部properties属性文件引入到Spring配置文件中
      • 引入context名称空间
          <?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 http://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/context  http://www.springframework.org/schema/context/spring-context.xsd">
        
      • 在spring配置文件使用标签引入外部属性文件
          <!--引入外部属性文件-->
            <context:property-placeholder location="classpath:jdbc.properties"/>
            <!--配置连接池-->
            <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
                <property name="driverClassName" value="${prop.driverClass}"/>
                <property name="url" value="${prop.url}"/>
                <property name="username" value="${prop.username}"/>
                <property name="password" value="${prop.password}"/>
            </bean>     
        

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

  • 1.什么是注解
    • (1)注解是代码特殊标记,格式:@注解名称(属性名称=属性值,属性名称=属性值…)
    • (2)使用注解,注解作用在类的上面,方法上面,属性上面
    • (3)使用注解的目的:简化xml配置
  • 2.Spring针对Bean管理中创建对象提供注解
    • (1)@Component
    • (2)@Service
    • (3)@Controller
    • (4)@Repository
      上面的四个注解功能都是一样的,都可以用来创建bean实例
    
  • 3.基于注解方式实现对象的创建
    • (1)第一步,引入依赖
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.1.9.RELEASE</version>
        </dependency>
      
    • (2)第二步,开启组件扫描
        <!--开启组件扫描
        1.如果扫描多个包,多个包使用逗号隔开
        2.扫描包上层目录-->
        <context:component-scan base-package="com.Gby"></context:component-scan>
      
    • (3)第三步创建类,在类上面添加创建对象的注解
        //在注解里面value属性值可以省略不写
        //默认值是类名称,首字母小写 UserService-->userService
        @Component(value = "userService")
        public class UserService {
        
            public void add(){
                System.out.println("service add...");
            }
        }
      
  • 4.开启组件扫描细节配置
      <!--示例1
      use-default-filters表示现在不使用默认filter,自己配置filter
      annotation注解
      exclude-filter,设置扫描哪些内容
      -->
      <context:component-scan base-package="com.Gby" use-default-filters="false">
      <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
      </context:component-scan>
    
      <!--示例2
          下面配置扫描包所有内容
          context:exclude-filter:设置哪些内容不进行扫描
      -->
      <context:component-scan base-package="com.Gby">
      <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
      </context:component-scan>
    
  • 5.基于注解方式实现属性注入
    • (1)@AutoWired:根据属性类型进行自动装配

      • 第一步把Service和dao对象创建,在service和dao类添加创建对象注解
      • 第二步在service注入dao对象,在service类添加dao类型的属性,在属性上面使用注解
            @Service(value = "userService")
            public class UserService {
            //定义dao类型属性
            //不需要添加set方法
            //添加注入属性的注解
            @Autowired
            private UserDao userDao;
            
                public void add(){
                    System.out.println("service add...");
                    userDao.add();
                }
            }
        
    • (2)@Qualifier:根据属性名称进行注入

      • 这个@Qualifier注解的使用,和上面的@AutoWired一起使用
            //在注解里面value属性值可以省略不写
            //默认值是类名称,首字母小写 UserService-->userService
            @Service(value = "userService")
            public class UserService {
            //定义dao类型属性
            //不需要添加set方法
            //添加注入属性的注解
            @Autowired//根据类型进行注入
            @Qualifier(value = "userDaoImpl")
            private UserDao userDao;
            
                public void add(){
                    System.out.println("service add...");
                    userDao.add();
                }
            }
        
    • (3)@Resource:可以根据类型注入,可以根据名称注入

        //@Resource //根据类型进行注入
        @Resource(name = "userDaoImpl")
        private UserDao userDao;
      
      
    • (4)Value:注入普通类型属性

          @Value(value = "abc")
          private String name;
      
  • 6.完全注解开发
    • (1)创建配置类,替代xml配置文件
          @Configuration//作为配置类,替代xml配置文件
          @ComponentScan(basePackages = {"com.Gby"})
          public class SpringConfig {
          }
      
    • (2)编写测试类
          @Test
          public void test1(){
          ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
          UserService userService = context.getBean("userService", UserService.class);
          System.out.println(userService);
          userService.add();
          }
      

AOP(概念)

  • 1.什么是AOP
    • (1)面向切面编程(方面),利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发速率。
    • (2)通俗描述:不通过源代码方式,在主干功能里面添加新功能
      AOP(底层原理)
  • 1.AOP底层使用动态代理
    • (1)有两种情况的动态代理
      • 第一种情况,有接口情况,使用JDK动态代理
        • 创建接口实现类代理对象,增强类的方法
      • 第二种情况,没有接口情况,使用CGLIB动态代理

AOP(JDK动态代理)

  • 1.使用JDK动态代理,使用Proxy类里面的方法创建代理对象
    • (1)调用newProxyInstance方法
            static Object 	newProxyInstance(ClassLoader loader, 类<?>[] interfaces, InvocationHandler h)
            //返回指定接口的代理类的实例,该接口将方法调用分派给指定的调用处理程序。 
      
      • 方法有三个参数:

        第一参数,类加载器。
        第二参数,增强方法所在类,这个类实现的接口,支持多个接口
        第三参数,实现这个接口InvocationHandler,创建代理对象,写增强的方法
        
  • 2.编写JDK动态代理代码
    • (1)创建接口,定义方法
            public interface UserDao {
        public int add(int a,int b);
        public String update(String id);
        }
      
    • (2)创建接口实现类,实现方法
      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)使用Proxy类创建接口代理对象
          public class JdkProxy {
          public static void main(String[] args) {
          //创建接口实现类代理对象
          Class[] interfaces = {UserDao.class};
          UserDaoImpl userDao = new UserDaoImpl();
          UserDao o = (UserDao) Proxy.newProxyInstance(JdkProxy.class.getClassLoader(), interfaces, new UserDaoProxy(userDao));
          int add = o.add(1, 2);
          System.out.println(add);
          }
          }
      
          //创建代理对象代码
          class UserDaoProxy implements InvocationHandler{
          //1.把创建的是谁的代理对象,把谁传递过来
          //有参数构造传递
          private Object object;
          public UserDaoProxy(Object object){
          this.object=object;
          }
          
              //增强的逻辑
              @Override
              public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                  //方法之前
                  System.out.println("方法之前执行..."+method.getName()+":传递的参数"+ Arrays.toString(args));
                  //被增强的方法执行
                  Object invoke = method.invoke(object, args);
                  //方法之后
                  System.out.println("方法之后执行"+object);
                  return invoke;
              }
          }
      

AOP(术语)

  • 1.连接点
    • 类里面那些方法可以被增强,这些方法称为连接点
  • 2.切入点
    • 实际被增强的方法,称为切入点
  • 3.通知(增强)
    • 实际增强的逻辑部分称为通知(增强)
    • 通知有多种类型
          前置通知
          后置通知
          环绕通知
          异常通知
          最终通知 finally
      
  • 3.切面
    • 切面是动作,把通知应用到切入点过程

AOP操作(准备)

  • 1.Spring框架一般都是基于AspectJ实现Aop操作
    • (1)什么是AspectJ
      • AspectJ不是Spring组成部分,独立AOP框架,一般把AspectJ和Spring框架一起使用,进行Aop操作
  • 2.基于AspectJ实现AOP操作
    • (1)基于xml配置文件
    • (2)基于注解方式实现(使用)
  • 3.在项目工程里面引入AOP相关依赖
      <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.4</version>
      </dependency>
    
  • 4.切入点表达式
    • (1)切入点表达式作用:知道对哪个类里面的哪个方法进行增强
    • (2)语法结构:execution( [权限修饰符] [返回类型] [类全路径] ([参数列表]))
      • 举例1:对com.Gby.dao.BookDao类里面的add进行增强

        execution(* com.Gby.dao.BookDao.add(…))

      • 举例2:对com.Gby.dao.BookDao类里面的所有方法进行增强

        execution(* com.Gby.dao.BookDao.*(…))

      • 举例3:对com.Gby.dao包里面的所有类,类里面的所有方法进行增强

        execution(* com.Gby.dao.* .*(…))

AOP操作(AspectJ注解)

  • 1.创建类,在类里面定义方法
        public class User {
        public void add(){
            System.out.println("add.......");
        }
    }
    
  • 2.创建增强类(编写增强逻辑)
    • (1)在增强类里面,创建方法,让不同的方法代表不同的方法类型
          //增强的类
          public class UserProxy {
          //前置通知
          public void before(){
              System.out.println("before.....");
              }
          }
      
  • 3.进行通知的配置
    • (1)在Spring配置文件中,开启注解扫描

        <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.xsd
        http://www.springframework.org/schema/aop  http://www.springframework.org/schema/aop/spring-aop.xsd">
        
            <!--开启注解扫描-->
            <context:component-scan base-package="com.Gby"></context:component-scan>
        </beans>
      
      
    • (2)使用注解创建User和UserProxy对象

        //增强的类
        @Component
        public class UserProxy {
            //前置通知
            public void before(){
            System.out.println("before.....");
            }
        }
      
        //被增强的类
        @Component
        public class User {
            public void add(){
            System.out.println("add.......");
            }
        }
      
    • (3)在增强的类上面添加注解@Aspect

        //增强的类
        @Component
        @Aspect//生成代理对象
        public class UserProxy {
            //前置通知
            public void before(){
            System.out.println("before.....");
            }
        }
      
    • (4)在Spring配置文件中开启生成代理对象

          <!--开启注解扫描-->
          <context:component-scan base-package="com.Gby"/>
          <!--开启Aspect生成代理对象-->
          <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
      
  • 4.配置不同类型的通知
    • (1)在增强类的里面,在作为通知的方法上面添加通知类型注解,使用切入点表达式配置
          //增强的类
          @Component
          @Aspect//生成代理对象
          public class UserProxy {
              //前置通知
              @Before(value = "execution(* com.Gby.aop.User.add(..))")
              public void before(){
                  System.out.println("before.....");
              }
              //最终通知
              @After(value = "execution(* com.Gby.aop.User.add(..))")
              public void after(){
                  System.out.println("after....");
              }
              //方法返回值之后执行
              @AfterReturning(value = "execution(* com.Gby.aop.User.add(..))")
              public void AfterReturning(){
                  System.out.println("AfterReturning.......");
              }
              //异常通知
              @AfterThrowing(value = "execution(* com.Gby.aop.User.add(..))")
              public void AfterThrowing(){
                  System.out.println("AfterThrowing........");
              }
              //环绕通知
              @Around(value = "execution(* com.Gby.aop.User.add(..))")
              public void Around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
                  System.out.println("环绕之前......");
                  //被增强的方法执行
                  proceedingJoinPoint.proceed();
                  System.out.println("环绕之后......");
              }
          }
      
      
  • 5.形同切入点的提取
        //相同切入点抽取
        @Pointcut(value = "execution(* com.Gby.aop.User.add(..))")
        public void Pointcut(){}
        
        //前置通知
        @Before(value = "execution(* com.Gby.aop.User.add(..))")
        public void before(){
            System.out.println("before.....");
        }
        //最终通知
        @After(value = "Pointcut()")
        public void after(){
            System.out.println("after....");
        }
    
  • 6.有多个增强类多同一个方法进行增强,设置增强类优先级
    • (1)在增强类上面添加注解@Order(数字类型值),数字类型值越小优先级越高
          @Component
          @Aspect
          @Order(2)
          public class PersonProxy {
              //前置通知
              @Before(value = "execution(* com.Gby.aop.User.add(..))")
              public void before(){
                  System.out.println("person before.....");
              }
          }
      
  • 7.完全使用注解开发
    • (1)创建配置类,不需要创建xml配置文件
       @Configuration
       @ComponentScan
       @EnableAspectJAutoProxy(proxyTargetClass = true)
       public class ConfigAop {
       }
      

AOP操作(AspectJ配置文件)

  • 1.创建两个类,增强类和被增强类,创建方法

  • 2.在Spring配置文件中创建两个类对象

        <!--创建对象-->
        <bean id="Book" class="com.Gby.aopxml.Book"/>
        <bean id="BookProxy" class="com.Gby.aopxml.BookProxy"/>
    
    
  • 3.在Spring配置文件中配置切入点

    <!--配置aop增强-->
        <aop:config>
            <!--切入点-->
            <aop:pointcut id="p" expression="execution(* com.Gby.aopxml.Book.buy(..))"/>
            <!--配置切面-->
            <aop:aspect ref="BookProxy">
                <!--增强作用在具体的方法上-->
                <aop:before method="before" pointcut-ref="p"/>
            </aop:aspect>
        </aop:config>
    

JdbcTemplate(概念和准备)

  • 1.什么是JdbcTemplate
    • (1)Spring框架对Jdbc进行封装,使用JdbcTemplate方便对数据库操作
  • 2.准备工作
    • (1)引入相关的jar包

      <!--数据库驱动-->
          <dependency>
              <groupId>mysql</groupId>
              <artifactId>mysql-connector-java</artifactId>
              <version>5.1.47</version>
          </dependency>
          <!-- 数据库连接池 -->
           <dependency>
              <groupId>com.alibaba</groupId>
              <artifactId>druid</artifactId>
              <version>1.1.6</version>
           </dependency>
      
          <!--Servlet - JSP -->
          <dependency>
              <groupId>javax.servlet</groupId>
              <artifactId>servlet-api</artifactId>
              <version>2.5</version>
          </dependency>
          <dependency>
              <groupId>javax.servlet.jsp</groupId>
              <artifactId>jsp-api</artifactId>
              <version>2.2</version>
          </dependency>
          <dependency>
              <groupId>javax.servlet</groupId>
              <artifactId>jstl</artifactId>
              <version>1.2</version>
          </dependency>
          
          <!--Spring-->
          <dependency>
              <groupId>org.springframework</groupId>
              <artifactId>spring-webmvc</artifactId>
              <version>5.1.9.RELEASE</version>
          </dependency>
          <dependency>
              <groupId>org.springframework</groupId>
              <artifactId>spring-jdbc</artifactId>
              <version>5.1.9.RELEASE</version>
          </dependency>
          <dependency>
              <groupId>org.aspectj</groupId>
              <artifactId>aspectjweaver</artifactId>
              <version>1.9.4</version>
          </dependency>
      
      
    • (2)在Spring配置文件配置数据库连接池

           <!--直接配置连接池-->
          <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
              <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
              <property name="url" value="jdbc:mysql://localhost:3306/book"/>
              <property name="username" value="root"/>
              <property name="password" value="***"/>
          </bean>
      
    • (3)配置JDBCTemplate对象,注入DataSource

          <!--jdbcTemplate对象-->
          <bean id="JdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
              <!--注入dataSource-->
              <property name="dataSource" ref="dataSource"></property>
          </bean>
      
    • (4)创建service类,创建dao类,在dao注入JDBCTemplate对象

      • xml配置文件
         <!--开启组件扫描-->
        <context:component-scan base-package="com.Gby" ></context:component-scan>
      
      • Service
        @Service(value = "bookService")
        public class BookService {
            //注入dao
            @Autowired
            private BookDao bookDao;
        }
      
      • Dao
        @Repository
        public class BookDaoImpl implements BookDao{
            //注入jdbcTemplate
            @Autowired
            private JdbcTemplate jdbcTemplate;
        }
      

JDBCTemplate操作数据库(添加)

  • 1.对应数据库创建实体类
        public class User {
        private String userId;
        private String username;
        private String ustatus;
        
            public String getUserId() {
                return userId;
            }
        
            public void setUserId(String userId) {
                this.userId = userId;
            }
        
            public String getUsername() {
                return username;
            }
        
            public void setUsername(String username) {
                this.username = username;
            }
        
            public String getUstatus() {
                return ustatus;
            }
        
            public void setUstatus(String ustatus) {
                this.ustatus = ustatus;
            }
        
            public User() {
            }
        
            @Override
            public String toString() {
                return "User{" +
                        "userId='" + userId + '\'' +
                        ", username='" + username + '\'' +
                        ", ustatus='" + ustatus + '\'' +
                        '}';
            }
        }
    
  • 2.编写service和dao
    • (1)在dao进行数据库添加操作

        @Repository
        public class BookDaoImpl implements BookDao{
        
            //注入jdbcTemplate
            @Autowired
            private JdbcTemplate jdbcTemplate;
            
            @Override
            public void add(User user) {
                //创建sql语句
                String sql = "insert into t_user values(?,?,?)";
                //调用方法实现
                int update = jdbcTemplate.update(sql, user.getUserId(), user.getUsername(), user.getUstatus());
                System.out.println(update);
            }
        }
        
      
    • (2)调用JDBCTemplate对象里面update方法实现添加操作

        update(String sql,Object... args)
        有两个参数,第一个参数:sql语句,第二个参数:可变参数,设置sql语句值
      
  • 3.编写测试类进行数据库添加操作
        @Test
        public void add(){
            ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("AppliCationContext.xml");
            BookService bookService = context.getBean("bookService", BookService.class);
            User user = new User();
            user.setUserId("1");
            user.setUsername("java");
            user.setUstatus("a");
            bookService.addBook(user);
        }
    

JDBCTemplate操作数据库(删除,修改)

  • 1.修改数据库数据
    @Override
    public void update(User user) {
        String sql = "update t_user set username=?,ustatus=? where user_id = ?";
        Object[] args = {user.getUsername(),user.getUstatus(),user.getUserId()};
        int update = jdbcTemplate.update(sql, args);
        System.out.println(update);
    }
    
  • 2.删除数据库信息
    @Override
    public void delete(int id) {
        String sql = "delete from t_user where user_id = ?";
        int update = jdbcTemplate.update(sql, id);
        System.out.println(update);
    }
    

JDBCemplate操作数据库(查询返回某个值)

  • 1.查询表里面有多少条记录,返回是某个值
  • 2.使用JDBCTemplate实现查询返回某个值代码
    queryForObject(String sql,Class<T> requiredType)
    有两个参数,第一个参数:sql语句,第二个参数,返回类型calss
    
    @Override
    public int insert(){
            String sql = "select count(*) from t_user";
            Integer integer = jdbcTemplate.queryForObject(sql, Integer.class);
            return integer;
            }
    
  • 3.这里可能会出现的问题
    出现这样的报错java.lang.NoSuchMethodError: org.springframework.dao.support.DataAccessUtils.nullableSingleResult(Ljava/util/Collection;)Ljava/lang/Object;
    是因为Spring相关的jar包版本的问题,解决办法,把spring相关的jar包改成统一的版本。(建议在加载spring相关的jar时,就用统一的版本,可能有时候不会出错,为了避免此类的错误,还是改成一样版本的)
    
    

JDBCTemplate操作数据库(查询返回对象)

  • 1.场景:查询图书的详情
  • 2.JDBCTemplate实现查询返回对象
        queryForObject(String sql,RowMapper<T> rowMapper,Object... args)
        //有三个参数,第一个参数:sql语句
        //第二个参数:rowMapper,是接口,返回不同类型数据,使用这个接口里面实现类完成数据封装
        //第三个参数:sql语句值
    
        @Override
        public User findBookInfo(String id) {
            String sql = "select * from t_user where user_id = ?";
            User user = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<User>(User.class), id);
            return user;
        }
    

JDBCTemplate操作数据库(查询返回集合)

  • 1.场景:查询图书列表分页
  • 2.调用JDBCTemplate方法实现查询返回集合
        @Override
        public List<User> findAll() {
            String sql = "select * from t_user";
            List<User> query = jdbcTemplate.query(sql, new BeanPropertyRowMapper<User>(User.class));
            return query;
        }
    

JBCTemplate操作数据库(批量操作)

  • 1.批量操作:操作表里面多条记录
    • (1)JBCTemplate实现批量添加操作
          batchUpdate(String sql,List<Object[]> batchArgs)
          //第一个参数:sql语句,第二个参数:list集合,添加多条记录的数据
      
              @Override
          public void batchAddBook(List<Object[]> batchArgs) {
              String sql = "insert into t_user values(?,?,?)";
              int[] ints = jdbcTemplate.batchUpdate(sql, batchArgs);
              System.out.println(Arrays.toString(ints));
          }
      
           //测试类批量操作
          List<Object[]> batchArgs = new ArrayList<>();
          Object[] o1 = {"4","mysql","a"};
          Object[] o2 = {"5","vue","b"};
          Object[] o3 = {"6","spring","a"};
          batchArgs.add(o1);
          batchArgs.add(o2);
          batchArgs.add(o3);
          bookService.batchAdd(batchArgs);
      
    • (2)JBCTemplate实现批量修改操作
          @Override
          public void batchUpdate(List<Object[]> batchArgs) {
              String sql = "update t_user set username=?,ustatus=? where user_id = ?";
              int[] ints = jdbcTemplate.batchUpdate(sql, batchArgs);
              System.out.println(ints);
          }
      
    • (3)JBCTemplate实现批量删除操作
           @Override
          public void batchDelete(List<Object[]> batchArgs) {
              String sql = "delete from t_user where user_id = ?";
              int[] ints = jdbcTemplate.batchUpdate(sql, batchArgs);
              System.out.println(Arrays.toString(ints));
          }
      

事务操作(事务概念)

  • 1.什么是事务
    • (1)事务是数据库操作最基本单元,逻辑上的一组操作,要么都成功,如果有一个失败所有操作都失败
    • (2)典型场景:银行转账
  • 2.事物的四个特性(ACID)
    • (1)原子性:一个事务包含多个操作,这些操作要么全部执行,要么全都不执行。
    • (2)一致性:一个提交更新的事务的结果被另一个读操作的事务获取的程度,以达到一致性。
    • (3)隔离性:并发事务之间互相影响的程度,比如一个事务会不会读取到另一个未提交的事务修改的数据。
    • (4)持久性:事务提交后,对系统的影响是永久的。

事务操作(搭建事务操作环节)

  • 1.创建数据库表,添加记录

        CREATE TABLE `book`.`t_account`( `id` VARCHAR(20) NOT NULL, `username` VARCHAR(50), `money` INT, PRIMARY KEY (`id`) ) ENGINE=INNODB CHARSET=utf8;
    
  • 2.创建service,搭建dao,完成对象创建和注入关系

    • service注入dao,在dao注入JDBCTemplate,JDBCTemplate在注入DateSource
        @Service
        public class UserService {
        
            //注入dao
            @Autowired
            private UserDao userDao;
            //转账方法
            public void accountMoney(){
                //lucy少一百
                userDao.reduceMoney();
                //mary多一百
                userDao.addMoney();
            }
        }
    
  • 3.在Dao创建两个方法:多钱和少钱的方法,在service创建方法(转账的方法)

        @Repository
        public class UserDaoImpl implements UserDao{
        
            @Autowired
            private JdbcTemplate jdbcTemplate;
        
            @Override
            public void addMoney() {
                String sql = "update t_account set money=money+? where username = ?";
                jdbcTemplate.update(sql,100,"mary");
            }
        
            @Override
            public void reduceMoney() {
                String sql = "update t_account set money=money-? where username = ?";
                jdbcTemplate.update(sql,100,"lucy");
            }
        }
    
  • 4.上面代码,如果正常执行没有问题,但是如果代码在执行过程中出现了异常

        @Service
        public class UserService {
        
            //注入dao
            @Autowired
            private UserDao userDao;
            //转账方法
            public void accountMoney(){
                //lucy少一百
                userDao.reduceMoney();
                //模拟异常
                int i= 10/0;
                //mary多一百
                userDao.addMoney();
            }
        }
    
  • 5.问题解决

    • (1)使用事务进行解决
    • (2)事务操作过程
          //转账方法
          public void accountMoney(){
              try{
              //第一步,开启事务操作
              
              //第二步,进行业务操作
              //lucy少一百
              userDao.reduceMoney();
              //模拟异常
              int i= 10/0;
              //mary多一百
              userDao.addMoney();
              //第三步,没有异常提交事务
          }catch (Exception e){
              //第四步,出现异常,事务回滚
              e.printStackTrace();
          }
      
          }
      

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

  • 1.事务添加到JAVAEE三层架构里面的Service层(业务逻辑层)
  • 2.在Spring里面进行事务管理操作
    • (1)有两种方式:编程式事务管理和声明式事务管理(使用)
  • 3.声明式事务管理
    • (1)基于注解方式
    • (2)基于xml配置文件方式
  • 4.在Spring进行声明式事务管理,底层使用Aop
  • 5.Spring事务管理API
    • (1)提供了一个接口,代表事务管理器,这个接口针对不同框架提供了不同的实现类

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

  • 1.在spring配置文件配置事务管理器
    <!--创建事务管理器-->
        <bean id="TransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <!--注入数据源-->
            <property name="dataSource" ref="dataSource"></property>
        </bean>
    
  • 2.在Spring配置文件,开启事务注解
    • (1)在Spring配置文件引入名称空间tx
          xmlns:tx="http://www.springframework.org/schema/tx"
          http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
      
    • (2)开启事务注解
        <tx:annotation-driven transaction-manager="TransactionManager"></tx:annotation-driven>
      
    • (3)在Service类上面(获取Service类里面方法上面)添加事务注解
      • @Transactional,这个注解添加到类上面,也可以添加到方法上面
      • 如果把这个注解添加类上面,这个类里面所有的方法都添加事务
      • 如果把这个注解添加方法上面,为方法添加了事务
            @Service
            @Transactional
            public class UserService {}
        

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

  • 此处文章链接链接

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

  • 当类中某些方法不需要事物时:

        @Transactional  
        public class TestServiceBean implements TestService {
            private TestDao dao;
            public void setDao(TestDao dao) {
                this.dao = dao;
            }
            @Transactional(propagation =Propagation.NOT_SUPPORTED)
            public List getAll() {
                return null;
            }
        }
    
  • 事物传播行为介绍:

        @Transactional(propagation=Propagation.REQUIRED) :如果有事务, 那么加入事务, 没有的话新建一个(默认情况下)
        @Transactional(propagation=Propagation.NOT_SUPPORTED) :容器不为这个方法开启事务
        @Transactional(propagation=Propagation.REQUIRES_NEW) :不管是否存在事务,都创建一个新的事务,原来的挂起,新的执行完毕,继续执行老的事务
        @Transactional(propagation=Propagation.MANDATORY) :必须在一个已有的事务中执行,否则抛出异常
        @Transactional(propagation=Propagation.NEVER) :必须在一个没有的事务中执行,否则抛出异常(与Propagation.MANDATORY相反)
        @Transactional(propagation=Propagation.SUPPORTS) :如果其他bean调用这个方法,在其他bean中声明事务,那就用事务.如果其他bean没有声明事务,那就不用事务.
        @Transactional(propagation=Propagation.NESTED) :如果有事务在运行,当前的方法就应该在这个事务的嵌套事务内运行,否则,就启动一个新的事务,并在它自己的事务内运行。
    
    
  • 事物超时设置:@Transactional(timeout=30) //默认是30秒

  • 事务隔离级别:

        @Transactional(isolation = Isolation.READ_UNCOMMITTED):读取未提交数据(会出现脏读, 不可重复读) 基本不使用
        @Transactional(isolation = Isolation.READ_COMMITTED):读取已提交数据(会出现不可重复读和幻读)
        @Transactional(isolation = Isolation.REPEATABLE_READ):可重复读(会出现幻读)
        @Transactional(isolation = Isolation.SERIALIZABLE):串行化
    
        MYSQL: 默认为REPEATABLE_READ级别
        SQLSERVER: 默认为READ_COMMITTED
    
    • 脏读 : 一个事务读取到另一事务未提交的更新数据
    • 不可重复读 : 在同一事务中, 多次读取同一数据返回的结果有所不同, 换句话说,
    • 后续读取可以读到另一事务已提交的更新数据. 相反, "可重复读"在同一事务中多次
    • 读取数据时, 能够保证所读数据一样, 也就是后续读取不能读到另一事务已提交的更新数据
    • 幻读 : 一个事务读到另一个事务已提交的insert数据
  • @Transactional注解中常用参数说明

        readOnly
        
        该属性用于设置当前事务是否为只读事务,设置为true表示只读,false则表示可读写,默认值为false。例如:@Transactional(readOnly=true)
        
        rollbackFor
        
        该属性用于设置需要进行回滚的异常类数组,当方法中抛出指定异常数组中的异常时,则进行事务回滚。例如:
        
        指定单一异常类:@Transactional(rollbackFor=RuntimeException.class)
        
        指定多个异常类:@Transactional(rollbackFor={RuntimeException.class, Exception.class})
        
        rollbackForClassName
        
        该属性用于设置需要进行回滚的异常类名称数组,当方法中抛出指定异常名称数组中的异常时,则进行事务回滚。例如:
        
        指定单一异常类名称:@Transactional(rollbackForClassName="RuntimeException")
        
        指定多个异常类名称:@Transactional(rollbackForClassName={"RuntimeException","Exception"})
        
        noRollbackFor
        
        该属性用于设置不需要进行回滚的异常类数组,当方法中抛出指定异常数组中的异常时,不进行事务回滚。例如:
        
        指定单一异常类:@Transactional(noRollbackFor=RuntimeException.class)
        
        指定多个异常类:@Transactional(noRollbackFor={RuntimeException.class, Exception.class})
        
        noRollbackForClassName
        
        该属性用于设置不需要进行回滚的异常类名称数组,当方法中抛出指定异常名称数组中的异常时,不进行事务回滚。例如:
        
        指定单一异常类名称:@Transactional(noRollbackForClassName="RuntimeException")
        
        指定多个异常类名称:
        
        @Transactional(noRollbackForClassName={"RuntimeException","Exception"})
        
        propagation
        
        该属性用于设置事务的传播行为,具体取值可参考事物传播行为介绍。
        
        例如:@Transactional(propagation=Propagation.NOT_SUPPORTED,readOnly=true)
        
        isolation
        
        该属性用于设置底层数据库的事务隔离级别,事务隔离级别用于处理多事务并发的情况,通常使用数据库的默认隔离级别即可,基本不需要进行设置
        
        timeout
        
        该属性用于设置事务的超时秒数,默认值为-1表示永不超时
    
    
    
    
    
  • 注意的几点:

    • 1、@Transactional 只能被应用到public方法上, 对于其它非public的方法,如果标记了@Transactional也不会报错,但方法没有事务功能.
    • 2、用 spring 事务管理器,由spring来负责数据库的打开,提交,回滚.默认遇到运行期例外(throw new RuntimeException(“注释”);)会回滚,即遇到不受检查(unchecked)的例外时回滚; 而遇到需要捕获的例外(throw new Exception(“注释”);)不会回滚,即遇到受检查的例外(就是非运行时抛出的异常,编译器会检查到的异常叫受检查例外或说受检查异常)时, 需我们指定方式来让事务回滚要想所有异常都回滚,要加上 @Transactional( rollbackFor={Exception.class,其它异常}) .如果让unchecked例外不回滚: @Transactional(notRollbackFor=RunTimeException.class)如下:
          @Transactional(rollbackFor=Exception.class) //指定回滚,遇到异常Exception时回滚
          public void methodName() {
              throw new Exception("注释");
          }
          @Transactional(noRollbackFor=Exception.class)//指定不回滚,遇到运行期例外(throw new RuntimeException("注释");)会回滚
          public ItimDaoImpl getItemDaoImpl() {
              throw new RuntimeException("注释");
          }
      
    • 3、@Transactional 注解应该只被应用到 public 可见度的方法上。 如果你在 protected、private 或者 package-visible 的方法上使用 @Transactional 注解,它也不会报错, 但是这个被注解的方法将不会展示已配置的事务设置。
    • 4、@Transactional 注解可以被应用于接口定义和接口方法、类定义和类的 public 方法上。然而,请注意仅仅 @Transactional 注解的出现不足于开启事务行为,它仅仅 是一种元数据,能够被可以识别 @Transactional 注解和上述的配置适当的具有事务行为的beans所使用。
      上面的例子中,其实正是 元素的出现 开启 了事务行为。
    • 5、Spring团队的建议是你在具体的类(或类的方法)上使用 @Transactional 注解,而不要使用在类所要实现的任何接口上。你当然可以在接口上使用 @Transactional 注解,
      但是这将只能当你设置了基于接口的代理时它才生效。因为注解是不能继承的,这就意味着如果你正在使用基于类的代理时,那么事务的设置将不能被基于类的代理所识别,而且对象也将不会被事务代理所包装(将被确认为严重的)。因此,请接受Spring团队的建议并且在具体的类上使用 @Transactional 注解。

事务操作(xml声明式事务管理)

  • 1.在Spring配置文件中进行配置
    • (1)第一步,配置事务管理器
        <!--1.创建事务管理器-->
        <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <!--注入数据源-->
            <property name="dataSource" ref="dataSource"></property>
        </bean>
      
        <!--这里一定要切记,使用xml进行事务管理的时候,bean的id值一定要是transactionManager,否则就会报错-->
      
    • (2)第二步,配置通知
        <!--2.配置通知-->
        <tx:advice id="txadvice">
            <!--配置事务参数-->
            <tx:attributes>
                <!--指定哪种规则的方法上面添加事务-->
                <tx:method name="account*" propagation="REQUIRED"/>
            </tx:attributes>
        </tx:advice>
      
    • (3)第三步,配置切入点和切面
          <!--3.配置切入点和切面-->
          <aop:config>
              <!--配置切入点-->
              <aop:pointcut id="pt" expression="execution(* com.Gby.Service.UserService.*(..))"/>
              <!--配置切面-->
              <aop:advisor advice-ref="txadvice" pointcut-ref="pt"/>
          </aop:config>
      

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

  • 1.创建配置类,使用配置类代替xml配置文件
        @Configuration//配置类
        @ComponentScan(basePackages = "com.Gby")//组件扫描
        @EnableTransactionManagement(proxyTargetClass = false)//开启事务
        public class TxConfig {
            //创建数据库连接池
            @Bean
            public DruidDataSource getDruidDataSource(){
                DruidDataSource druidDataSource = new DruidDataSource();
                druidDataSource.setDriverClassName("com.mysql.jdbc.Driver");
                druidDataSource.setUrl("jdbc:mysql://localhost:3306/book");
                druidDataSource.setUsername("root");
                druidDataSource.setPassword("gby20010704..");
                return druidDataSource;
            }
            //创建jdbcTemplate对象
            @Bean
            public JdbcTemplate getJdbcTemplate(DataSource dataSource){
                //到ioc容器中根据类型找到DataSource
                JdbcTemplate jdbcTemplate = new JdbcTemplate();
                //注入dataSource
                jdbcTemplate.setDataSource(dataSource);
                return jdbcTemplate;
            }
            //创建事务管理器
            @Bean
            public DataSourceTransactionManager getDataSourceTransactionManager(DataSource dataSource){
                DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
                dataSourceTransactionManager.setDataSource(dataSource);
                return dataSourceTransactionManager;
            }
        }
    

Spring5框架新功能

  • 1.基于Java8,同时兼容jdk9,许多不建议使用的类和方法在代码库里删除
  • 2.自带了通用的日志封装
    • (1)Spring5已经移除了log4jConfigListener,官方建议使用log4j2
    • (2)Spring5框架整合Log4j2
      • 引入java包
            <!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core -->
            <dependency>
                <groupId>org.apache.logging.log4j</groupId>
                <artifactId>log4j-core</artifactId>
                <version>2.12.1</version>
            </dependency>
            <!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api -->
            <dependency>
                <groupId>org.slf4j</groupId>
                <artifactId>slf4j-api</artifactId>
                <version>1.7.30</version>
            </dependency>
        
      • 第二步创建Log4j2.xml配置文件
            <?xml version="1.0" encoding="UTF-8"?>
            <!--日志级别一级优先级排序:OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL-->
            <!--Configuration后面的status用于设置Log4j2自身内部信息输出,可以不设置,当设置成trace时,可以看到log4j2内部各种详细输出-->
            <configuration status="INFO">
                <!--先定义所有的appender-->
                <appenders>
                    <!--输出日志信息到控制台-->
                    <console name="Console" target="SYSTEM_OUT">
                        <!--控制日志输出格式-->
                        <Patternlayout pattern="%d{yyyy-MM-dd HH:mm:ss.sss} [%t] %-5level %logger{36} - %msg%n"/>
                    </console>
                </appenders>
                <!--然后定义logger,只有定义了logger并引入的appender,appender才会生效-->
                <!--root:用于指定项目的跟日志,如果没有单独指定logger,则会使用root作为默认的日志输出-->
                <loggers>
                    <root level="info">
                        <appender-ref ref="Console"/>
                    </root>
                </loggers>
            </configuration>
        
  • 3.Spring5框架核心容器支持@Nullable注解
    • (1)@Nullable注解可以使用在方法上面,属性上面,参数上面,表示方法返回可以为空,属性值可以为空,参数值可以为空
    • (2)注解用在方法上面,方法返回值可以为空
          @Nullable
          String getId();
      
    • (3)注解使用在方法参数里面,方法参数可以为空
          public <T> void registerBean(@Nullable String beanName)
      
    • (4)注解使用在上面表示属性值可以为空
          @Nullable
          private String book;
      
  • 4.Spring5核心容器支持函数式风格GenericApplicationContext
        //函数式风格创建对象,交Spring进行管理
        @Test
        public void testGenericApplicationContext(){
            //1.创建GenericApplicationContext对象
            GenericApplicationContext context = new GenericApplicationContext();
            //2.调用Context的方法对象注册
            context.refresh();
            context.registerBean("user",User.class,() -> new User());
            //3.获取在Spring注册的对象
            //User user = context.getBean("com.Gby.pojo.User", User.class);
            User user = context.getBean("user", User.class);
            System.out.println(user);
        }
    
  • 5.Spring5支持整合JUnit5
    • (1)整合Junit4
      • 第一步引入Spring相关针对测试依赖
            <!-- https://mvnrepository.com/artifact/org.springframework/spring-test -->
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-test</artifactId>
                <version>5.2.6.RELEASE</version>
                <scope>test</scope>
            </dependency>
        
        
      • (2)第二步创建测试类,使用注解方式完成
          @RunWith(SpringJUnit4ClassRunner.class)//单元测试框架
          @ContextConfiguration("classpath:ApplicationContext.xml")//加载配置文件
          //这两个注解就相当于ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("AppliCationContext.xml");
          public class JTest4 {
              @Autowired
              private UserService userService;
        
              @Test
              public void test1(){
                  userService.accountMoney();
              }
          }
        
            <--可能会出现的错误,版本不一致导致的-->
            java.lang.NoClassDefFoundError: org/springframework/core/annotation/MergedAnnotations
        
    • (2)Spring5整合Junit5
      • 第一步引入JUnit5的jar包
            <!-- https://mvnrepository.com/artifact/org.springframework/spring-test -->
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-test</artifactId>
                <version>5.1.9.RELEASE</version>
                <scope>test</scope>
            </dependency>
        
      • 第二步创建测试类,使用注解完成
            @ExtendWith(SpringExtension.class)
            @ContextConfiguration("classpath:ApplicationContext.xml")//加载配置文件
            public class JTest5 {
            @Autowired
            private UserService userService;
            
                @Test
                public void test(){
                    
                }
            }
        
    • (3)使用一个复合注解替代上面两个注解完成整合
        @SpringJUnitConfig(locations = "classpath:ApplicationContext.xml")
        public class JTest5 {
        @Autowired
        private UserService userService;
        
            @Test
            public void test(){
                userService.accountMoney();
            }
        }
      
  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值