ssm黑马程序员之Spring

Spring  

1.概述

spring framework:最早,设计型,底层框架

spring boot:加速开发

spring cloud:分布式开发

2.Spring Framework架构的基本学习内容

学习内容:

1.核心容器Ioc

2.数据继承Mybatis

3.面向切面AOP

4.事务:事务实用开发

3.IOC原理

为了降低耦合,提供一个IOC容器,来充当new对象的作用

IOC管理的对象,称为Bean。

但是service创建对象需要用到DAO层呀,所以他们俩是相互依赖的。IOC容器就顺便把service和dao依赖绑定了。我们称为依赖注入,也称为DI

最终效果:使用对象时,1可以从IOC容器中获取,2而且获取的Bean3已经注入好依赖了

4.IOC案例思路分析

1.导入spring和spring frame的坐标pom.xml

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.2.10.RELEASE</version>
    </dependency>

2.写好要作为Bean调用的接口和实现类(bean标签  id定义名字  class代表实现类)

package com.itheima.dao.impl;

import com.itheima.dao.BookDao;

public class BookDaoImpl implements BookDao {
    public void save() {
        System.out.println("book dao save ...");
    }
}
package com.itheima.dao;

public interface BookDao {
    public void save();
}

3.再resourse里面创建iml,来进行spring的配置

 <!--2.配置bean-->
    <!--bean标签标示配置bean
    id属性标示给bean起名字
    class属性表示给bean定义类型-->
    <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/>

    <bean id="bookService" class="com.itheima.service.impl.BookServiceImpl"/>

4.利用IOC来进行调用Bean

        //3.获取IoC容器
        ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml");
        //4.获取bean(根据bean配置id获取)
        BookDao bookDao = (BookDao) ctx.getBean("bookDao");
        BookService bookService = (BookService) ctx.getBean("bookService");
        bookDao.save();

IOC实例的应用:

5.DI

不能new 对象,要从外面传参。所以要写一个set方法,从外面传进去

//5.删除业务层中使用new的方式创建的dao对象
   private BookDao bookDao;
 //6.提供对应的set方法
    public void setBookDao(BookDao bookDao) {
        this.bookDao = bookDao;
    }

配置Dao和Service的关系,在大的里面配置

第一个name对于的java代码里面的变量名

第二个对应着xml里面的bean的id

 <bean id="bookService" class="com.itheima.service.impl.BookServiceImpl">
        <!--7.配置server与dao的关系-->
        <!--property标签表示配置当前bean的属性
        name属性表示配置哪一个具体的属性
        ref属性表示参照哪一个bean-->
        <property name="bookDao" ref="bookDao"/>
<!--        <property name="bookDao" ref="bookDao"></property>-->
    </bean>

 

 

6.Bean的基础配置

name和id的效果一样,都可以写在ref里面进行引用;也可以再getBean里面引用

id里面只能写一个,name里面可以写多个(可以用,   ;   空格三种来进行分割)

spring默认ioc创建的对象是单例的(scope    单例:singleon    多例:prototype)

单例适合那些通用的;多例适合那些有状态的,每个都不一样的

7.bean如何实例化对象的

构造方法

无参构造(public,private)都可以

报错的话,从后面往前看,一般先看最后一句,不行再往上看

如果没有写无参构造方法,会抛出异常BeanCreationException

    public BookDaoImpl(){
        System.out.println("BookDaoImpl ...");
    }
    <!--方式一:构造方法实例化bean-->
<!--    <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/>-->

Bean静态工厂(了解即可)

造对象不要自己new,要用工厂new,可以一定程度上解耦。接口,实现类,静态工厂是三件套。

要的不是factory对象,是要里面的getOrderDao方法造出来的对象

package com.itheima.factory;

import com.itheima.dao.OrderDao;
import com.itheima.dao.impl.OrderDaoImpl;
//静态工厂创建对象
public class OrderDaoFactory {
    public static OrderDao getOrderDao(){
        System.out.println("factory setup....");
        return new OrderDaoImpl();
    }
}

主注意看这里的bean标签中的factory-method是怎么配置的 

    <bean id="orderDao" class="com.itheima.factory.OrderDaoFactory" factory-method="getOrderDao"/>

