(3)Spring学习笔记

目录

1-1Spring大概了解

1.优点

2.组成

3.IOC本质

1-2 如何使用Spring

1.导入Springjar包

2.编写一个实体类

3.配置spring的xml配置文件

如何返回ioc容器的一些参数

1-3Spring注入概念

1.Set注入

2.Spring的自动注入byName/byType

1-4 注解

类注解的使用

1-5Aop(面向切面编程)

1.代理学习

2.Aop是什么

3.Aop概念和使用语法

1-6 Spring集成Mybatis的使用

1.整合Mybatis的思路

2.创建dao对象和SqlSessionFactory对象

2.Spring统一处理事务

3.使用@Transactional注解增加事务

使用@Transactional步骤:


1-1Spring大概了解

2002年,Rod Jahnson首次推出了Spring框架雏形interface21框架。

Spring理念 : 使现有技术更加实用 . 本身就是一个大杂烩 , 整合现有的框架技术

官网 : Spring | Home

maven项目pom依赖:

<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>5.2.0.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>5.2.0.RELEASE</version>
</dependency>

1.优点

1、Spring是一个开源免费的框架 , 容器 .

2、Spring是一个轻量级的框架 , 非嵌入式的 .

3、控制反转 Ioc, 面向切面 Aop

4、对事物的支持 , 对框架的支持

一句话概括:

Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器(框架)。

2.组成

 Spring 框架是一个分层架构,由 7 个定义良好的模块组成。Spring 模块构建在核心容器之上,核心容器定义了创建、配置和管理 bean 的方式 

组成 Spring 框架的每个模块(或组件)都可以单独存在,或者与其他一个或多个模块联合实现。每个模块的功能如下:

  • 核心容器:核心容器提供 Spring 框架的基本功能。核心容器的主要组件是 BeanFactory,它是工厂模式的实现。BeanFactory 使用控制反转(IOC) 模式将应用程序的配置和依赖性规范与实际的应用程序代码分开
  • Spring 上下文:Spring 上下文是一个配置文件,向 Spring 框架提供上下文信息。Spring 上下文包括企业服务,例如 JNDI、EJB、电子邮件、国际化、校验和调度功能。
  • Spring AOP:通过配置管理特性,Spring AOP 模块直接将面向切面的编程功能 , 集成到了 Spring 框架中。所以,可以很容易地使 Spring 框架管理任何支持 AOP的对象。Spring AOP 模块为基于 Spring 的应用程序中的对象提供了事务管理服务。通过使用 Spring AOP,不用依赖组件,就可以将声明性事务管理集成到应用程序中。
  • Spring DAO:JDBC DAO 抽象层提供了有意义的异常层次结构,可用该结构来管理异常处理和不同数据库供应商抛出的错误消息。异常层次结构简化了错误处理,并且极大地降低了需要编写的异常代码数量(例如打开和关闭连接)。Spring DAO 的面向 JDBC 的异常遵从通用的 DAO 异常层次结构。
  • Spring ORM:Spring 框架插入了若干个 ORM 框架,从而提供了 ORM 的对象关系工具,其中包括 JDO、Hibernate 和 iBatis SQL Map。所有这些都遵从 Spring 的通用事务和 DAO 异常层次结构。
  • Spring Web 模块:Web 上下文模块建立在应用程序上下文模块之上,为基于 Web 的应用程序提供了上下文。所以,Spring 框架支持与 Jakarta Struts 的集成。Web 模块还简化了处理多部分请求以及将请求参数绑定到域对象的工作。
  • Spring MVC 框架:MVC 框架是一个全功能的构建 Web 应用程序的 MVC 实现。通过策略接口,MVC 框架变成为高度可配置的,MVC 容纳了大量视图技术,其中包括 JSP、Velocity、Tiles、iText 和 POI。

3.IOC本质

控制反转IoC(Inversion of Control),是一种设计思想,DI(依赖注入)是实现IoC的一种方法,也有人认为DI只是IoC的另一种说法。没有IoC的程序中 , 我们使用面向对象编程 , 对象的创建与对象间的依赖关系完全硬编码在程序中,对象的创建由程序自己控制,控制反转后将对象的创建转移给第三方(spring容器),所谓控制反转就是:由spring来控制和创建这些对象。

何为解耦合:

IoC是Spring框架的核心内容,使用多种方式完美的实现了IoC,可以使用XML配置,也可以使用注解,新版本的Spring也可以零配置实现IoC。

