从零开始学Java-11 Spring

什么是Spring

Spring是分层的Java SE/EE应用 full-stack 轻量级开源框架,以IOC(反转控制)和AOP(面向切面编程)为内核

配置文件

名称:随便,但是不要有中文

位置:随便

<?xml version="1.0" encoding="UTF-8"?>
<!-- 导入约束
spring-framework-4.2.4.RELEASE/docs/spring-framework-reference/html/xsd-configuration.html
 -->
<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">
    <!-- 创建对象 -->
    <bean id="customerService" class="com.leiyuee.service.impl.CustomerServiceImpl"></bean>
    <bean id="customerDao" class="com.leiyuee.dao.impl.CustomerDaoImpl"></bean>
</beans>

编写测试类

public class Client {
    /**
     * Spring的IOC入门
     *
     * Spring的容器接口:
     *      ApplicationContext
     *      
     * 他的实现类:
     *      ClassPathXmlApplicationContext:  解析的是类路径下的xml文件
     *      FileSystemXmlApplicationContext: 找的是系统磁盘任意位置的xml文件
     */
    public static void main(String[] args) {
        //根据配置文件构建一个工厂
        ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
        //根据id获取bean
        ICustomerService cs = (ICustomerService) ac.getBean("customerService");
        ICustomerDao cd = (ICustomerDao) ac.getBean("customerDao");
        //输出内存地址
        System.out.println(cs);
        System.out.println(cd);
    }
}

一、IoC

IoC(Inversion of Control):控制反转,实例的创建交给spring来管理,对象的创建,并不是在代码中用new操作new出来的,而是通过Spring进行配置创建的。

DI(Dependency Injection):依赖注入,spring管理某个类的时候会将该类依赖的属性注入进来,也就是注入类里面的属性值

底层原理:工厂设计模式+反射+XML配置文件

public class Client {
    /**
     * Spring的IOC入门
     *
     * Spring的容器接口:
     *      ApplicationContext:容器启动的时候创建容器中配置的所有对象
     *      
     * 他的实现类:
     *      ClassPathXmlApplicationContext:  解析的是类路径下的xml文件  【推荐】
     *      FileSystemXmlApplicationContext: 找的是系统磁盘任意位置的xml文件
     *      
     * 早期的API:
     *      接口:BeanFactory:每次获得对象的时候才会创建对象
     *      实现类: XmlBeanFactory
     *      
     * 早期的api和现在的api的区别:
     *      早期的api:使用了延迟加载的策略
     *      现在的api:使用立即加载的策略
     *
     *      主要是由于IT技术的发展,内存的普及
     *
     * 这些api的获取bean的方法:
     *      getBean();
     *      此方法的参数是bean在容器的id【就是bean标签对应的id属性的取值】
     */
    @SuppressWarnings("all")
    public static void main(String[] args) {
        //根据配置文件构建一个工厂
        //类路径下读取配置文件
//        ApplicationContext ac = new ClassPathXmlApplicationContext("/com/leiyuee/ui/bean.xml");
        ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
       //从文件系统读取配置文件
//        ApplicationContext ac = new FileSystemXmlApplicationContext("src/bean.xml");//相对路径
//        ApplicationContext ac = new FileSystemXmlApplicationContext("C:\\workspace\\SpringIOC_BeanFactory\\src\\bean.xml");//绝对路径
        //早期的API
//        Resource res = new ClassPathResource("bean.xml");
//        BeanFactory ac = new XmlBeanFactory(res);
        //根据id获取bean
        ICustomerService cs = (ICustomerService) ac.getBean("customerService");
        ICustomerDao cd = (ICustomerDao) ac.getBean("customerDao");
        //输出内存地址
        System.out.println(cs);
        System.out.println(cd);
    }
}

Spring的配置文件解释

<?xml version="1.0" encoding="UTF-8"?>
<!-- 导入约束
spring-framework-4.2.4.RELEASE/docs/spring-framework-reference/html/xsd-configuration.html
 -->
<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">
    <!-- 创建对象 -->
    <!--