import com.itheima.dao.UserDao;
import com.itheima.factory.OrderDaoFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class AppForInstanceOrder {
    public static void main(String[] args) {
        //通过静态工厂创建对象
        OrderDao orderDao = OrderDaoFactory.getOrderDao();
        orderDao.save();


//        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
//
//        OrderDao orderDao = (OrderDao) ctx.getBean("orderDao");
//
//        orderDao.save();

    }
}

 Bean实例工厂初始化(了解)

不是静态的,没有static,所以必须要先new一个对象,再调用方法

package com.itheima.factory;

import com.itheima.dao.UserDao;
import com.itheima.dao.impl.UserDaoImpl;
//实例工厂创建对象
public class UserDaoFactory {
    public UserDao getUserDao(){
        return new UserDaoImpl();
    }
}
package com.itheima;

import com.itheima.dao.OrderDao;
import com.itheima.dao.UserDao;
import com.itheima.factory.OrderDaoFactory;
import com.itheima.factory.UserDaoFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class AppForInstanceUser {
    public static void main(String[] args) {
        //创建实例工厂对象
        UserDaoFactory userDaoFactory = new UserDaoFactory();
        //通过实例工厂对象创建对象
        UserDao userDao = userDaoFactory.getUserDao();
        userDao.save();


    }
}

<bean/>标签怎么写?

先把工厂对象造出来,再调用工厂对象把需要的bean造出来

 <bean id="userFactory" class="com.itheima.factory.UserDaoFactory"/>
    <bean id="userDao" factory-method="getUserDao" factory-bean="userFactory"/>

FactoryBean(重点)

泛型里面想写谁就写谁,要造谁写谁

FactoryBean是Spring提供的一个抽象方法,我们要对接口中的方法进行实现

public class UserDaoFactoryBean implements FactoryBean<UserDao>{


    @Override
    public UserDao getObject() throws Exception {
        return new UserDaoImpl();
    }

    @Override
    public Class<?> getObjectType() {
        return UserDao.class;
    }
}

默认单例

如果不想要单例,可以重写接口方法

public class UserDaoFactoryBean implements FactoryBean<UserDao>{


    @Override
    public UserDao getObject() throws Exception {
        return new UserDaoImpl();
    }

    @Override
    public Class<?> getObjectType() {
        return UserDao.class;
    }

    @Override
    public boolean isSingleton() {
        return false;
    }
}

在xml里面配置一下即可:

    <!--方式四:使用FactoryBean实例化bean-->
    <bean id="userDao" class="com.itheima.factory.UserDaoFactoryBean"/>

 

7.Bean的生命周期

用标签控制

在创建以后,摧毁之前做一些事情。

手动写一个init()  和destory()。取什么名字无所谓,但是必须要是public void 

    public void init(){
        System.out.println("init...");
    }
    //表示bean销毁前对应的操作
    public void destory(){
        System.out.println("destory...");
    }

ctrl+点击:点进一个方法。

        然后再点击alt+7,就能看到所有方法;

ctrl+h:查看一个接口,实现类

原本写的ApplicationContext里面没有close,但是它的子类ClassPathXmlApplicationContext中有 。close是关闭虚拟机,在关闭前释放容器


public class AppForLifeCycle {
    public static void main( String[] args ) {
        ClassPathXmlApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml");
       // ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");

        BookDao bookDao = (BookDao) ctx.getBean("bookDao");
        bookDao.save();
        ctx.close();
    
        
    }
}

 还可以设置关闭钩子:在java虚拟机停止前,先关闭容器

public class AppForLifeCycle {
    public static void main( String[] args ) {
        ClassPathXmlApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml");
       // ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");

        BookDao bookDao = (BookDao) ctx.getBean("bookDao");
        bookDao.save();
        ctx.registerShutdownHook();
       // ctx.close();


    }
}

最后想让init()和destory()和生命周期绑定,就要在xml里面配置一下

    <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl" init-method="init" destroy-method="destory"/>

直接用Spring配置好的接口

还有一种方法,不用在<bean> 标签处配置init-method方法。

继承DispoableBean,InitializingBean接口,再重写destroy,afterPropertiesSet.。前者很好理解,就是销毁前做的,后者是数据刚刚set好,执行的

public class BookServiceImpl implements BookService ,DisposableBean ,InitializingBean {
    private BookDao bookDao;