Spring容器在初始化时先读取配置文件,根据配置文件或元数据创建与组织对象存入容器中,程序使用时再从Ioc容器中取出需要的对象。

在这里插入图片描述

Bean通常指的就是Java的实现类对象

控制反转是一种通过描述(XML或注解)并通过第三方(其他的软件或框架如Tomcat,spring等等)去生产或获取特定对象的方式。在Spring中实现控制反转的是IoC容器,其实现方法是依赖注入(Dependency Injection,DI)

1-2 如何使用Spring

1.导入Springjar包

跟其他的框架一样,spring也需要一个jar包,我们需要导入相应的jar包才能使用,直接去官网下载或者通过maven的pom文件下载也是可以的.

<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>5.2.0.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>5.2.0.RELEASE</version>
</dependency>

2.编写一个实体类

这就是一个普通的类,用来演示Ioc容器怎样实现这个类的

public class Hello {
   private String name;

   public String getName() {
       return name;
  }
   public void setName(String name) {
       this.name = name;
  }

   public void show(){
       System.out.println("Hello,"+ name );
  }
}

3.配置spring的xml配置文件

<?xml version="1.0" encoding="UTF-8"?>
<!--spring的规范-->
<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就是java对象 , 由Spring创建和管理
     这里的 id 就是这个被创建的java对象在spring ioc容器中的名字
        我们正常创建一个对象是new出来的 Hello h = new Hello(); 但是在spring中
            它会根据我们提供的这个 class 中的全限定名称找到我们要使用的java类,使用反射机制
                创建这个类的类对象,并且存储在ioc容器中,像map那样的方式放入进去

             map.put("hello",new Hello);
   这样spring在使用的时候只要通过这个id就能找到这个类对象,就可以使用了

-->
    <bean id="hello" class="com.kuang.pojo.Hello">

        <!--property是用来在xml配置文件里设置该类的字段值的
                通过name:来设置那个字段的value:值-->
       <property name="name" value="Spring"/>
   </bean>

</beans>

4.运行代码

@Test
public void test(){
   //解析beans.xml文件 , 生成管理相应的Bean对象
   String config = "beans.xml";
    //获取spring的ioc容器对象实例,我们需要的对象就存放在这个容器中
    //通过这个ClassPathXmlApplicationContext实现类对象读取xml配置文件得到ioc容器
    //ApplicationContext就是ioc容器的接口
   ApplicationContext a = new ClassPathXmlApplicationContext(config);
   //容器对象.getBean(需要得到的对象在容器中的 id )
   //这样可以得到你需要对应id的对象,但是返回是object的所以需要向下转型才能使用
   Hello hello = (Hello) a.getBean("hello");
   hello.show();
}
  • Hello 对象是谁创建的 ? hello 对象是由Spring创建的
  • Hello 对象的字段是怎么设置的 ? hello 对象的字段是由Spring容器设置的,在Bean里面使用了property标签来设定给定字段的值

这个过程就叫控制反转 :

  • 控制 : 谁来控制对象的创建 , 传统应用程序的对象是由程序本身控制创建的 比如new一个对象,而使用Spring后 , 对象是由Spring通过反射来创建的
  • 反转 : 程序本身不创建对象 , 而变成被动的接收对象 

如何返回ioc容器的一些参数

spring提供了两个方法可以返回ioc容器中对象的数量和id,

getBeanDefinitionCount():返回容器中的对象数量

getBeanDefinitionName():返回一个包含ioc中所有对象名的String数组

 //返回ioc中的对象总数
 System.out.println(a.getBeanDefinitionCount());
 //返回所有对象的id名
 System.out.println(a.getBeanDefinitionNames());

int count = a.getBeanDefinitionCount();

String[] id = a.getBeanDefinitionNames();

1-3Spring注入概念

1.Set注入

什么是set注入,按照传统的方式我们在一个类里给私有字段赋值的话只能使用set方法赋值,而spring可以在xml文件里帮助我们进行赋值,其原理也是通过反射来使用类中的set赋值,但是这样可以实现解耦合.

在使用set注入的时候必须保证该注入字段拥有了set方法,否则会抛出异常.

而spring寻找set方法是通过set+字段的名字找到该set方法的,不会区分大小写.

<!--简单字段的赋值-->

<bean id="xxx" class="xx.xxx.xxx">
                    <!--赋值要按照xml格式填写,值必须要用" "起来-->
 <property name="需要赋值的字段名" value="需要赋的值"/>
