Spring学习笔记

Spring

1.简介

  • 首次推出:2002年 Spring框架雏形:interface21
  • 正式版:以interface21框架为基础,经过程序设计,并不断丰富内涵,于2004年3月24日,发布了1.0正式版
  • Spring理念:使现有技术更加容易使用,整合了现有的技术框架
    • SSH: Struct2+Spring+Hibernate
    • SSM:SpringMVC+Spring+Mybatis

官网: Spring Framework

中文文档:Spring Framework 中文文档 - Spring Framework 5.1.3.RELEASE Reference | Docs4dev

官方下载地址: repo.spring.io

GitHub: spring-projects/spring-framework: Spring Framework (github.com)

Spring Mavean

Maven Repository: Search/Browse/Explore (mvnrepository.com)

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

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

2.优点

  • Spring是一个开源的免费的框架
  • Spring是一个轻量级、非入侵式的框架
  • 两个特性:控制反转(IOC)、面向切面编程(AOP)
  • 支持事务的处理,对框架整合的支持

Spring是一个轻量级的控制反转(IOC)和面向切面编程(AOP)的框架

3.组成

在这里插入图片描述

参考博客:Spring框架七大核心模块_crazy丢的博客-CSDN博客_spring七大模块

4.Spring简化Java开发的策略

  • 基于POJO的轻量级和最小侵入性编程
  • 通过IOC,依赖注入(DI)和面向接口实现松耦合
  • 基于切面(AOP)和惯例进行声明式编程
  • 通过切面和末班减少样式代码

5.拓展

  • Spring Boot
    • 一个快速开发的脚手架
    • 基于SprintBoot可以快速开发单个微服务
  • Spring Cloud
    • 基于SpringBoot实现

IOC

1.理论推导

  • set注入

    private UserDao userDao;
    //利用set进行动态实现值的注入
    public void setUserDao(UserDao userDao) {
    	this.userDao = userDao;
    }
    

    使用set注入之后,程序由主动创建对象变为被动接受对象

    这种思想从本质上解决了问题,大大降低了系统的耦合性

2.本质

控制反转IOC是一种设计思想DI(依赖注入)是实现IOC的一种方法

没有IOC的程序中,我们使用面向对象编程,对象的创建与对象间的依赖关系完全硬编码在程序中,对象的创建由程序自己控制,控制反转后将对象的创建转移给第三方。获得依赖对象的方式反转了

IOC是Spring框架的核心内容,可以使用XML配置,也可以使用注解

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

在这里插入图片描述

采用XML方式配置Bean时,Bean的定义信息是和实现分离的,而采用注解的方式可以把两者合为一体,Bean的定义信息直接以注解的形式定义在实现类中,从而达到了零配置的目的

控制反转是一种通过描述(XML或注解)并通过第三方去生存或获取特定对象的方式。在Spring中实现控制反转的是IOC容器,其实现方法是依赖注入(DI)

3.控制反转过程

控制:传统应用程序的对象是由程序本身控制创建的,使用Spring后,对象是由Spring创建的

反转:程序本身不创建对象,变成被动的接收对象

依赖注入:利用Set方法进行注入

HelloSpring

beans.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
       https://www.springframework.org/schema/beans/spring-beans.xsd">
    <!--使用spring创建对象
    bean=对象     new Hello();
    id=变量名  class=new的对象    property相当于给对象设置一个值
    -->
    <bean id="hello" class="com.example.pojo.Hello">
        <property name="str" value="Spring"/>
    </bean>
</beans>

Hello.java

package com.example.pojo;
public class Hello {
    private String str;

    public String getStr() {
        return str;
    }

    public void setStr(String str) {
        this.str = str;
    }

    @Override
    public String toString() {
        return "Hello{" +
                "str='" + str + '\'' +
                '}';
    }
}

MyTest.java

import com.example.pojo.Hello;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyTest {
    public static void main(String[] args) {
        //获取Spring上下文对象
        ApplicationContext context=new ClassPathXmlApplicationContext("beans.xml");
        //对象都在Spring中管理 要使用时直接调用
        Hello hello=(Hello) context.getBean("hello");
        System.out.println(hello.toString());
    }
}

