Spring

Spring


0. 两个特点

1. 控制反转 (IOC)

2. 面向切面编程(AOP)

1. IOC(Inversion of Control)

IOC 的底层原理

  1. 把对象的创建和对象的调用,交给Spring进行管理

  2. 降低耦合度

IOC的过程

1.1xml 方式

  1. xml配置文件, 创建对象的xml

  2. 创建工厂类(反射创建对象)

  3. class UserFactoy {
        public static UserDao getDao() {
            String classVal = ""//XML解析
            //反射创建对象
            Class clazz = Class.forName(classVal);
            (/*强转*/)clazz.newInstance();
        }  
    }
    
  4. IOC基于IOC容器,两个接口

    • BeanFactory

      IOC最基本的, Spring 内部接口, 一般我们不用

    • ApplicationContext

      是BeanFactory的子接口, 提供了更多的功能, 一般我们用这个

      (1) 加载配置文件的时候, 就会去创建

      (2)把耗时的过程放在服务器启动的时候去搞, 所以我们喜欢用这个

      实现类

      ClassPathXmlApplication
      
      FileSystemXmlApplication
      
  5. IOC操作

    • Bean管理

      • Spring创建对象

      • Spring注入属性

    • Bean操作

      • XML配置文件

      • <bean id="xxx", class="全类名"></bean>
        <!--属性-->
        <!--id:唯一属性 给对象起别名 getBean()的时候第一个参数-->
        <!--class:全类名-->
        <!--name 属性,和id 属性一样-->
        <!-- 注意调用的是无参构造器-->
        
      • public void test() {
            ApplicationContext context 
                        = new ClassPathXmlApplicationContext("xml的文件");
            Object obj = context.getBean("id属性值", 类名.class);//创建对象
            //这样就创建好了对象
        }
        

        基于XML注入属性

        • set方法

        • <bean id="" class="" >
              <property name="" value=""></property>
          </bean>
          
        • 构造方法

        • <constructor-arg name="" value=""></constructor-arg>
          <!-- 如果有多个属性,可以写多行
              
          -->
          
      • XML注入其他属性,可以为null

        <property name="" >
            <null/>
        </property>
        
      • p名称空间注入

      • xmlns:p = "http://www.springframework.org/schema/beans"
        <bean id="" class="" p:属性名="" ...>
        
        </bean>
        
      • 写特殊符号

      • <porperty name="" value="<hh>">
        <!-- 注入<> -->
        
   <property name=""> 
       <value><![CDATA[<<xxx>>]]></value>
   </property>

外部bean

 poublic interface UserDao {
     void update();
 }

 public class UserDao implements UserDao{
     public void update() {
         //xxx
     }
 }



 public interface UserService {
     void update();
 }


 public class UserServiceImpl implements UserService {

 /*
     原始做法

 UserDao userDao = new UserDaoImpl

     UserDao userDao = new UserDaoImpl
     public void update() {
         userDao.update();
     }    

 */
     private UserDao usreDao;//属性值


     //set方法
     public void setUserDao(UserDao userDao) {
         this.userDao = userDao;
     }


 }
<!--
       创建userService UserDao是他的属性值
   -->
   <bean id="userService" class="com.service.UserService">
           <!-- ref 引用下边创建的对象-->
           <property name="userDao" ref="userDao"></property>
       </bean>
       <bean id="userDao" class="com.dao.UserDaoImpl"></bean>