</bean>


<!--引用字段的赋值-->

<bean id="xxx" class="xxx.xxx.xx">
    <property id="xxxxx" ref="需要赋的值的bean id">
</bean>

类中的字段分为简单字段引用字段,简单字段通常是基本类行,String也在这属于简单字段,而类对象则为引用对象.

这里其实也只是单单的使用了set方法,跟平时使用set没啥区别,但是有了很大的不同,我们只需要修改xml配置文件就能修改需要赋的值或者对象.

2.Spring的自动注入byName/byType

使用xml配置文件手工注入set是可行的,但是这在有大量类的情况下就有点捉襟见肘了,所以spring也提供了两种自动注入的方式,byName(按照名称)和byType(按照类样式)来实现自动注入

而我们如果要使用自动注入则要在需要注入的bean标签里面加上atuowire="注入方式",来寻找我们需要的注入对象;

示例:

类:

class School{
//一个类字段
Student student;

}

class Student{

//student里面的字段
 String name;
 int age;


//set.....方法

}

如果通过byName去自动注入,则需要studen的bean对象id和School中的Student类字段id相同,这样spring才能找到需要注入的对象.

如果是通过byType去字动注入,则需要class是Student或者其子类,接口实现类,就可以找到注入对象,对名称没有要求.

xml配置文件示例:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

<!--按照所需对象的对象名称来寻找注入对象-->
    <bean id="student" class="study.ssm.sp.Student">
        <property name="name" value="V"/>
        <property name="age" value="21"/>
    </bean>


      <!--使用byName,按照所需对象的id匹配注入-->
    <bean id="school" class="study.ssm.sp.School" autowire="byName">
        <property name="name" value="zuen"/>
        <property name="address" value="皮尔特洛夫下城区"/>


------------------------------------------分割线--------------------------------------------
 <!--按照所需对象的类类型来寻找注入对象-->
   <bean id="xxxxxx" class="study.ssm.sp.Student">
            <property name="name" value="Jinx"/>
            <property name="age" value="19"/>
    </bean>

        <!--使用byType,按照所需对象的id匹配注入-->
    <bean id="school" class="study.ssm.sp.School" autowire="byType">
        <property name="name" value="zuen"/>
        <property name="address" value="皮尔特洛夫下城区"/>


    </bean>

</beans>

1-4 注解

类注解的使用

使用spring的ioc容器,除了可以在xml配置文件中创建对象,也可以使用注解来代替xml中的bean标签,注解开发使开发更加简单并且具有可读性.

Component注解的使用:@Component(value="id名字")

使用这个注解跟xml中的bean标签同理,可以创建一个对象放入到spring的ioc容器中使用,后面的值为在ioc中的对象名,被这个注释的类表示一个模块,并且不用去创建xml这个bean标签.


//这是一个注解,表示被注释的这个类是spring的一个模块
@Component("在ioc中的对象名")
public class TT{


}

有了这个注释后,就可以省略bean标签的繁琐方式了,但是使用注解的话必须要让spring知道这个类被注解了,那么就需要用到spring的扫描器:

<context:component-scan base-package="被注解类的全限定名或者是想扫描的包名"/>

这样spring在启动的时候就可以扫描到我们需要注解的类,到后面这个xml标签也可以编程注解写到程序里,@ComponentScan注解.

@ComponentScan(basePackages = {"扫描到的包名", "other.pkg"})
public class Application { ... }

不论是component-scan标签,还是@ComponentScan注解。它们扫描或解析的bean只能是Spring内部所定义的,比如@Component、@Service、@Controller或@Repository。如果有一些自定义的注解,比如@Consumer、这个注解修饰的类是不会被扫描到的。这个时候我们就得自定义扫描器完成这个操作。
 

其他的注解类型:

@Service:注解逻辑层类

@Repository:注解持久层类

@Contorller:注解控制层类

@Component:注解不属于上面三种类的其他类类型

如果要给类里面的字段赋值,传统的xml配置方法是使用property来赋值,而使用注解则可以使用@Value("赋的值")并且不需要有set方法就可以赋值,而如果是引用类型的注解则使用@AtuoWirte来赋值.

@AtuoWired默认是byType去寻找这个对象,如果要使用byName去寻找的话要在下面加上@Qualifier("需要匹配的id名字")