运行结果

在这里插入图片描述

  • Hello对象由Spring创建
  • Hello对象的属性由Spring容器设置(依赖注入)

IOC创建对象

  • 使用无参构造创建对象(默认)

  • 有参构造

    • 下标赋值

      <?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
             https://www.springframework.org/schema/beans/spring-beans.xsd">
          <!--下标赋值-->
          <bean id="user" class="com.example.pojo.User">
              <constructor-arg index="0" value="张三"/>
          </bean>
      </beans>
      
    • 通过类型创建

      <?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
             https://www.springframework.org/schema/beans/spring-beans.xsd">
          <!--通过类型创建-->
          <bean id="user" class="com.example.pojo.User">
              <constructor-arg type="java.lang.String" value="张三"/>
          </bean>
      </beans>
      
    • 通过参数名赋值

      <?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
             https://www.springframework.org/schema/beans/spring-beans.xsd">
          <!--通过参数名赋值-->
          <bean id="user" class="com.example.pojo.User">
              <constructor-arg name="name" value="张三"/>
          </bean>
      </beans>
      

Spring配置

1 别名

<alias name="user" alias="用户"/>

在程序中可以使用别名获取对象

2 Bean的配置

<bean id="user" class="com.example.pojo.User" name="user2,用户">
	<constructor-arg name="name" value="张三"/>
</bean>
<!--
	id:bean的唯一标识符,相当于对象名
    class:bean对象所对应的全限定名(包名+类名)
    name:作用等同alias,可以同时取多个别名
-->

3 import

一般用于团队开发,可以将多个配置文件导入合并为一个文件

依赖注入

注入方式:

  • 构造器注入
  • Set方式注入
  • 拓展方式注入

1 Set方式注入

依赖:bean对象的创建依赖于容器

注入:bean对象中的所有属性,由容器注入

环境搭建

复杂类型 Address.java

package com.example.pojo;

public class Address {
    private String address;

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "Address{" +
                "address='" + address + '\'' +
                '}';
    }
}

真实测试对象 Student.java

package com.example.pojo;

import java.util.*;

public class Student {
    private String name;
    private Address address;
    private String[] books;
    private List<String> hobby;
    private Map<String,String> card;
    private Set<String> games;
    private Properties info;

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Address getAddress() {
        return address;
    }
    public void setAddress(Address address) {
        this.address = address;
    }
    public String[] getBooks() {
        return books;
    }
    public void setBooks(String[] books) {
        this.books = books;
    }
    public List<String> getHobby() {
        return hobby;
    }
    public void setHobby(List<String> hobby) {
        this.hobby = hobby;
    }
    public Map<String, String> getCard() {
        return card;
    }
    public void setCard(Map<String, String> card) {
        this.card = card;
    }
    public Set<String> getGames() {
        return games;
    }
    public void setGames(Set<String> games) {
        this.games = games;
    }
    public Properties getInfo() {
        return info;
    }
    public void setInfo(Properties info) {
        this.info = info;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", address=" + address.toString() +
                ", books=" + Arrays.toString(books) +
                ", hobby=" + hobby +
                ", card=" + card +
                ", games=" + games +
                ", info=" + info +
                '}';
    }
}

applicationContext.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="address" class="com.example.pojo.Address">
        <property name="address" value="杭州"/>
    </bean>
    <bean id="student" class="com.example.pojo.Student">
        <!--普通值注入 value-->
        <property name="name" value="张三"/>
        <!--bean注入 ref-->
        <property name="address" ref="address"/>
        <!--数组注入 array value-->
        <property name="books">
            <array>
                <value>红楼梦</value>
                <value>水浒传</value>
                <value>西游记</value>
                <value>三国演义</value>
            </array>
        </property>
        <!--List注入-->
        <property name="hobby">
            <list>
                <value>听音乐</value>
                <value>打游戏</value>
                <value>看电影</value>
            </list>
        </property>
        <!--Map注入-->
        <property name="card">
            <map>
                <entry key="IDCard" value="1234567890"/>
                <entry key="Credit" value="1234561234"/>
            </map>
        </property>
        <!--Set注入-->
        <property name="games">
            <set>
                <value>LOL</value>
                <value>GenShin</value>
            </set>
        </property>
        <!--properties注入-->
        <property name="info">
            <props>
                <prop key="学号">1001</prop>
                <prop key="性别"></prop>
            </props>
        </property>
    </bean>