内部bean和级联赋值

  • 级联赋值(也就是外部bean ref)

  • <bean id="emp" class="com.bean.Emp">
            <property name="eName" value="lang"></property>
            <property name="gender" value="boy"></property>
            <property name="dept" ref="dept">
    
            </property>
        </bean>
    <!--属性dept是一个类 也可以用上边的外部bean, ref的方法-->
                <bean id="dept" class="com.bean.Dept">
                    <property name="dName" value="财务部"></property>
                </bean>
    
  • 一对多的关系

  • <bean id="emp" class="com.bean.Emp">
            <property name="eName" value="lang"></property>
            <property name="gender" value="boy"></property>
            <property name="dept">
              <!--属性dept是一个类 也可以用上边的外部bean, ref的方法-->
                <bean id="dept" class="com.bean.Dept">
                    <property name="dName" value="财务部"></property>
                </bean>
            </property>
        </bean>
    
  • 注入集合属性

    • 注入数组

    • <property name="courses" >
                 <array>
                       <value>语文</value>
                       <value>数学</value>
                       <value>英语</value>
                </array>
        </property>
      
    • 注入List集合

    • <property name="list">
           <list>
                <value>lang</value>
                <value>浪</value>
                <value>梓</value>
          </list>
       </property>
      
    • 注入Map集合

    • <property name="map">
          <map>
              <entry key="java" value="hard"></entry>
          </map>
      </property>
      
  • 在集合设置对象类型的值

    <bean id="" class="">
            <property name="list">
             <list>
                  <ref bean="id01"> </ref>
                  <ref bean="id02"> </ref>
            </list>
         </property>
    </bean>
    <bean id="id01" class=""></bean>
    <bean id="id02" class=""></bean>
    
  • 把集合注入部分提取出来

    • (1) 引入名称空间 util

    • (2) 注入 ref

    • <?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">
             <util:list id="bookList">
                 <value>java</value>
                 <value>cpp</value>
                 <value>spring</value>
             </util:list>
          <bean id="book" class="com.collection.Book">
              <property name="list" ref="bookList">
      
              </property>
          </bean>
      </beans>
      

IOC操作bean的管理

  1. 普通bean: 定义的和返回的是一个类型

  2. 工厂bean :不一定是一个类型

    • (1) 实现FactoryBean接口

    • (2)在接口方法中定义返回类型

public interface FactoryBean<T> {
    String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";

    @Nullable
    T getObject() throws Exception;

    @Nullable
    Class<?> getObjectType();

    default boolean isSingleton() {
        return true;
    }
}

bean的作用域

  • bean可以是多实例也可以是多实例(创建对象时,创建的是同一个对象?)

  • 如何设置, bean标签 scope属性

  • <bean scope="singleton"><!-- 单实例
        加载配置文件的时候, 会创建单实例对象
    -->
    <bean scope="prototype"> <!-- 多实例
        调用getBean()时会创建对象
    -->
    

bean的生命周期

  1. 通过无参构造器创建实例

  2. 为bean设置属性

  3. 调用bean初始化方法 initMethod xml中配置

  4. bean可以使用了

  5. 当容器关闭时, 调用bean销毁的方法 destroyMethod xml中配置

bean的后置处理器

  • 在第三步前后各有一个 把bean的实例传递后置处理器, 所以一共七步

xml的自动装配

不需要写==property==标签把属性注入

<bean autowire="byName"></bean>
<!--根据属性名字-->
<bean autowire="byType"></bean>
<!--根据属性类型-->

引入外部属性文件

druid的连接池,直接注入属性

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

引入外部==properties==文件

driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/test
username=root
password=990808

xml引入context

  1. 利用context:property-placeholder 的location属性读取properties文件

  2. property 标签利用表达式${}注入属性值

<?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">


    <context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>

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

1.2 注解方式

使用注解可以简化xml配置

  1. 创建对象的注解
    • @Component

    • @Service

    • @Controller

    • @Repository

流程

  1. xml配置

    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">
    <!--    开启组件扫描-->
        <context:component-scan base-package="com.dao, com.service"></context:component-scan>
    </beans>
    
  2. 在类上写注解

    @Component(value = "userService")//类似于bean标签的 id属性
    public class UserService {
        public void add() {
            System.out.println("add...");
        }
    }
    

    细节

    <context:component-scan base-package="com.dao, com.service" use-default-filters="false">
            <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
        <!-- use-default-filters
     属性 是否按照默认的方式扫描
       context:include-filte 只扫描Controller的注解
     context:exclude-filter 只扫描不包含Controller的注解-->
        </context:component-scan>
        <context:component-scan base-package="com.dao, com.service" use-default-filters="true">
            <context:exclude-filter type="annotation" expression=""/>
        </context:component-scan>
    