bean标签: 配置的是要管理的对象,也就是bean
     属性:
     id:是bean在容器的唯一标识,不能重复
     class:类的全限定名,框架通过反射技术创建出来的对象,默认调用的无参的构造方法创建对象
     scope: 类的作用范围
     singleton : 单例【默认值】    : Service 和 Dao 都用单例
     prototype : 多例      : Action用多例
     request: 一次请求一个实例【了解】
     session: 一个会话一个实例【了解】     
     init-method: 初始化的方法
     destroy-method : 销毁的方法     
     bean的生命周期:
     singleton : 单例
     1)什么时候出生  :容器被创建它就出生
     2)什么时候活着   : 容器在,它就在
     3)什么时候死亡  : 容器销毁,它就死亡
     prototype : 多例
     1)什么时候出生 : 调用getBean的时候才出生
     2)什么时候活着 : 只要有引用就一直活着
     3)什么时候死亡 : 没有引用等着垃圾回收机制回收
     -->
    <bean id="customerService" 
       class="com.leiyuee.service.impl.CustomerServiceImpl" 
       scope="prototype"
       init-method="init"
       destroy-method="des"
       ></bean>
    <bean id="customerDao" class="com.leiyuee.dao.impl.CustomerDaoImpl"></bean>
</beans>

1、依赖注入

1.1 构造方法注入

<?xml version="1.0" encoding="UTF-8"?>
<!-- 导入约束
spring-framework-4.2.4.RELEASE/docs/spring-framework-reference/html/xsd-configuration.html
 -->
<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">
    <bean id="customerService" 
       class="com.leiyuee.service.impl.CustomerServiceImpl" 
       scope="prototype"
       init-method="init"
       destroy-method="des"
       ></bean>
    <bean id="customerDao" class="com.leiyuee.dao.impl.CustomerDaoImpl"></bean>
</beans>

1.2 set方法注入

1)给全局属性提供set方法

public class CustomerServiceImpl implements ICustomerService {
    //set方法注入
    private String name;
    private Integer age;
    private Date birthday;
    public void setName2(String name) {
        this.name = name;
    }
    public void setAge(Integer age) {
        this.age = age;
    }
    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }
    @Override
    public void saveCustomer() {
        System.out.println(name);
        System.out.println(age);
        System.out.println(birthday);
    }
}

2)在配置文件中使用property标签

<?xml version="1.0" encoding="UTF-8"?>
<!-- 导入约束
spring-framework-4.2.4.RELEASE/docs/spring-framework-reference/html/xsd-configuration.html
 -->
<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">
    <!-- 创建对象 -->
    <bean id="customerService" class="com.leiyuee.service.impl.CustomerServiceImpl" >
     <!--
     1) 通过构造方法注入:了解
     constructor-arg标签注入属性:有几个参数就有几个标签
     属性:
     index: 构造方法的参数的索引,从0开始
     name : 构造方法的参数名称【用这种就够】
     type : 构造方法的参数的数据类型
     ===============上面是往哪里赋值===下面是赋什么值
     value: 注入基本数据类型和String
     ref:   其他的bean类型,其他的bean的id      
      <constructor-arg name="name2" value="金刚狼" />
      <constructor-arg name="age" value="300" />
      <constructor-arg name="birthday" ref="now"/>
       2)通过set方法注入: 重中之重
       property标签:通过set方法注入,找的set方法后面的字符串,首字母小写
       属性:
       name:找的set方法后面的字符串,首字母小写
       value: 注入基本数据类型和String
       ref: 其他的bean类型,其他的bean的id
      -->
     <constructor-arg name="name2" value="金刚狼" />
      <constructor-arg name="age" value="300" />
      <constructor-arg name="birthday" ref="now"/>
      <property name="name2" value="小鸭鸭"></property>
      <property name="age" value="20"></property>
      <property name="birthday" ref="now"></property>
    </bean>
    <bean id="now" class="java.util.Date"></bean>
</beans>

1.3 复杂数据类型的注入

<?xml version="1.0" encoding="UTF-8"?>
<!-- 导入约束
spring-framework-4.2.4.RELEASE/docs/spring-framework-reference/html/xsd-configuration.html
 -->