    public void setBookDao(BookDao bookDao) {
        System.out.println("set .....");
        this.bookDao = bookDao;
    }

    public void save() {
        System.out.println("book service save ...");
        bookDao.save();
    }

    @Override
    public void destroy() throws Exception {
        System.out.println("service destroy");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("service init");
    }


}

 但是无论哪种init和destroy方法

都要用close或者钩子,要不然destroy看不到。close注意放置的位置,钩子可以随便放

完整的生命周期:

1.创建对象2.进行构造方法3.set配置数据4.执行Bean的init()方法

使用Bean执行业务(调用save等等方法)

进行销毁操作:用close;钩子

8.依赖注入

setter注入

        引用注入

        简单注入

构造器注入

        引用注入

        简单注入

setter

setter注入引用类型
<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"/>

    <!--注入引用类型-->
    <bean id="bookService" class="com.itheima.service.impl.BookServiceImpl">
        <!--property标签:设置注入属性-->
        <!--name属性:设置注入的属性名,实际是set方法对应的名称-->
        <!--ref属性:设置注入引用类型bean的id或name-->
        <property name="bookDao" ref="bookDao"/>
        <property name="userDao" ref="userDao"/>
    </bean>

setter注入简单类型

配置的先后顺序无所谓

public class BookDaoImpl implements BookDao {


    private String databaseName;
    private int connectionNum;

    public void setDatabaseName(String databaseName) {
        this.databaseName = databaseName;
    }

    public void setConnectionNum(int connectionNum) {
        this.connectionNum = connectionNum;
    }

    public void save() {
        System.out.println("book dao save ..."+databaseName+","+connectionNum);
    }
}
​​    <!--注入简单类型-->
    <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl">
        <!--property标签:设置注入属性-->
        <!--name属性:设置注入的属性名,实际是set方法对应的名称-->
        <!--value属性:设置注入简单类型数据值-->
        <property name="connectionNum" value="10"/>
        <property name="databaseName" value="mysql"/>
    </bean>

构造器

用构造引用类型
 private BookDao bookDao;
    private UserDao userDao;

    public BookServiceImpl(BookDao bookDao, UserDao userDao) {
        this.bookDao = bookDao;
        this.userDao = userDao;
    }

标签换成<constuction-arg    但是,这个name,就不是变量名了,而是构造方法里面传的形参名。

<bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"/>

    <bean id="bookService" class="com.itheima.service.impl.BookServiceImpl">
<!--        <constructor-arg name="userDao" ref="userDao"/>-->
        <constructor-arg name="userDao" ref="userDao"/>
        <constructor-arg name="bookDao" ref="bookDao"/>
    </bean>
用构造方法,简单方法
    <!--解决参数类型重复问题,使用位置解决参数匹配-->
    <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl">
        <!--根据构造方法参数位置注入-->
        <constructor-arg index="0" value="mysql"/>
        <constructor-arg index="1" value="100"/>
    </bean>
    <bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"/>
public class BookDaoImpl implements BookDao {
    private String databaseName;
    private int connectionNum;

    public BookDaoImpl(String databaseName, int connectionNum) {
        this.databaseName = databaseName;
        this.connectionNum = connectionNum;
    }

    public void save() {
        System.out.println("book dao save ..."+databaseName+","+connectionNum);
    }
}

 

总结:给你构造器,就用构造器注入;自己写用setter 

依赖自动装配

自动装配用于引用,不用于简单

一般用bytype,装配的bean要唯一

byname耦合性比较高