注解方式注入属性

  • @Autowired 根据属性类型

  • @Qualifier 根据属性名称, 需要和Autowired一块使用

  • @Resource 以上两者都可以

  • @Value 注入普通类型

纯注解开发

  • 创建配置类

    类上加注解, 还有(组件扫描的设置)扫描的类设置

    @Configuration
    @ComponentScan(basePackages = {"com"})
    public class SpringConfig {
    
    }
    
  • 创建对象的过程稍有改变

    使用==AnnotationConfigApplicationContext==

    public void test01() {
            ApplicationContext context =
                    new AnnotationConfigApplicationContext(SpringConfig.class);
            UserService userService = context.getBean("userService", UserService.class);
        }
    
    

2.AOP(Aspect Oriented Programming)

2.1 基本概念

利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性同时提高了开发的效率

面向切面编程, 可以降低耦合度

2.2 底层原理

  1. AOP底层使用动态代理

    • 有接口 JDK的动态代理
      1. 创建interface

      2. 创建实现实现上述interface的类

      3. 创建代理类

    • 没有接口的 CGLIB动态代理

  2. AOP的术语

    • 连接点

      类里边可以增强的方法

    • 切入点

      实际被真正增强的方法

    • 通知(增强)

      实际增强的逻辑部分

      • 前置通知

      • 后置通知

      • 环绕通知

      • 异常通知

      • 最终通知

    • 切面

      是动作:把通知应用到切入点的过程

  3. AOP操作(注解实现)

    • 基于==AspectJ==实现

      • 什么是AspectJ

        单独的框架,基于xml和基于注解

    • 引入依赖

    • 切入点表达式

      • 知道对哪个类的哪个方法增强

      • execution([权限修饰符] [返回类型] [全类名] [方法名] [参数列表])

  4. 操作步骤

    • 创建被增强类, 方法

      @Component
      public class User {
          public void add() {
              System.out.println("user add....");
          }
      }
      
    • 创建增强的类, 方法

      @Component//创建对象
      @Aspect//aop
      public class UserProxy {
      
          //配置通知类型
          //前置通知
          @Before(value = "execution(* com.aopanno.User.add(..))")
          public void before() {
              System.out.println("before....");
          }
          //在方法返回值之后执行
          @AfterReturning(value = "execution(* com.aopanno.User.add(..))")
          public void afterReturning() {
              System.out.println("AfterReturning");
          }
          //后置, 方法执行后执行
          @After(value = "execution(* com.aopanno.User.add(..))")
          public void after() {
              System.out.println("after");
          }
          //异常
          @AfterThrowing(value = "execution(* com.aopanno.User.add(..))")
          public void afterThrowing() {
              System.out.println("AfterThrowing");
          }
      
          //环绕, 方法执行之前之后都执行
          @Around(value = "execution(* com.aopanno.User.add(..))")
          public void around() {
              System.out.println("Around");
          }
      }
      
    • 在增强的类上加注解==@Aspect==

    • 在增强的方法上边加上通知的注解(如前置通知 @Before(value="execution(.....)"))

    • spring配置文件

      <?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.xsd
                              http://www.springframework.org/schema/aop
                              http://www.springframework.org/schema/aop/spring-aop.xsd">
      <!--    扫描-->
          <context:component-scan base-package="com.aopanno"></context:component-scan>
          <!--开启AspectJ 生成代理对象-->
          <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
      </beans>
      
  5. 公共切入点提取

    • //配置通知类型
          //前置通知
          @Before(value = "pointCut()")
          public void before() {
              System.out.println("before....");
          }
          //在方法返回值之后执行
          @AfterReturning(value = "pointCut()")
          public void afterReturning() {
              System.out.println("AfterReturning");
          }
          //后置, 方法执行后执行
          @After(value = "pointCut()")
          public void after() {
              System.out.println("after");
          }
          //异常
          @AfterThrowing(value = "pointCut()")
          public void afterThrowing() {
              System.out.println("AfterThrowing");
          }
      
          //环绕, 方法执行之前之后都执行
          @Around(value = "pointCut()")
          public void around() {
              System.out.println("Around");
          }
       
       //切入点抽取
          @Pointcut(value = "execution(* com.aopanno.User.add(..))")
          public void pointCut() {
      
          }
      
      
  6. 多个增强类对同一个方法增强, 需要设置执行优先级

    • 在增强类的上边添加注解@Order(数值) 数值越小,优先级越高

  7. 配置文件操作

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
        <bean id="book" class="com.aopxml.Book">
    
        </bean>
        <bean id="bookProxy" class="com.aopxml.BookProxy">
    
        </bean>
    <!--    配置aop增强-->
        <aop:config>
    <!--        配置切入点-->
            <aop:pointcut id="p" expression="execution(* com.aopxml.Book.add(..))"/>
    <!--        配置切面-->
            <aop:aspect ref="bookProxy">
                <!--这个p就是上边的id属性值-->
                <aop:before method="before" pointcut-ref="p"/>
            </aop:aspect>
        </aop:config>
    </beans>
    
  8. 完全注解方式(需要配置类)

    @Configuration
    @ComponentScan(basePackages = {"com.aopanno"})
    @EnableAspectJAutoProxy(exposeProxy = true)
    public class ConfigAop {
    }
    