@Component("LOL")
public class TT{

//将Jinx这个字符串赋给这个name
@Value("Jinx")
private String name;

@Value("19")
private int age;


//给Hope类赋一个hope对象
//AtuoWired有一个required默认值为true,为false如果没有找到可以注入的类不会报错
//如果没有修改默认为true,如果没找到可以注入的类就会抛出异常
@AtuoWired
Hope hope;


//按照byName方式去查找
@AtuoWired
@Quelifier("V")
Hope hope;

}

还有一个是Java包提供的注解方法是byName类型@Resource,这个用法跟Atuowired用法相同,放在需要赋值的对象上,而查找的就是需要赋值对象的对象名

//先使用byName自动注入,如果byName失败了则使用byType注入
@Resource    //byName去寻找school名的对象
School school;

如果都失败了则抛出异常

1-5Aop(面向切面编程)

1.代理学习

学习链接https://blog.csdn.net/xiaofeng10330111/article/details/105633821?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522164025293016780261931410%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=164025293016780261931410&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~top_positive~default-1-105633821.first_rank_v2_pc_rank_v29&utm_term=%E5%8A%A8%E6%80%81%E4%BB%A3%E7%90%86&spm=1018.2226.3001.4187https://blog.csdn.net/xiaofeng10330111/article/details/105633821?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522164025293016780261931410%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=164025293016780261931410&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~top_positive~default-1-105633821.first_rank_v2_pc_rank_v29&utm_term=%E5%8A%A8%E6%80%81%E4%BB%A3%E7%90%86&spm=1018.2226.3001.4187

动态代理实现方式:jdk动态代理,使用jdk中的Proxy,Method,InvocaitonHandler创建代理对象.

                                jdk动态代理要求目标类必须实现接口

cglib动态代理:第三方工具库,创建代理对象,原理就是继承.通过继承目标类,创建子类.

                        子类就是代理对象.要求目标类不能是final的,方法也不能是final的.

动态代理的作用:

1)在目标类源代码不改变的情况下增加功能.

2)减少代码的重复.

3)专注业务逻辑代码.

4)解耦合,将业务代码和非业务代码分离.


2.Aop是什么

Aop:面向切面编程,基于动态代理,可以使用jdk或者cglib两种代理方式

Aop就是动态代理的规范化,吧动态代理的实现步骤,方式都定义好了,让开发人员用同样的方式使用动态代理.

Aop是用来在增加业务功能或者增加功能冗余的情况下可以使用.

                                                                   传统代码

aop的应用 

3.Aop概念和使用语法

  • 目标对象:需要被增强的类就是目标对象.
  • Aspect:切面,表示给目标类增强的功能,一般都是非业务方法独立使用.
  • joinpoint:连接点,连接业务方法和切面方法的位置,就某个类的业务方法
  • pointcut:切入点,多个连接点的集合,多个方法.
  • Advice:通知,执行切面功能的时间(增强事务位置)

 切面三要素:

1)切面的功能代码,切面干什么.

2)切面的执行位置,使用pointcut表示切面执行的位置.

3)切面的执行时间,使用Advice表示时间,是在目标方法之前,还是目标方法之后.

//目标对象
public class A{


//切入点,单个又称连接点
public void B(){

      //Advice(切入时间)表示是在代码前切入还是在代码后切入
       //Advice在目标代码前切入
          new before();

     //正常业务逻辑代码
        new Work();

     //Advice(切入时间)在目标代码后切入
        new after(); 

    }
}

aop的实现:spring自带aop实现但是一般不用,而是用集成的aspectJ框架来实现.

4.aspectJ的注解使用

切面的执行时间,这个执行时间在规范中叫做Advice(通知,增强)

在aspectj框架中用注解表示的,也可以用xml配置文件来实现.

Advice的注解实现:

1)@Before

2)@AfterReturning

3)@Around

4)@AfterThrowing

5)@After

这五个分别表示不同的切入时间.

AspectJ专门定义表达式用于指定切入点.表达式原型:

execution([修饰符]? 返回值类型 包名?.类名?.方法名(参数列表) 抛出异常类型?)

带?的为可选项,可以不填,其他为必填.每一项中间都有空格隔开

execution中可使用符号
*0至多个任意字符
..

用在方法中表示多个参数

用在包名后表示当前包及其子包的路径

+

用在类名后,表示当前类及其子类

用在接口后,表示当前接口及其子接口

例子:

//这里execution表示的意思是
//切入 所有访问修饰 所有返回类型 并且在com包下的所有类的dosome方法 这个方法的传入的参数可以为多个参数的方法的前面
@Before("execution(* * com.*.dosome(..))")