</beans>

测试类 MyTest.java

import com.example.pojo.Student;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyTest {
    public static void main(String[] args) {
        ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
        Student student=(Student) context.getBean("student");
        System.out.println(student.getName());
    }
}

2 拓展方式注入

p命名空间和c命名空间不能直接使用,需要导入xml约束

p命名空间:

xmlns:p="http://www.springframework.org/schema/p"

c命名空间

xmlns:c="http://www.springframework.org/schema/c"
<!--p命名空间注入 可以直接注入属性的值 property-->
<bean id="user" class="com.example.pojo.User" p:name="张三" p:age="20"/>
<!--c命名空间注入 通过构造器注入 construct-args-->
<bean id="user1" class="com.example.pojo.User" c:age="21" c:name="李四"/>

bean的作用域

单例模式 singleton

原型模式 prototype

每次从容器中get时产生一个新对象

Bean的自动装配

Spring在上下文中自动寻找,并为bean自动装配属性

装配方式

  • 在xml中显式的配置
  • 在java中显式配置
  • 隐式的自动装配

1 自动装配

    <bean id="cat" class="com.example.pojo.Cat"/>
    <bean id="dog" class="com.example.pojo.Dog"/>
    <!--
    byName:根据属性名和id匹配
    byType:根据属性的类型和class匹配
    -->
    <!--<bean id="person" class="com.example.pojo.Person" autowire="byName">
        <property name="name" value="张三"/>
    </bean>-->
    <bean id="person" class="com.example.pojo.Person" autowire="byType">
        <property name="name" value="张三"/>
    </bean>
  • byName需要保证所有bean的id唯一,并且这个bean需要和自动注入的属性的set方法的值一致

  • byType需要保证所有的bean的class唯一,并且这个bean需要和自动注入的属性的类型一致

2 使用注解实现自动装配

  • 导入约束 context约束

  • 配置注解的支持

    <context:annotation-config/>
    

@Autowired

  • 直接在属性或set方法上使用
  • 当自动装配的属性在IOC容器中存在且符合byName时,可以省略set方法
@Nullable //标记字段可以为null,作用同@Autowired(required=false)
package com.example.pojo;

import org.springframework.beans.factory.annotation.Autowired;

public class Person {
    @Autowired
    private Cat cat;
    @Autowired
    private Dog dog;
    private String name;

    public Cat getCat() {
        return cat;
    }

    public Dog getDog() {
        return dog;
    }

    public String getName() {
        return name;
    }

    @Override
    public String toString() {
        return "Person{" +
                "cat=" + cat +
                ", dog=" + dog +
                ", name='" + name + '\'' +
                '}';
    }
}

@Qualifier(value=“xxx”)

配合**@Autowired**使用,指定唯一的bean对象注入

@Resource

@Resource
private Cat cat;

@Resource和@Autowired区别

  • @Autowired通过byTame方式实现,且对象必须存在
  • @Resource默认通过byName方式实现,若找不到名字,就通过byType实现。如果两种方式都找不到,就报错

使用注解开发

1 bean

<?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:annotation-config/>
    <!--指定要扫描的包,使包下的注解生效-->
    <context:component-scan base-package="com.example.pojo"/>
</beans>

2 属性如何注入

package com.example.pojo;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component //相当于<bean id="user" class="com.example.pojo.User"/>
public class User {

    public String name;
    //相当于<property name="name" value="张三"/>
    @Value("张三")
    public void setName(String name) {
        this.name = name;
    }
}

3 衍生的注解

@Component的衍生注解

  • dao 【@Repository】
  • service 【@Service】
  • controller 【@Controller】

都代表将某个类注册到Spring中,并装配bean

使用java配置spring

JavaConfig:Spring的子项目,在Spring4之后成为核心功能