3.JdbcTemplate

3.1 操作

  • dao层与数据库连接, service 与到层连接, 所以在dao层注入jdbcTemplate, 在service注入dao

<?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">
<!--    组件扫描-->
    <context:component-scan base-package="com"></context:component-scan>
<!--    properties文件目录-->
    <context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
    <!--druid获取连接的-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${driverClassName}"></property>
        <property name="url" value="${url}"></property>
        <property name="username" value="${username}"></property>
        <property name="password" value="${password}"></property>
    </bean>
<!--    创建jdbcTemplate对象-->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
</beans>
  • dao层

@Repository
public class UserDaoImpl implements UserDao {
    @Autowired
    private JdbcTemplate jdbcTemplate;//创建对象
}
  • service层

@Service
public class UserService {

    @Autowired
    private UserDao userDao;
}
jdbc.driverClassName=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/test?characterEncoding=utf8&useUnicode=true&useSSL=false&serverTimezone=UTC
jdbc.username=root
jdbc.password=990808

==spring不要写username==

下边是对一条记录的CRUD的相应方法

@Repository
public class UserDaoImpl implements UserDao {

    @Autowired
    private JdbcTemplate jdbcTemplate;//创建对象

    @Override
    public void add(User user) {

        String sql = "insert into user values(?,?,?,?,?)";
        int update = jdbcTemplate.update(sql, user.getId(),user.getName(), user.getPassword(), user.getAddress(), user.getPhone());
        System.out.println("userDao" + update);
    }

    @Override
    public User queryById(Integer id) {
        String sql = "select * from user where id=?";
        return jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<>(User.class), id);
    }

    @Override
    public List<User> queryForList() {
        String sql = "select * from user";
        return jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(User.class));
    }

    @Override
    public int findCount() {
        String slq = "select count(*) from `user`";
        return jdbcTemplate.queryForObject(slq, Integer.class);
    }


}

==批量insert==, (update, delete 同理)

@Override
    public void batchAdd(List<Object[]> users) {
        String sql = "insert into user values(?,?,?,?,?)";
        jdbcTemplate.batchUpdate(sql, users);
    }

4. 事务(Transaction)

4.1 基本概念

指的是数据库操作的基本单元,逻辑上是一组操作,要么都成功,要么都失败,事务由事务开始(begin transaction)和事务结束(end transaction)之间执行的全体操作组成。