//如果参数不匹配则会切入失败
//这里传入的参数只需要知道参数的类型就行了,不用形参名
//如果目标类方法只有一个String参数或者参数与这里设定的类型不匹配则不切入
//必须满足execution里面的所有条件才会切入,否则切入失败
@Before("execution(* * com.*.dosome(String,Integer))")

定义一个切面:

在aspectj中,可以使用@Aspect来定义一个切面类

可以定义一个普通的类,该类中实现增强的方法,然后在该类上使用@Aspect将该类作为切面类使用

@Before(前置通知)

在业务代码前执行的通知.

@Component("doOther")
//@Aspect(切面)表示这个类是切面类
@Aspect
public class DoOther {
    //用来表面这个切入的时间和切入哪个目标,当前使用的是@Before这个注解,表示在目标方法前执行这个被注解的方法.
    @Before(value = "execution(public void study.ssm.sp.*.dosome(..))")
    public void do1() {
        System.out.println("增强方法,非业务方法,打印当前时间" + new Date());

    }

    public void do2(){

    }
}

@AfterReturning(后置通知)

@AfterReturning是在执行目标类的方法后执行的一个切入,除了value参数外还有一个returning参数,并且可以拿到目标类方法的返回值,在业务逻辑结束后做一些事,.

@Aspect
public class A{

//returning的参数是增强方法里的形参名
//这个增强方法可以接收到目标方法的返回值,用Object接收
@AfterReturning(value="execution(* com.*..doSomething(..))",retruning="res")
public void B(Object res){
        //目标方法的返回值,可以拿来做一些事情
        //如果是值拷贝,改变无效,如果是引用则会改变
            res.xxxx();
        //执行的代码
     
    }

}

@Around(环绕通知)

环绕通知可以在目标方法的前面和后面增强功能,可以控制目标方法是否被调用执行,还能修改目标方法的执行结果,影响最后的调用结果.

@Aspect
public class A{


@Around(value="execution(* com.*.doSomething(..))")
//这里使用了Proceedingjoinpoint一个对象,可以拿到目标方法
public Object B(ProceedingJoinPoint pjp){
           //方法执行返回结果
            Object result = null;
        //可以从执行的目标方法中拿到所有实参
        Object[] args = pjp.getArgs();

        
            //在目标方法执行前增强功能
            System.out.println("环绕通知:在目标方法前执行"+new Date());
            //执行目标方法
            result = pjp.proceed();
        
            //在目标方法后加入功能
            //加入方法.....

           
             //返回执行结果
             return result;
    }
}

同时也可以在该环绕通知方法里加入判断,决定是否执行业务方法,同样返回值也可以这样决定.

JoinPoint参数:

@AftherRrturning(value="execution(xxx xxx.(..))",result="xxx")
//这个参数可以获得目标方法在执行的时候的信息,例如方法名,方法实参.
public void B(JoinPoint jp){
        //获取方法完整定义
    System.out.println("方法的签名(定义)="+jp.getSignature());
    //获取方法名称jp.getSignature().getName();
    //获取方法实参jp.getSignature().getArgs();

}

@AfterThrowing(异常通知)

用来在目标方法执行发生异常时执行的,可以做异常监控程序,如果有异常则进行处理.


//throwing的参数名必须和形参名匹配
@AfterThrowing(value="xxx xxx.*.doSomething(..)",throwing="ex")
//目标方法发生异常是执行该方法
public void A(Exception ex){
  
    System.out.println("异常通知:方法执行发生异常"+ex.getMessage());

}

@After(最终通知)

在目标方法执行后总是会执行的,同finally一样.

@After(value="execution(* com.*.doSomething(..))")
public void A(){
//一般做项目清除的
System.out.println("执行的最终通知");

}

@Pointcut

这个不是通知的注解,而是辅助类型的注解,当有多个通知的切入点表达式(execution)中的切入点相同时可以使用,用来去重复可以复用的,可以声明一个方法加上该注解定义切入点,然后在其他通知注解的切入点表达式中使用该方法就可以了.

@Pointcut(value="execution(* com.study.ssm.doSomething(..))")
private void poinCutt(){
        //这个方法只是用来表示其他的通知注解的切入点表达式的,所以不用写任何代码
        //也不用被其他对象调用所以为private
}



@Before(value="poinCutt()")
public void A(){

    //切入代码...
}