自动装配的优先级低于setter和构造器注入,同时注入的话,自动装配可能会失败(手写优先

给好set方法

public class BookServiceImpl implements BookService{
    private BookDao bookDao;


//    public BookServiceImpl(BookDao bookDao) {
//        this.bookDao = bookDao;
//    }

    public void setBookDao(BookDao bookDao) {
        this.bookDao = bookDao;
    }

    public void save() {
        System.out.println("book service save ...");
        bookDao.save();
    }
}

给唯一的bean 甚至可以省略name

 aurowire选byType

 <bean class="com.itheima.dao.impl.BookDaoImpl"/>
    <!--autowire属性:开启自动装配,通常使用按类型装配-->
    <bean id="bookService" class="com.itheima.service.impl.BookServiceImpl" autowire="byType"/>

9.集合注入

一般都是注入简单类型

array,set,list都是类似的

map因为有键值对,所以需要用到entity实体,然后key写键名,value写值名 

依赖都是写在<bean id="接口名">

里面的

10.数据源对象管理

第三方数据源配置

数据源要连接哪些????

连接setter(点进去看写的是什么类)

这个除了url可以改,其他都是固定的。才发现之前的是用ioc配置的,本质就是用setter注入简单类型

  <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/spring_db"/>
        <property name="username" value="root"/>
        <property name="password" value="root"/>
    </bean>

c3p0

这个时候我们是不知道c3p0要配置哪些的,所以要通过百度什么的来搜索。

这时候可以尝试写bean name不重要,先写class来找c3p0的datatsource

找到后,往里面加依赖,不确定是setter还是构造器,回原本的去看看,(为什么构造方法是setter啊?因为无参吗)

然后把固定的四个往里面加,试试看,因为每个数据源的名字都大差不差

注意:这里面的class要注意不能选错,可以先百度,要不然不知道哪错,debug半天


 <bean  id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
     <property name="driverClass" value="com.mysql.jdbc.Driver"/>
     <property name="jdbcUrl" value="dbc:mysql://localhost:3306/spring_db"/>
     <property name="user" value="root"/>
     <property name="password" value="root"/>
 </bean>

总的来说分为两点:1.导入pom.xml坐标。    2.配置config.xml的bean

11.加载properties文件

1.加载文件

2.读文件

坑点:可能会有和系统变量重名的情况,这种情况写NEVER

    <context:property-placeholder location="jdbc.properties" system-properties-mode="NEVER"/>

可以加载多个文件

    <context:property-placeholder location="jdbc.properties,jdbc2.properties" system-properties-mode="NEVER"/>

所有的文件都加载

    classpath:*.properties  :   设置加载当前工程类路径中的所有properties文件

12.容器

创建容器

第一种好用,不管哪种都能加载多个xml

获取容器

最后一种常用,但是只能有一个,要不然会报错

容器类层次结构

beanFactory

是很早以前用的,也可以用来造容器,但是很久不用了。

区别就是beanfactory延迟加载;

aplicationcontext是立即加载,但也可以延迟加载,要打标记lazy-init

核心容器开发

13.注解开发定义Bean 

配置Bean

1.可以指定id名称

2.可以不写(),后面根据类型来getBean就行了

 BookDao bookDao = (BookDao) ctx.getBean("bookDao");
  BookService bookService = ctx.getBean(BookService.class);

第一个就能写bookDao,要不然getBean找不到

下面一个就不用,因为他是根据类型来写的

注意再xml里面加上扫描语句:

<context:component-scan base-package="com.itheima"/>

 Controller,Service,Repository和component效果是一样的,只是可以放在不同的层上,好让我们区分

14.纯注解开发模式 

用java来代替配置文件

新建Config类来代替配置文件,在class类上写两个注解就能替换xml了,太方便了叭

没有了xml,那么获取容器ctx的语句自然也要换

总结就三句话:

1.新建个java加上@Configuration  表明他是配置

2.再加上@ComponentScan()里面加上写了component的类的所在包,这样才能扫描到

@Configuration
@ComponentScan({"com.itheima.service","com.itheima.dao"})
public class SpringConfig{

}

3.获取IOC容器的语句

里面加上上面的jave类的类型

 ApplicationContext ctx=new AnnotationConfigApplicationContext(SpringConfig.class);

15.注解开发Bean的作用范围和生命管理周期

注意在pom.xml里面添加jsr250-api,否则@PostConstruct和@PreDestroy识别不了

@Scope:singleton;prototype

@PostConstruct

@PreDestroy

注意:非单例的,不会destory,他们的销毁不属于IOC管理

16.注解开发依赖注入 

引用类型

1.要往service里注入Dao,就直接在service里面写Autowired标签就好了

2.如果Dao有好几个实现类,就要在每个写上id,然后在autowired下面写@Qualifier里面写上id,注意,必须要和autowired连用

 @Autowired
   @Qualifier("bookDao")
    private BookDao bookDao;

简单类型 

在上面写@Value就好了

propoties的加载

1.怎么配置2.怎么加载 

1.在springconfig上面配置标签

@PropertySource({"jdbc.properties"})

2.双引号里面写${}里面写上变量名即可

如果要写多个来源,就用{}括起来

标签这里不支持通配符*

每种标签都只能写一次,妙妙妙,真的简洁

17.第三方的Bean怎么导入

主要分为两部分:

1.第三方Bean的书写 DataSource方法的书写:

1.用Druid 取ds 

2.设置ds的各项数据

3.return ds

2.将Bean导入SpringConfig中

import括号里面的class不用打双引号

18.注解开发为外部Bean注入数据 

注入简单变量

就是用私有成员变量做一个过渡

注入引用变量,把形参注入即可

他会自动装配。但是Dao类上面还是要写标签

注解开发总结

 

19.Spring整合mybatis

书写Mybati-config文件,在springconfig中import。

就两个地方需要改:"com.itheima.domain"里面是实体类的变量和信息

                                "com.itheima.dao"里面是数据库的语句

public class MybatisConfig {
    //定义bean,SqlSessionFactoryBean,用于产生SqlSessionFactory对象
    @Bean
    public SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource){
        SqlSessionFactoryBean ssfb = new SqlSessionFactoryBean();
        ssfb.setTypeAliasesPackage("com.itheima.domain");
        ssfb.setDataSource(dataSource);
        return ssfb;
    }
    //定义bean,返回MapperScannerConfigurer对象
    @Bean
    public MapperScannerConfigurer mapperScannerConfigurer(){
        MapperScannerConfigurer msc = new MapperScannerConfigurer();
        msc.setBasePackage("com.itheima.dao");
        return msc;
    }
}

 然后在main函数里面就可以调用IOC容器了