@Configuration
@ComponentScan("com.example.pojo")
public class MyConfig {
    @Bean
    //id为方法名 class属性为方法返回值
    public User getUser(){
        return new User();//返回要注入到bean的对象
    }
}

测试类

public class MyTest {
    public static void main(String[] args) {
        ApplicationContext context=new AnnotationConfigApplicationContext(MyConfig.class);
        User user= (User) context.getBean("getUser");
        System.out.println(user.name);
    }
}

代理模式

分类

  • 静态代理
  • 动态代理

1 静态代理

角色分析

  • 抽象角色:一般使用抽象类或接口解决
  • 真实角色:被代理的角色
  • 代理角色:代理真实角色
  • 客户:访问代理对象的角色

好处

  • 可以使真实角色的操作更纯粹
  • 公共业务由代理角色管理,实现了业务的分工
  • 公共业务发生扩展时,方便集中管理

缺点

  • 一个真实角色会产生一个代理角色,降低了开发效率

代码步骤

接口

package com.example.demo1;
//租房
public interface Rent {
    public void rent();
}

真实角色

package com.example.demo1;
//房东
public class Host implements Rent{

    @Override
    public void rent() {
        System.out.println("房东出租房子");
    }
}

代理角色

package com.example.demo1;

public class Proxy {
    private Host host;
    public Proxy(){}
    public  Proxy(Host host){
        this.host=host;
    }
    public void rent(){
        host.rent();
    }
    //看房
    public void seeHouse(){
        System.out.println("看房");
    }
    //收中介费
    public void fare(){
        System.out.println("收中介费");
    }
    //签租赁合同
    public void agreement(){
        System.out.println("签合同");
    }
}

客户端访问代理角色

package com.example.demo1;

public class Client {
    public static void main(String[] args) {
        //房东要出租房子
        Host host=new Host();
        //代理角色一般会有附属操作
        Proxy proxy=new Proxy(host);
        //越过房东 和中介对接
        proxy.rent();
    }
}

2 动态代理

  • 动态代理和静态代理角色一致
  • 动态代理的代理类是动态生成
  • 动态代理分类
    • 基于接口的动态代理
      • JDK动态代理
    • 基于类的动态代理
      • cglib
    • Java字节码实现
      • JAVAssist

动态代理的好处:

  • 一个动态代理类代理一个接口,对应一类业务
  • 只要实现同一个接口,一个动态代理类可以代理多个类
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

//使用这个类自动生成代理类
public class ProxyInvocationHandler implements InvocationHandler {
//    Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
//            new Class<?>[] { Foo.class },
//            handler);
    //被代理的接口
    private Object target;

    public void setTarget(Object target) {
        this.target = target;
    }

    //生成得到代理类
    public Object getProxy(){
        return Proxy.newProxyInstance(this.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                this);
    }

    //处理代理实例并返回结果
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        log(method.getName());
        Object result=method.invoke(target,args);//使用反射机制实现动态代理
        return result;
    }
    public void log(String msg){
        System.out.println("执行了"+msg+"方法");
    }
}

AOP(面向切面编程)

1 AOP在Spring中的作用

提供声明式事务;允许用户自定义切面

SpringAOP中,通过Advice定义横切逻辑。Spring中支持5中类型的Advice

2 使用Spring实现AOP

导入依赖包

<dependency>
	<groupId>org.aspectj</groupId>
	<artifactId>aspectjweaver</artifactId>
    <version>1.9.9.1</version>
</dependency>

方式一:使用Spring的API接口

applicationContext.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: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-->
    <bean id="userService" class="com.example.service.UserServiceImpl"/>
    <bean id="log" class="com.example.log.Log"/>
    <bean id="afterLog" class="com.example.log.AfterLog"/>
    <!--配置AOP-->
    <aop:config>
        <!--切入点
        expression:表达式
        -->
        <aop:pointcut id="pointcut" expression="execution(* com.example.service.UserServiceImpl.*(..))"/>
        <!--执行环绕增加-->
        <aop:advisor advice-ref="log" pointcut-ref="pointcut"/>
        <aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>
    </aop:config>
</beans>

execution表达式参考博客:

关于 expression=“execution(* com.xy.service..(…))”-pudn.com