<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">
    <bean id="customerService" class="com.leiyuee.service.impl.CustomerServiceImpl" >
     <!--
     1) 通过构造方法注入:了解
     constructor-arg标签注入属性:有几个参数就有几个标签
     属性:
     index: 构造方法的参数的索引,从0开始
     name : 构造方法的参数名称【用这种就够】
     type : 构造方法的参数的数据类型
     ===============上面是往哪里赋值===下面是赋什么值
     value: 注入基本数据类型和String
     ref:   其他的bean类型,其他的bean的id      
      <constructor-arg name="name2" value="金刚狼" />
      <constructor-arg name="age" value="300" />
      <constructor-arg name="birthday" ref="now"/>
       2)通过set方法注入: 重中之重
       property标签:通过set方法注入,找的set方法后面的字符串,首字母小写
       属性:
       name:找的set方法后面的字符串,首字母小写
       value: 注入基本数据类型和String
       ref: 其他的bean类型,其他的bean的id
       3)注入复杂数据类型
       用的也是property 标签,是什么类型就用什么标签
       数据结构相同,标签可以互换: list 和 map 就够了
      -->
      <property name="myArray" >
       <set>
       <value>eee</value>
       <value>fff</value>
       </set>
      </property>      
      <property name="myList">
       <array>
       <value>aaa</value>
       <value>bbb</value>
       </array>
      </property>      
      <property name="mySet">
       <list>
       <value>ccc</value>
       <value>ddd</value>
       </list>
      </property>
      <property name="myMap">
       <props>
       <prop key="a1" >iii</prop>
       <prop key="a2" >jjj</prop>
       </props>
      </property>
      <property name="myProp">
       <map> <entry key="k1" value="ggg"></entry> <entry key="k2" value="hhh"></entry>
       </map>
      </property>
    </bean>
</beans>

2、注解

导包

在类的根路径下创建一个任意名称的XML文件(不能是中文-- bean-xml)

使用@Component注解配置管理的资源

/**
 * <!-- 创建对象 -->
    <bean id="customerService" class="com.leiyuee.service.impl.CustomerServiceImpl">
        <property name="customerDao" ref="customerDao"></property>
    </bean>    
 *  ====================================
 *  1、创建对象的注解
 *  @Component : 组件的意思,它是用于创建对象的,把当前的对象放入Spring的容器中
 *          1)如果没有其他的属性,id是短的类名,首字母小写
 *              把这个组件写在类上,就相当于把类交给Spring管理       
 */
@Component  
 // 相当于: <bean id="customerServiceImpl" class="com.leiyuee.service.impl.CustomerServiceImpl"/>
public class CustomerServiceImpl implements ICustomerService {
    private ICustomerDao customerDao;
    public void setCustomerDao(ICustomerDao customerDao) {
        this.customerDao = customerDao;
    }
    @Override
    public void saveCustomer() {
        customerDao.save();
    }
}

编写配置文件,告诉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"
     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我们的创建对象注解在哪里
     1)导入一个context的名称空间
     2)开启创建对象注解【组件】的扫描
     context:component-scan
     属性:
     base-package : 写上要扫描的基础包,简称基包
     -->
     <context:component-scan base-package="com.leiyuee"></context:component-scan>
</beans>

2.1 常用注解