@After(value="poinCutt()")
public void C(){
    //切入代码...

}

1-6 Spring集成Mybatis的使用

1.整合Mybatis的思路

Spring将Mybatis整合到一起,当作一个框架使用,这样减轻了开发人员的负担

实现的方法就是ioc,ioc可以将Mybatis框架创建对象的工作交给Spring统一创建,开发人员只需要从spring中获取对象就可以使用了,不用同时面向两个框架或多个框架了,只需要面对spring.

Mybatis使用步骤:

  1. 定义dao接口.StudentDao
  2. 定义mapper文件 StudentDao.xml
  3. 定义mybatis主配置文件.mybatis.xml
  4. 创建dao代理对象, StudentDao dao = SqlSession.getMapper(StudentDao.class);
  5. 使用dao代理去访问数据库,List<Student> student = dao.selectStudent();

dao对象创建大致流程:

dao ==> SqlSession.getMapper() ==> SqlSession ==>SqlSessionFactory ==>mybatis主配置文件

要使用dao对象,就必须要使用getMapper()方法才能得到dao对象,所以必须要拿到SqlSession才能使用getMapper()方法:

1.获取SqlSession对象,需要使用到SqlSessionFactory的openSession方法.

2.创建SqlSessionFactory对象. 通过mybatis主配置文件可以创建SqlSessionFactory对象.

所以我们只要拿到SqlSessionFactory对象就能创建dao对象了.

Mybatis主文件的配置:

1.数据库信息比如driver,url,user,password.

2.Mapper文件的位置 

所以,如果要在spring框架中使用mybatis,必须创建以下对象:

  • 独立的连接池对象
  • SqlSessionFactory对象
  • 创建dao对象

2.创建dao对象和SqlSessionFactory对象

大致步骤:

1.新建mevan项目

2.加入pom依赖

  • spring依赖
  • mybatis依赖
  • mysql驱动
  • spring事务依赖
  • mybatis和spring集成依赖:mybatis官方用的,用来在spring项目中创建mybatis的SqlSessionFactory,dao对象

3.创建实体类(用来读/取数据库的数据存放类)

public class Student{
//需要查询或添加的名字
public String name;
//需要查询或添加的数字
public Integer number;
public String job;

}

4.创建dao接口和mapper文件

Dao接口:

//创建的Dao接口
public interface StudentDao{

//定义一个方法
    int insertStudent();
    List<Student> selectStudent();

}

mapper配置文件:

创建StudentDao.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.study.ssm.StudentDao">
         <insert id="insertStudent">
        insert into student value(#{id},#{name},#{job})      
         </insert>

        <select id="selectStudent" resulType="com.study.ssm.Student">
       select id,name,job from student
        </select>
  </mapper>

5.创建mybatis配置文件

创建一个mybatis.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> 
<configuration>
    <mappers>
        <mapper resource="com/xyh/dao/StudentDao.xml"/>
    </mappers>
</configuration>

6.创建Spring配置文件:声明mybatis对象交给spring创建

创建一个applicationContext.xml文件

数据源:

<!--数据源(dataSource)对象,连接池使用的德鲁伊连接池-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
        <property name="url" value="jdbc:mysql://localhost:3306/newsDB?characterEncoding=UTF-8"></property>
        <property name="username" value="root"></property>
        <property name="password" value="12345"></property>
</bean>

SqlSessionFactory:

<!--创建sqlSessionFactory对象
    class里用org.mybatis.spring.SqlSessionFactoryBean来创建SqlSessionFactory对象-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">

<!--给SqlSessionFactoryBean对象使用set赋值-->
            <!--读取mybatis主文件配置路径-->
            <property name="configLocation" value="classpath:MyBatis-Configuration.xml"></property>
            <!--读取创建的数据源-->
            <property name="dataSource" ref="mydataSource" />
</bean>

创建Dao对象:

<!--单个Dao对象创建-->
<bean id="studentDao" class="org.mybatis.spring.mapper.MapperFactoryBean">
       <!--dao对象-->  
        <property name="mapperInterface" value="com.xyh.dao.StudentDao"/> 
       <!--SqlSessionFactory对象-->
        <property name="sqlSessionFactory" ref="sqlSessionFactory"/> 
    </bean> 

===========================

<!--MapperScannerConfigurer是调用内部getMapper()方法生成每个dao接口的代理对象-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
       <!--指定sqlSessionFactory的id-->
      <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
        <!--创建的Dao对象所在的包名,多个包的Dao对象可以用逗号分隔去创建-->
        <property name="basePackage" value="study.ssm.namespace.StudentDao"/>
    </bean> 

声明自定义的Service:

//创建servic实体类来使用dao接口
public class ServicStudentimp implement ServiceStudent{
//dao接口类
private StudentDao studentdao;
//servic方法来使用dao访问数据库
public int addStudent(Student student){
    
        return studentdao.insert(student);
    }


}

7.获取Service对象,通过service调用dao进行访问数据库

public class T{

public static void main(String[] args){

String config = "classpath:/applicationcontext.xml";
ApplicationContext ap = ClasspathXmlApplicationContext(config);

ServiceStudent st = (ServiceStudent)ap.getBean("serviceStudent");
st.insert(new Student);

    }

}

2.Spring统一处理事务

1)什么是事务