Log.java

package com.example.log;

import org.springframework.aop.MethodBeforeAdvice;

import java.lang.reflect.Method;

public class Log implements MethodBeforeAdvice {
    //method:目标对象的方法
    //object:参数
    //target:目标对象
    @Override
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println(target.getClass().getName()+"的"+method.getName()+"方法被执行了");
    }
}

AfterLog.java

package com.example.log;

import org.springframework.aop.AfterReturningAdvice;

import java.lang.reflect.Method;

public class AfterLog implements AfterReturningAdvice {
    //returnValue:返回值
    @Override
    public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
        System.out.println("执行了"+method.getName()+"方法,返回结果为"+returnValue);
    }
}

MyTest.java

import com.example.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyTest {
    public static void main(String[] args) {
        ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
        //动态代理的是接口
        UserService userService=(UserService) context.getBean("userService");
        userService.add();
    }
}

运行结果

方式二:自定义类实现AOP

<!--自定义类实现AOP-->
<bean id="custom" class="com.example.custom.CustomPointCut"/>
<aop:config>
	<!--自定义切面:ref 要引用的类-->
	<aop:aspect ref="custom">
		<!--切入点-->
		<aop:pointcut id="point" expression="execution(* com.example.service.UserServiceImpl.*(..))"/>
		<!--通知-->
		<aop:before method="before" pointcut-ref="point"/>
		<aop:after method="after" pointcut-ref="point"/>
	</aop:aspect>
</aop:config>

CustomPointCut.java

package com.example.custom;

public class CustomPointCut {
    public void before(){
        System.out.println("方法执行前");
    }
    public void after(){
        System.out.println("方法执行后");
    }
}

方式三:使用注解实现AOP

AnnotationPointCut.java

package com.example.custom;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

@Aspect //将这个类标记为切面
public class AnnotationPointCut {
    @Before("execution(* com.example.service.UserServiceImpl.*(..))")
    public void before(){
        System.out.println("方法执行前");
    }
    @After("execution(* com.example.service.UserServiceImpl.*(..))")
    public void after(){
        System.out.println("方法执行后");
    }
    @Around("execution(* com.example.service.UserServiceImpl.*(..))")
    public void around(ProceedingJoinPoint joinPoint) throws Throwable{
        System.out.println("环绕前");
        //获得签名
        Signature signature = joinPoint.getSignature();
        System.out.println("signature:"+signature);
        Object proceed = joinPoint.proceed();//执行方法
        System.out.println("环绕后");
    }
}

运行结果

整合MyBatis

  • 导入相关jar包

    • junit

      <dependency>
          <groupId>junit</groupId>
          <artifactId>junit</artifactId>
          <version>4.12</version>
      </dependency>
      
    • mybatis

      <dependency>
          <groupId>org.mybatis</groupId>
          <artifactId>mybatis</artifactId>
          <version>3.5.10</version>
      </dependency>
      
    • mysql数据库

      <dependency>
          <groupId>mysql</groupId>
          <artifactId>mysql-connector-java</artifactId>
          <version>8.0.29</version>
      </dependency>
      
    • Spring相关

      <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-jdbc</artifactId>
          <version>5.3.20</version>
      </dependency>
      <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-webmvc</artifactId>
          <version>5.3.21</version>
      </dependency>
      
    • aop织入

      <dependency>
          <groupId>org.aspectj</groupId>
          <artifactId>aspectjweaver</artifactId>
          <version>1.9.9.1</version>
      </dependency>
      
    • mybatis-spring

      <dependency>  
          <groupId>org.mybatis</groupId>
          <artifactId>mybatis-spring</artifactId>
          <version>2.0.7</version>
      </dependency>
      