4.2 特性(ACID)

  1. 原子性(atomicity)

    一个事务是一个不可分割的工作单位,事务中包括的操作要么都做,要么都不做。

  2. 一致性(consistency)

    事务必须是使数据库从一个一致性状态变到另一个一致性状态。一致性与原子性是密切相关的。

  3. 隔离性(isolation)

    一个事务的执行不能被其他事务干扰。即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。

  4. 持久性(durability)

    持久性也称永久性(permanence),指一个事务一旦提交,它对数据库中数据的改变就应该是永久性的。接下来的其他操作或故障不应该对其有任何影响。

4.3 Spring事务管理的操作

  • 一般加在service层上,有两种方式,编程方式和声明式(主要使用)

  • 声明式的管理方式

  1. 注解(使用)

  2. xml配置文件

  • 底层使用了AOP

  • API

    interface platformTranscationManager
    

4.4 注解方式实现事务管理

  1. 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:tx="http://www.springframework.org/schema/tx"
           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/tx
                               http://www.springframework.org/schema/tx/spring-tx.xsd
                               http://www.springframework.org/schema/aop
                               http://www.springframework.org/schema/aop/spring-aop.xsd">
    <!--    组件扫描-->
        <context:component-scan base-package="com"></context:component-scan>
    <!--    properties文件-->
        <context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
    <!--    dataSource对象-->
        <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
            <property name="driverClassName" value="${jdbc.driverClassName}"></property>
            <property name="url" value="${jdbc.url}"></property>
            <property name="username" value="${jdbc.username}"></property>
            <property name="password" value="${jdbc.password}"></property>
        </bean>
    <!--    jdbcTemplate对象-->
        <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    <!--        数据源-->
            <property name="dataSource" ref="dataSource"></property>
        </bean>
    <!--    创建事务管理-->
        <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <!--        引入数据源-->
            <property name="dataSource" ref="dataSource"></property>
        </bean>
    <!--    事务注解-->
        <tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
    
    </beans>
    
  2. 在service添加注解

    @Service
    @Transactional//可以加到类上也可以加到方法上
    public class UserService {
        @Autowired
        private UserDao userDao;
    
        public void account(UserTable userTable) {
            userDao.add(userTable);
            userDao.reduce(userTable);
        }
    }
    
  • 细节

    1. propagation事务的传播行为
      • ==PROPAGATION_REQUIRED==:如果当前没有事务,就创建一个新事务,如果当前存在事务,就加入该事务,这是最常见的选择,也是Spring默认的事务传播行为。(required需要,没有新建,有加入)

      • PROPAGATION_SUPPORTS:支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就以非事务执行。(supports支持,有则加入,没有就不管了,非事务运行)

      • PROPAGATION_MANDATORY:支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就抛出异常。(mandatory强制性,有则加入,没有异常)

      • ==PROPAGATION_REQUIRES_NEW==:创建新事务,无论当前存不存在事务,都创建新事务。(requires_new需要新的,不管有没有,直接创建新事务)

      • PROPAGATION_NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。(not supported不支持事务,存在就挂起)

      • PROPAGATION_NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。(never不支持事务,存在就异常)

      • PROPAGATION_NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则按REQUIRED属性执行。(nested存在就在嵌套的执行,没有就找是否存在外面的事务,有则加入,没有则新建)

    2. 事务的隔离级别

    三个并发问题

    • 脏读(==接受不了==)

      • 一个未提交的事务读取到了另一个未提交的事务的数据

      • A事务正在修改数据但未提交,此时B事务去读取此条数据,B事务读取的是未提交的数据,A事务回滚。B事务读的内容就是临时且无效的

    • 不可重复读(正常)

      • 一个未提交的事务读到了一个已经提交的事务

      • A事务读了一个字段,B事务更新了,然后提交了, 之后A 事务再一次读同一个字段, 值就不一样了。

    • 幻读()

      • 一个未提交的事务读到了一个已经提交的事务

      • 在同一事务中两次相同查询数据的条数不一致,例如第一次查询查到5条数据,第二次查到8条数据,这是因为在两次查询的间隙,另一个事务插入了3条数据

    隔离级别

    • **READ UNCOMMITTED **

      读未提交, 以上三种问题都没解决

    • **READ COMMITTED ** 

      读已提交 解决了脏读

    • REPEATABLE READ ==MySQL默认==

      可重复读 解决了脏读 不可重复读

    • SERILIZABLE

      串行化 解决了三个问题

    配置隔离级别

    @Transactional(propagation = Propagation.REQUIRED, isolation= Isolation.READ_UNCOMMITTED)//可以加到类上也可以加到方法上
    
    1. timeout 超时

      事务需要在一定的时间内提交, 不然会rollback

    2. readOnly

      读:查询操作, 写:添加修改删除操作

      默认值是 false

    3. rollbackFor

      设置出现哪些异常进行事务的回滚

    4. noRollBack

      设置出些哪些异常不进行事务的回滚