/**
 * <!-- 创建对象 -->
    <bean id="customerService" class="com.leiyuee.service.impl.CustomerServiceImpl">
        <property name="customerDao" ref="customerDao"></property>
    </bean>
 *
 *  ====================================
 *  1、创建对象的注解
 *  @Component : 组件的意思,它是用于创建对象的,把当前的对象放入Spring的容器中
 *          1)如果没有value的属性,id是短的类名,首字母小写
 *              把这个组件写在类上,就相当于把类交给Spring管理
 *                  例如: @Component   
 *                      // 相当于: <bean id="customerServiceImpl" class="com.leiyuee.service.impl.CustomerServiceImpl"/>
 *          2)如果有value属性,id就是value的取值
 *                  例如: @Component(value="customerService")   |  @Component("customerService")   
 *                      // 相当于: <bean id="customerService" class="com.leiyuee.service.impl.CustomerServiceImpl"/>
 *  ------------------------------------------------
 *  @Component 注解衍生的三个注解 ,为了三层架构衍生出来  
 *              web层: @Controller
 *          service层: @Service
 *              dao层: @Repository
 *          
 *          这三个注解和Component注解一模一样,没有任何区别
 *          
 *  2、Spring容器中对象的作用范围:单例和多例的问题
 *           <bean id="customerServiceImpl"
 *                 class="com.leiyuee.service.impl.CustomerServiceImpl"
 *                 scope="singleton【默认】|prototype|request|session"/>
 *     @Scope : 指定对象的作用范围,也就是单例或者多例,它与bean标签中的scope属性一致
 *            属性:
 *            value: 指定单例或者多例
 *                  singleton:单例
 *                  prototype:多例
 *                  
 *  -------------------------------------------------------
 *  3、依赖注入的注解:
 *      @Autowired 【推荐】: 跟类型自动注入,如果用了这个注解,set方法就不是必须的
 *          1)当容器中只有一个对象,自动注入
 *          2)当容器中有多个对象,以属性的名称作为key,去Spring容器中查找对象注入
 *                  找得到就注入
 *                  找不到就发烂渣【抛异常】
 *                  
 *      @Qualifier : 
 *          1)在Autowired的基础上使用,它的value的属性指定的是容器中bean的id
 *          2)如果在方法参数上使用,可以单独使用,
 *              
 *      @Resource 【推荐】:
 *          1)如果不写任何属性它的作用与 @Autowired 一样
 *          2)如果有容器中有多个bean,那么需要指定bean的id,用name属性
 *          
 *      @Value : 注入其他的数据类型:基本数据类型和String
 *                  它里面可以Spring的EL表达式,等会讲        
 */
//@Component   // 相当于: <bean id="customerServiceImpl" class="com.leiyuee.service.impl.CustomerServiceImpl"/>
//@Component("customerService")   // 相当于: <bean id="customerService" class="com.leiyuee.service.impl.CustomerServiceImpl"/>
@Service("customerService")   // 相当于: <bean id="customerService" class="com.leiyuee.service.impl.CustomerServiceImpl"/>
//@Scope(value="singleton")
@Scope("singleton")
public class CustomerServiceImpl implements ICustomerService {    
    /*@Autowired//根据类型自动注入
    @Qualifier("cd2")//value的属性指定的是容器中bean的id*/        
    @Resource(name="cd")
    private ICustomerDao customerService=null;    
    @Value("张三")
    private String name;    
    @Value("18")
    private Integer age;    
    @Override
    public void saveCustomer() {
        customerService.save();
        System.out.println(name);
        System.out.println(age);
    }
}

2.2 纯注解

  • 配置类
/**
 *  @Configuration : 这个注解就是生命当前类是一个配置类,spring就会扫描此类上的其他注解
 *  @ComponentScan : 指定扫描的基础包
 *          属性:
 *          basePackages : 指定要扫描的基包
 *          value        : 指定要扫描的基包
 */
@Configuration
//@ComponentScan(basePackages={"com.leiyuee"})
//@ComponentScan(value={"com.leiyuee"})
@ComponentScan("com.leiyuee")
public class SpringConfiguration {
}
  • 容器实现类
public static void main(String[] args) {
        //1、获取Spring的容器
        ApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfiguration.class);
        //2、根据id获取Bean
        ICustomerService cs = (ICustomerService) ac.getBean("customerService");
//        ICustomerService cs2 = (ICustomerService) ac.getBean("customerService");
//        ICustomerDao cd = (ICustomerDao) ac.getBean("cd");
        CustomerDaoImpl cd = (CustomerDaoImpl) ac.getBean("cd");
        /*if(cd instanceof ICustomerDao){
            System.out.println("是这个接口类型:ICustomerDao");
        }else{
            System.out.println("不是这个接口类型:ICustomerDao");
        }*/
        //3、测试
        System.out.println(cs);
        System.out.println(cd);
        cs.saveCustomer();
    }

1)Bean注解