方式一

  • 编写实体类

  • 编写mapper接口

  • 实现mapper接口 mappe.xml

  • 编写mapper接口实现类 mapperImpl.java

    package org.example.mapper;
    
    import org.example.pojo.User;
    import org.mybatis.spring.SqlSessionTemplate;
    
    import java.util.List;
    
    public class UserMapperImmpl implements UserMapper{
        //原先使用SqlSession执行的操作,现在使用SqlSessionTemplate执行
        private SqlSessionTemplate sqlSessionTemplate;
        
        public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) {
            this.sqlSessionTemplate = sqlSessionTemplate;
        }
        
        @Override
        public List<User> queryUsers() {
            UserMapper mapper = sqlSessionTemplate.getMapper(UserMapper.class);
            return mapper.queryUsers();
        }
    }
    
  • 编写spring-dao.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"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
           https://www.springframework.org/schema/beans/spring-beans.xsd
           http://www.springframework.org/schema/context
                  http://www.springframework.org/schema/context/spring-context-4.2.xsd">
        <context:property-placeholder location="classpath:db.properties"/>
        <!--编写数据源配置
    DataSource:使用Spring的数据源替换MyBatis的配置
        org.springframework.jdbc.datasource.DriverManagerDataSource-->
        <bean id="datasource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
            <property name="driverClassName" value="${driver}"/>
            <property name="url" value="${url}"/>
            <property name="username" value="${jdbc_username}"/>
            <property name="password" value="${password}"/>
        </bean>
        <!--sqlSessionFactory-->
        <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
            <property name="dataSource" ref="datasource"/>
            <!--绑定MyBatis配置文件-->
            <property name="configLocation" value="mybatis-config.xml"/>
            <property name="mapperLocations" value="classpath:org/example/mapper/userMapper.xml"/>
        </bean>
        <!--sqlSessionTemplate=sqlSession-->
        <bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
            <!--只能使用构造器注入sqlSessionFactory,因为没有set方法-->
            <constructor-arg index="0" ref="sqlSessionFactory"/>
        </bean>
        <bean id="userMapper" class="org.example.mapper.UserMapperImmpl">
            <property name="sqlSessionTemplate" ref="sqlSessionTemplate"/>
        </bean>
    </beans>
    
    • 可能遇到的问题

      • Caused by: java.sql.SQLException: Access denied for user 'XXX'@'localhost' (using password: YES)
        

        错误原因:上面spring-dao.xml中第15行,username的值存在歧义

        解决办法:修改db.properties中的username的变量名,使其唯一,例如修改为jdbc_username

      • Property or field 'driver' cannot be found on object of type 'org.springframework.beans.factory.config.BeanExpressionContext' - maybe not public or not valid?
        

        错误原因:在注册datasource时,driver的值应该由${}引入

        解决办法:检查driver的值,改为${}引入

        如果报错的原因不是driver,检查field后的变量名即可

      • Mapped Statements collection already contains value for
        

        错误原因:同时在mapper核心配置文件及spring-dao.xml中注册了mapper

        解决办法:删除mapper核心配置文件中对mapper的注册

  • 测试

方式二

修改方式一中的实现类MapperImpl.java,继承SqlSessionDaoSupport类

package org.example.mapper;

import org.apache.ibatis.session.SqlSession;
import org.example.pojo.User;
import org.mybatis.spring.support.SqlSessionDaoSupport;

import java.util.List;

public class UserMapperImpl extends SqlSessionDaoSupport implements UserMapper{
    @Override
    public List<User> queryUsers() {
        SqlSession sqlSession = getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        return mapper.queryUsers();
    }
}

修改spring-dao.xml中注册userMapper的语句

<bean id="userMapper" class="org.example.mapper.UserMapperImpl2">
    <property name="sqlSessionFactory" ref="sqlSessionFactory"/>
</bean>

声明式事务

  • 声明式事务:AOP
  • 编程式事务:需要在代码中进行事务的管理
<!--结合AOP实现事务织入-->
<!--配置事务通知的类-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
    <!--需要配置事务的方法-->
    <!--配置事务的传播特性 propagation 默认为REQUIRED-->
    <tx:attributes>
        <tx:method name="*" propagation="REQUIRED"/>
    </tx:attributes>
</tx:advice>
<!--配置事务切入-->
<aop:config>
    <aop:pointcut id="txPointcut" expression="execution(* org.example.mapper.*.*(..))"/>
    <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>
</aop:config>

为什么需要事务

  • 如果不配置事务,可能存在数据提交时不一致的情况
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值