@Transactional(readOnly = false, timeout = -1, propagation = Propagation.REQUIRED, isolation= Isolation.READ_UNCOMMITTED)//可以加到类上也可以加到方法上

4.5 xml方式实现事务管理

  1. 步骤

    • 配置事务管理器

    • 配置通知

    • 配置切入点和切面

<?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:tx="http://www.springframework.org/schema/tx"
       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/tx
                           http://www.springframework.org/schema/tx/spring-tx.xsd
                           http://www.springframework.org/schema/aop
                           http://www.springframework.org/schema/aop/spring-aop.xsd">
    <!--    组件扫描-->
    <context:component-scan base-package="com"></context:component-scan>
    <!--    properties文件-->
    <context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
    <!--    dataSource对象-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${jdbc.driverClassName}"></property>
        <property name="url" value="${jdbc.url}"></property>
        <property name="username" value="${jdbc.username}"></property>
        <property name="password" value="${jdbc.password}"></property>
    </bean>
    <!--    jdbcTemplate对象-->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <!--        数据源-->
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    <!--    创建事务管理-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!--        引入数据源-->
        <property name="dataSource" ref="dataSource"></property>
    </bean>
   
<!--    配置通知-->
    <tx:advice id="txadvice">
<!--        配置事务参数-->
        <tx:attributes>
            <tx:method name="account" propagation="REQUIRED" isolation="READ_COMMITTED"/>
        </tx:attributes>
    </tx:advice>
    <aop:config >
<!--        配置切面-->
        <aop:pointcut id="pt" expression="execution(* com.service.UserService.*(..))"/>
<!--        配置切入点-->
        <aop:advisor advice-ref="txadvice" pointcut-ref="pt"></aop:advisor>
    </aop:config>
</beans>

4.5完全注解

配置类

@Configuration//配置类
@ComponentScan(basePackages = "com")//组件扫描
@EnableTransactionManagement//开启事务
public class TxConfig {

    //数据源, 连接池
    @Bean
    public DruidDataSource getDruidDataSource() {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://localhost:3306/test");
        dataSource.setUsername("root");
        dataSource.setPassword("990808");
        return dataSource;
    }

    @Bean
    public JdbcTemplate getJdbcTemplate(DataSource dataSource) {
//     ioc容器中找到DataSource类型,然后完成注入
        JdbcTemplate jdbcTemplate = new JdbcTemplate();
        jdbcTemplate.setDataSource(dataSource);
        return jdbcTemplate;
    }

//    创建事务管理对象
    @Bean
    public DataSourceTransactionManager getDataSourceTransactionManager(DataSource dataSource) {
        DataSourceTransactionManager dataSourceTransactionManager =
                new DataSourceTransactionManager();
        dataSourceTransactionManager.setDataSource(dataSource);
        return dataSourceTransactionManager;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值