//@Component //<bean id="jdbcConfig" class="com.leiyuee.config.JdbcConfig"/>
public class JdbcConfig {
    /**
     * @Bean 注解:把方法的返回值交给Spring管理
     *      1)如果指定了name属性:那么bean的id是属性的取值
     *              定义:@Bean(name="ds")
     *              获取:ac.getBean("ds");
     *      2)如果不指定name属性:那么bean的id是方法名,不要后面的括号
     *              定义:@Bean
     *              获取:ac.getBean("createDs");
     */
    @Bean(name="ds")//<bean id="ds" class="com.mchange.v2.c3p0.ComboPooledDataSource"/>
    public DataSource createDs() throws Exception{
        ComboPooledDataSource ds = new ComboPooledDataSource();
        ds.setDriverClass("com.mysql.jdbc.Driver");
        ds.setJdbcUrl("jdbc:mysql://localhost:3306/test");
        ds.setUser("root");
        ds.setPassword("root");
        return ds;
    }
}

2)Import注解

/**
 *  @Configuration : 这个注解就是生命当前类是一个配置类,spring就会扫描此类上的其他注解   
 *  @ComponentScan : 指定扫描的基础包
 *          属性:
 *          basePackages : 指定要扫描的基包
 *          value        : 指定要扫描的基包
 *  
 *  @Import :导入其他的配置类
 *          只有一个value属性,指定的是配置类的字节码对象
 */
@Configuration
//@ComponentScan(basePackages={"com.leiyuee"})
//@ComponentScan(value={"com.leiyuee"})
@ComponentScan("com.leiyuee")
@Import(JdbcConfig.class)
public class SpringConfiguration {
}

二、AOP

Aspect Oriented Programming--面向切面编程

     把程序重复的代码抽取出来,在需要执行的时候,使用动态代理的技术,在不修改源代码的基础上,对我们已有的方法进行增强。

作用:-在程序运行期间,不修改源代码对已有方法进行增强

优势:-减少重复代码  提高开发效率  维护方法


动态代理的特点 -字节码随用随创建,随用随加载

基于接口的动态代理

  提供者:JDK官方的Proxy类

  要求:被代理类最少实现一个接口

基于子类的动态代理

  提供者:第三方的CGLib,如果报asmxxx异常,需要导入asm.jar

  要求:被代理类不能用final修饰的类(最终类).

<?xml version="1.0" encoding="UTF-8"?>
<!--
导入约束
找文档:spring-framework-4.2.4.RELEASE/docs/spring-framework-reference/html/xsd-configuration.html
-->
<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
        http://www.springframework.org/schema/aop/spring-aop.xsd">
    <!-- 创建对象 -->
    <bean id="customerService" class="com.leiyuee.service.impl.CustomerServiceImpl"></bean>
<!-- Spring的AOP配置步骤 -->
<!-- 第一步:导入aop的jar包 -->
<!-- 第二步:把通知类交给Spring管理 -->
<bean id="myLog" class="com.leiyuee.utils.Logger"></bean>
<!-- 第三步:AOP的配置 -->
<aop:config>
<!-- 配置全局切入点:配置在aspect标签外面 -->
<aop:pointcut expression="execution(* com.leiyuee.service.impl.*.*(..))" id="pt1"/>
<!-- 第四步:配置切面 : id属性是切面的唯一标识 ; ref属性:引用通知类,引用了通知类之后,这个通知类就变成切面类-->
<aop:aspect id="myAspect" ref="myLog">
 <!--  aop:before : 前置通知: 在业务方法之前执行
 <aop:before method="beforePrintLog" pointcut-ref="pt1"/>
 后置通知 :当业务方法正常执行时,才执行
 <aop:after-returning method="afterReturnningPrintLog" pointcut-ref="pt1"/>
 异常通知:当业务方法有异常的时候,才执行
 <aop:after-throwing method="afterThrowingPrintLog" pointcut-ref="pt1"/>
 最总通知:不管业务方法有无异常,都会执行
 <aop:after method="afterPrintLog" pointcut-ref="pt1"/> -->
 <!-- 环绕通知: 详情请看通知类:Logger中的aroundPrintLog方法 -->
 <aop:around method="aroundPrintLog" pointcut-ref="pt1"/>
</aop:aspect>
</aop:config>
</beans>

切入点表达式

切入点表达式的写法:

修饰符  返回类型  包名.包名...类名.方法名(参数列表)

全匹配法:

public void com.leiyuee.service.impl.CustomerServiceImpl.saveCustomer()

修饰符:可以省略

void com.leiyuee.service.impl.CustomerServiceImpl.saveCustomer()

返回类型:可以使用*号代替任意的返回类型