public class App2 {
    public static void main(String[] args) {
        ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);

        AccountService accountService = ctx.getBean(AccountService.class);

        Account ac = accountService.findById(1);
        System.out.println(ac);
    }
}

 20.Spring整合Junit

21.AOP 

AOP:面向切片编程

OOP:面向对象编程

作用:在不惊动原始设计的基础上(不改源代码),增加功能

连接点:原始方法(自己写的)

切入点:要追加功能的方法

通知:共性的功能

切面:把通知和切入点连接起来,要不然怎么知道哪个方法要哪个通知呢

22.AOP案例

接口执行前输出当前时间

1.导入坐标

2.在SpringConfig上面加上@EnableAspectJAutoProxy

3.创建一个Myadvise类,加上@Component标签

写一个方法,加上@Pointcut("execution(void com.itheima.dao.BookDao.update1())")作为切入点,告诉程序你要对哪些方法用

  @Pointcut("execution(void com.itheima.dao.BookDao.update1())")
    private void pt(){}

再写一个通知,上面加上@Before标签,告诉大家在扫描前执行还是后执行通知

   @Before("pt()")
    public void method(){
        System.out.println(System.currentTimeMillis());
    }

23.AOP工作流程

 1.Spring启动

2.加载所有切面配置的切入点(就是读取卸载befor里面的)

3.初始化bean,判定类中对应的方法,是否匹配任意切入点

        匹配失败:创建对象

        匹配成功:创建原始对象的代理对象

4.获取Bean执行方法

        获取Bean,调用方法并执行,完成操作

        获取代理对象,拿到原有的方法和额外AOP配置的

但是最后AOP会进行tostring重写,所以看到的有些差距

匹配上:

com.itheima.dao.impl.BookDaoImpl@1e4f4a5c
class jdk.proxy2.$Proxy20

匹配不上:

com.itheima.dao.impl.BookDaoImpl@38467116
class com.itheima.dao.impl.BookDaoImpl

匹配上就调代理对象,匹配不上就原始对象

24.AOP切入点表达式

描述接口或者实现类都可以

*  可以独立存在;也可以写在一个单词后面find*,作为后缀;也可以写在参数里面。但是注意:*是任意,但是要有

..   任意,有没有都行

+   子类,接口的实现类就是接口的子类

 

一般描述接口

访问修饰符因为很多对接口实现,所以一般都是public,可以省略

25.AOP通知类型

before:方法调用前

after:方法调用后

环绕:

开始前和结束后都调用,有对原始要求的调用,得用Object接出来返回值,并且最后return扔回去

AfterReturning 