事务是一组sql语句的集合,集合中有很多sql语句,可能是insert,update,select,delete,我们希望这些多个sql语句都能成功,或者都失败,这些sql语句是一致的,作为一个整体执行,就是事务.

2)什么时候使用事务

当操作数据库,涉及到多个表或者多个sql语句的insert,update,delete.需要确保这些语句都是成功才能完成功能,或者都失败,保证操作是符合要求的.

最简单的例子:当你vx发给朋友100元,从你的账户中-100,朋友+100.必须保证这个操作都执行了,或者都失败,不然就会产生问题.

在Java代码中,控制事务一般放在service类的业务方法上,因为业务方法会调用多个dao方法,执行多个sql语句.

3) 处理事务的统一方式

在开发中,访问数据库的框架可能不同,有mybatis,jdbc,hibernate等一些用来访问,而这些访问方法不同,处理事务也不相同.

jdbc访问数据库,处理事务   Connect   con;   con.commit();   con.rollback();

mybatis访问数据库,处理事务   SqlSession.commit();   SqlSession.rollback();

hibernate访问数据库,处理事务  Session.commit();  Session.rollback();

不同的访问数据库的技术方法不同,并且处理的方式也不同,而且需要掌握多种数据库中事务的处理逻辑,什么时候提交事务,什么时候回滚事务.

4)Spring统一模型

Spring提供一种处理事务的模型,使用统一步骤的方式,完成多种不同数据库访问技术的事务处理.

使用spring的事务处理机制,可以完成mybatis,jdbc,hibernate的事务处理.

1)事务内部提交,回滚事务,使用事务管理器对象,代替你完成commit,rollback,事务管理器是一个接口和其他众多的实现类.

接口:PlatformTransactionManager,定义了事务重要方法 commit , rollback.

实现类:spring把每一种数据库访问技术对应的事务处理类都创建好了.

如果你是使用mybatis访问数据库----spring创建的是 DataSourceTransactionManager

如果是hibernate访问数据库----spring创建的是 HibernateTransactionManager

这些都是spring自带的,而我们只需要告诉spring去使用哪种访问技术的实现类就行了,声明需要实现的bean对象.

声明一个需要使用的访问技术的类就ok了,spring就知道你要使用哪种技术去管理事务

<bean id = "xxxx" class = "..DataSourceTransactionManager "> 

5)事务定义接口

事务定义接口TransactionDefinition定义了事务描述的三类常量:事务隔离级别,事务传播行为,事务默认超时时限,以及对他们的操作.

  • 事务隔离级别

作用:方法在高并发情况下对数据安全性的控制

DEFAULT:使用DB默认的事务隔离级别,Mysql默认是REPEATABLE_READ; Oracle默认的是READ_COMMITTED; 

READ_UNCOMMITTED:读未提交)  不解决任何并发问题.

READ_COMMITTED:读已提交)  解决脏读,存在不可重复读和幻读.

REPEATABLE_READ:可重复读)  解决脏读,不可重复读,存在幻读.

SERIALIZABLE:串行化)  不存在并发问题

  • 事务传播行为

PROPAGATION_REQUIRED:

指定的方法必须在事务内执行,若当前存在事务,就加入到当前事务中,若当前没有事务,则创建一个新事务.这是spring的默认的事务传播方式.

PROPAGATION_REQUIRED_NEW:

指定的方法支持当前事务,但若当前没有事务,也可以以非事务方式执行.

PROPAGATION_SUPPORTS:

指定的方法总是新建一个事务,若当前存在事务,就将当前事务挂起,直到新事务完毕.

  • 事务默认超时时限

 表示一个最长的执行时间,如果执行时间超过则回滚事务,单位是秒,整数值,默认是-1.