* com.leiyuee.service.impl.CustomerServiceImpl.saveCustomer() 

包名:可以使用一个*号代替一个包

* *.*.*.*CustomerServiceImpl.saveCustomer()

包名:可以使用..代表当前包及其子包

* *..CustomerServiceImpl.saveCustomer()

类名:可以使用*号代替任意类名

* *..*.saveCustomer()

方法名:可以使用*号代替任意方法名

* *..*.*()

参数列表:可以使用一个*号代替一个参数,不包括无参

* *..*.*(*)

参数列表:可以使用..代表任意参数,包括无参

* *..*.*(..)

全通配法:【一般不用,如果用的话,小心点,小心切到自己】

* *..*.*(..)

建议用法:只切到某一层

例如: * com.leiyuee.service.impl.*.*(..)

/**
 * 此类是个通知类【切面类】
 */
public class Logger {
    // 通知方法:前置
    public void beforePrintLog(){
        System.out.println("前置通知:打印日志");
    }
    // 通知方法:后置
    public void afterReturnningPrintLog(){
        System.out.println("后置通知:打印日志");
    }
    // 通知方法:异常 
    public void afterThrowingPrintLog(){
        System.out.println("异常通知:打印日志");
    }
    // 通知方法:最终
    public void afterPrintLog(){
        System.out.println("最终通知:打印日志");
    }
}
//环绕通知
/**
     * 环绕通知:
     *      这个通知比较特殊,需要我们手动执行业务方法
     * 需要用到一个参数:ProceedingJoinPoint
     *      这个是个接口,我们不用管,是spring给我们注入的
     *      
     * 此接口有一个放行的方法:
     *      proceed();
     */
    @Around("pt1()")
    public void aroundPrintLog(ProceedingJoinPoint pjp){
        try {
            //前置通知
            System.out.println("前置通知: 打印了日志");
            //业务层方法
            pjp.proceed();
            //后置通知
            System.out.println("后置通知: 打印了日志");
        } catch (Throwable e) {
            //异常通知
            System.out.println("异常通知:打印了日志");
            e.printStackTrace();
        }finally{
            System.out.println("最终通知:打印了日志");
        }
    }

三、事务

1、基本特性

⑴ 原子性(Atomicity)原子性是指事务包含的所有操作要么全部成功,要么全部失败回滚,因此事务的操作如果成功就必须要完全应用到数据库,如果操作失败则不能对数据库有任何影响。

⑵ 一致性(Consistency)一致性是指事务必须使数据库从一个一致性状态变换到另一个一致性状态,也就是说一个事务执行之前和执行之后都必须处于一致性状态。

⑶ 隔离性(Isolation)隔离性是当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。

⑷ 持久性(Durability)持久性是指一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。

2、Spring中事务的分类

2.1 编程式事务控制

  自己手动控制事务,就叫做编程式事务控制。

       Jdbc代码:

              Conn.setAutoCommit(false);  // 设置手动控制事务

       Hibernate代码:

              Session.beginTransaction();    // 开启一个事务

       【细粒度的事务控制: 可以对指定的方法、指定的方法的某几行添加事务控制】

       (比较灵活,但开发起来比较繁琐: 每次都要开启、提交、回滚.)

2.2声明式事务控制

 Spring提供了对事务的管理, 这个就叫声明式事务管理。

       Spring提供了对事务控制的实现。用户如果想用Spring的声明式事务管理,只需要在配置文件中配置即可; 不想使用时直接移除配置。这个实现了对事务控制的最大程度的解耦。

       Spring声明式事务管理,核心实现就是基于Aop。

       【粗粒度的事务控制: 只能给整个方法应用事务,不可以对方法的某几行应用事务。】

       (因为aop拦截的是方法。)

       Spring声明式事务管理器类:

              Jdbc技术:DataSourceTransactionManager

              Hibernate技术:HibernateTransactionManager

2.3 使用

1.xml文件中 <tx:annotation-driven/>

2. 在需要管理的方法或者类上声明

@Transactional(isolation=Isolation.REPEATABLE_READ,readOnly=false,propagation=Propagation.REQUIRED

以上为个人学习总结,如有错漏,希望能得到沟通以及指正,非常感谢!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值