没有抛异常才会调用,在最后调用

AfterThrowing 

抛异常后才会调用,在最后调用

26.案例:测量接口案例

写around的时候,注意你切入点的返回值是什么,你要写对应的类型

 获取类型和方法名

   Signature signature = pjp.getSignature();
        String classname = signature.getDeclaringTypeName();
        String methodname = signature.getName();

27.AOP获取数据

参数

参数:所有都能调用。用JoinPoint创建对象,getArgs()方法获取Object数组即可

  @Before("pt()")
    public void be(JoinPoint jp){
        Object[] args = jp.getArgs();
        System.out.println(Arrays.toString(args));
    }

返回值

around和AfterReturning可以用

around的返回值之前学过,直接调用pjp.proceed就好了。而且pjp是jp的子类,继承了所有父类的方法,所以可以getArgs

    @Around("pt()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {


        Object[] args = pjp.getArgs();
        System.out.println(Arrays.toString(args));
        args[0]=666;

        Object pr = pjp.proceed(args);       //这就是拿到返回值吗
        return pr;
    }

对于AfterReturning来说有点特殊。所有通知的形参只要有JoinPoint,就必须放在第一位。

首先标签上要定义一个returning  来接下面方法中的object的变量名。然后就好了,注意一定要一一对应

 @AfterReturning(value = "pt()",returning = "ret")
    public void afterReturning(JoinPoint jp,Object ret){
        System.out.println("*******");
        System.out.println(ret);
    }

异常

只有Around和AfterTrouwing可以用

Around的贼好拿哈哈哈哈哈,真的方便。直接try catch环绕就能拿到。idea是方便哈

       Object pr = null;       //这就是拿到返回值吗
        try {
            pr = pjp.proceed(args);
        } catch (Throwable e) {
            throw new RuntimeException(e);
        }
        return pr;

afterThrowing就和上面的afterreturning类似了。 

   @AfterThrowing(value="pt()",throwing = "t")
    public void aft(Throwable t){
        System.out.println(t);
    }

小技巧:抛异常要是抛不了,可以用以下语句骗一骗

    if(true)throw new NullPointerException();

28.百度网盘案例

其实不难,只是之前没写过。那里面的for循环处理非常绝妙!!!!!!!

 @Around("servicePt()")
    public Object tr(ProceedingJoinPoint pjp) throws Throwable {
        Object[] args=pjp.getArgs();

        for(int i=0;i< args.length;i++){
            if(args[i].getClass().equals(String.class)){
                args[i]=args[i].toString().trim();
            }
        }
        Object ret=pjp.proceed(args);
        return ret;
    }

使用AOP简化共性功能的开发

29.Spring事务

保证业务层对数据库的操作同成功同失败

可以在数据层也可以在业务层开

内部用的是jdbc才能用以下的方法,刚好mybatis就是jdbc

1.业务层接口加上事务管理

接口方法上写一个标签

最好写在接口上,降低耦合

@Transactional

2.设置事务管理器

在jdbcConfig里面定义一个Bean

里面写着PlatformTransactionManager方法

new一个DataSourceTransactionManager

用传参的方式把DataSource传参传进去

然后把创建好的DataSourceTransactionManager.setDataSource(dataSource)

最后返回创建好的DataSourceTransactionManager即可

注意:都是在围绕着DataSourceTransactionManager做操作

    @Bean
    public PlatformTransactionManager transactionManager(DataSource dataSource){
        DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
        dataSourceTransactionManager.setDataSource(dataSource);
        return dataSourceTransactionManager;
    }

3.开启注解事务驱动

在SprignConfig上面加上标签

@EnableTransactionManagement

突然发现jdbc里面配置的是mybatis,因为jdbc是用

30.Spring事务角色

mybatis和PlatformTransactionManager里面的dataSource是同一个,要不然没法进行统一管理

31.Spring事务属性

ctrl+h先点进去class。双击右上角的方法。

alt+7再点进去,就能看到每个方法了

 

  @Transactional(rollbackFor = {IOException.class})

 

 

重新开启一个事务 

public interface LogService {
    //propagation设置事务属性:传播行为设置为当前操作需要新事务
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    void log(String out, String in, Double money);
}

所谓事务传播行为本质上就是事务协调员对事务管理员的态度 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值