6)提交事务,回滚事务的时机

  • 当你的业务方法执行成功,没有抛出异常,当方法执行完毕,spring会自动提交事务.
  • 当你的业务方法抛出运行异常(包括它的子类)或ERROR,spring执行回滚,调用事务管理器的rollback.
  • 当业务方法抛出非运行时异常(受查异常),提交事务.例如 IOExecption,SQLException.

3.使用@Transactional注解增加事务

通过@Transactional注解方式,可以将事务织入到相应的public方法中,实现事务管理.

propagation:事务传播属性,为Propagation的枚举,默认为Propagation.REQUIRED.

isolation:用于设置事务隔离级别,默认值为Ioslation.DEFAULT.

readOnly:设置该方法对数据库的操作是否是只读,默认为false;

timeout:用于设置本操作与数据库连接的超时时限.单位为秒,默认值-1;

rollbackFor:指定需要回滚的异常类,类型为Class[],默认值为空数组.

rollbackForClassName:指定需要回滚的异常类类名,类型为String[],默认为空数组.

noRollbackFor:指定不需要回滚的异常类,类型为Class[],默认为空数组.

noRollbackForClassName:指定不需要回滚的异常类类名,类型为String[].

使用@Transactional步骤:

1.需要声明事务管理器对象

<!--创建一个事务管理器对象,放入到ioc中
    这里创建的是mybatis的管理对象-->
<bean id="dataSourceTransaction" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <!--连接的数据库,指定数据源-->
    <property name="dataSource" ref="myDataSource"/>    

</bean>

2.开启事务注解驱动,告诉spring框架,要使用注解的方式管理事务.

spring使用aop机制,创建@Transactional所在的类代理对象,给方法加入事务功能.

<!--开启事务注解驱动,告诉spring使用注解管理事务,创建代理对象
        transaction-manager:事务管理器对象id-->
<tx:annotation-driven transaction-manager="dataSourceTransaction">

3.在方法上面加入@Transactional.

@Transactional(
    //传播属性
    propagation=Propagation.REQUIRED,
    //隔离级别
    isolation = Isolation.DEFAULT,
    //该方法对数据库的操作是否是只读的
    readOnly = false,
    //发生指定的异常就回滚事务
    rollbackFor = {
        //指定的异常类型 
    NullPointerException.class    
    }
)
public void bu(){

}


==================================
//也可以使用全部默认值
//默认抛出运行异常回滚事务
@Transactional
public void A(){}

@Transactional必需加在public方法上!!!!!!

上面使用的是注解的方式进行事务管理,如果有多个方法,或者类甚至是几个包中的方法,一个个写注解不仅冗余,而且还浪费时间,所以我们可以采用xml文件来配置事务管理器.

编程式事务管理

编程式事务管理我们可以通过PlatformTransactionManager实现来进行事务管理,同样的Spring也为我们提供了模板类TransactionTemplate进行事务管理,下面主要介绍模板类,我们需要在xml配置文件中配置.

 配置事务管理器:

 <!--配置事务管理的模板-->
    <bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
        <!--事务管理器id-->
        <property name="transactionManager" ref="transactionManager"></property>
        <!--定义事务隔离级别,-1表示使用数据库默认级别-->
        <property name="isolationLevelName" value="ISOLATION_DEFAULT"></property>
        <!--事务传播方式-->
        <property name="propagationBehaviorName" value="PROPAGATION_REQUIRED"></property>
    </bean>

基于tx和aop命名空间xml配置:

    <!--定义需要被任务管理器管理的方法-->
    <tx:advice id="advice" transaction-manager="transactionManager">
        <tx:attributes>
            <!--需要被管理的方法,还有其他的事务属性-->
            <tx:method name="insert" propagation="REQUIRED" read-only="false"  rollback-for="Exception"/>
        </tx:attributes>
    </tx:advice>

    <aop:config>
        <!--需要被管理类的包名-->
        <aop:pointcut id="pointCut" expression="execution (* com.gray.service.*.*(..))"/>
        <!--需要切入的任务管理器-->
        <aop:advisor advice-ref="advice" pointcut-ref="pointCut"/>
    </aop:config>

这样配置完后,所有com.gray.service下的所有类中的insert方法就会被事务管理器管理起来,事务提交都会进行验证,符合要求就会提交事务,不符合则抛出运行异常回滚.

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值