Spring的使用(入门到熟练)---强势总结

Spring的使用(入门到熟练)—强势总结

Spring:春天 ==》寓意就是程序员的春天来了

这里抛一个问题 在一个项目中如何使用多个框架呢? 又怎么将多个框组合到一起?

Spring这个框架最大的功能就是能够为业务逻辑层 提供事务 整合第三方框架 他相当于是所有框架之间的粘合剂。也就是说,这个鬼就像我们的胶水一样,能够把其他的框架整合到一起

1、Spring能干什么

  1. 为业务逻辑层提供事务
  2. 整合第三方框架
  3. 为Controller提供解决方案
  4. 为DAO层提供解决方案
  5. 提供了AOP编程的这种思想
  6. 实现了对象依赖的解耦

2、Spring中的七大模块

在这里插入图片描述

  • Core:这个是Spring的核心模块 主要功能 IOC(控制反转) DI(依赖注入)
  • AOP:面向切面编程 就是将你以前的重复代码,抽取城一个类,然后原来程序在正常运行的时候 动态植入我们抽取出来的代码,的这种编程思想就叫做面向切面编程
  • Web MVC:这个模块就是传说中的 SpringMVC,也就说SpringMVC其实是Spring框架的一个模块哦,别搞错了
  • Web:Spring这个框架对Web开发的支持
  • Context:上下文模块(这个就是类似一个类,这个类中保存了程序运行的所有信息,通过这个类就可以找到我们程序运行过程中的所有数据)
  • DAO:Spring提供了对数据库访问的支持,也就是JdbcTemplate(这个鬼类似于DBUtils的使用)
  • ORM:(Object Relation Mapping) 对象关系映射 即Java对象通过映射关系,映射到数据库表中,也就是表字段与属性一一对应,这里补充一下,Spring整合第三方数据库访问框架有 (Hibernate Mybatis Toplink …)

3、Spring的第一个程序

  1. 创建一个maven工程,这里是通过idea创建的

在这里插入图片描述

在这里插入图片描述

  1. pom.xml 导包
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>spring-test</artifactId>
    <version>1.0-SNAPSHOT</version>
    <dependencies>
        <!--导入Spring的相关包-->
        <!--core-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>5.1.5.RELEASE</version>
        </dependency>
        <!--context-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.1.5.RELEASE</version>
        </dependency>
        <!--web-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>5.1.5.RELEASE</version>
        </dependency>
        <!--web mvc-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.1.5.RELEASE</version>
        </dependency>
        <!--aop-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>5.1.5.RELEASE</version>
        </dependency>
        <!--事务-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>5.1.5.RELEASE</version>
        </dependency>
        
        <!--测试-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
    </dependencies>
</project>
  1. 创建User类
package com.csdn.pojo;

/**
 * @author jimoji
 * @date : 2022-11-19
 */
public class User {
    
    
    private String username;
    private String password;
    public User() {
    
    
    }

    public User(String username, String password) {
    
    
        this.username = username;
        this.password = password;
    }

    public String getUsername() {
    
    
        return username;
    }

    public void setUsername(String username) {
    
    
        this.username = username;
    }

    public String getPassword() {
    
    
        return password;
    }

    public void setPassword(String password) {
    
    
        this.password = password;
    }

    private void init() {
    
    
        System.out.println("执行了初始化方法");
    }
    private void destory() {
    
    
        System.out.println("执行了销毁方法");
    }

    @Override
    public String toString() {
    
    
        return "User{" +
                "username='" + username + '\'' +
                ", password=" + password +
                '}';
    }
}
  1. 创建spring配置文件

在这里插入图片描述

spring的配置文件名称是可以任意命名的,一般情况命名为spring.xml或者 spring-config.xml

这里是最齐全的spring-config.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:p="http://www.springframework.org/schema/p"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:task="http://www.springframework.org/schema/task"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-4.0.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc.xsd
        http://www.springframework.org/schema/task
        http://www.springframework.org/schema/task/spring-task-3.1.xsd" >

   <!--创建类的对象
        这个Spring创建完对象之后 会放到一个容器中
           这个容器 就叫做 IOC容器  或者 单例池
        id:给这个对象整一个唯一的标识
        name:给生成的对象弄个名字
        class:要生成那个类的对象
        scope:这个表示的是生成对象是单例还是多例呢?
               singleton:表示生成的是单例(单例会放到容器中)
               prototype:这个表示的是生成这个对象是多例的(是不会放到容器中的)
        init-method:当我们的对象放到IOC容器去之后 如果要进行初始化的操作 那么就调用这个后面的方法
        destroy-method:当这个对象在IOC容器中要进行销毁的时候 要执行的方法
    -->
    <bean id="user" class="com.csdn.pojo.User" scope="singleton" init-method="init" destroy-method="destory" lazy-init="false"></bean>
</beans>
  1. 接下来测试一波
public class TestUser {
    
    
    @Test
    public void testUser(){
    
    
        //classpath:表示resource文件夹的路径
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:spring-config.xml");
		//通过name获取bean
        User user = (User)context.getBean("user");2
            
        System.out.println("拿到的这个对象是:" +user);
        context.close();
    }
}

测试结果

在这里插入图片描述

4、Spring IOC

IOC:控制反转

相信部分小伙伴都会有这个疑问 谁控制了谁? 什么东西反转了?

接下来说说Java创建对象的方式有哪些 new 反射 序列化 克隆

IOC这个概念: 谁控制了谁? 原来闯将对象是程序员自己来完成的 学习了Spring之后,我们对象的创建就交给Spring来完成

​ 即Spring控制了Java对象的这个创建

​ 什么东西反转了呢? 创建对象的权力反转了,原来由程序员自己完成 现在由Spring来完成

4.1通过配置文件创建对象
4.1.1创建简单对象
	 <!--创建类的对象
        这个Spring创建完对象之后 会放到一个容器中
           这个容器 就叫做 IOC容器  或者 单例池
        id:给这个对象整一个唯一的标识
        name:给生成的对象弄个名字
        class:要生成那个类的对象
        scope:这个表示的是生成对象是单例还是多例呢?
               singleton:表示生成的是单例(单例会放到容器中)
               prototype:这个表示的是生成这个对象是多例的(是不会放到容器中的)
        init-method:当我们的对象放到IOC容器去之后 如果要进行初始化的操作 那么就调用这个后面的方法
        destroy-method:当这个对象在IOC容器中要进行销毁的时候 要执行的方法
	  -->
    <bean id="user" class="com.csdn.pojo.User" scope="singleton" init-method="init" destroy-method="destory" lazy-init="false">
	</bean>
4.1.2创建有构造器的对象
	<!--创建一个带有构造器的对象  通过下标来构建我们的这个数据-->
	<bean id="user" class="com.csdn.pojo.User">
        <constructor-arg index="0" value="叽莫叽"></constructor-arg>
        <constructor-arg index="1" value="123"></constructor-arg>
	</bean>

	<!--通过变量名字来初始化我们的对象-->
    <bean id="user2" class="com.csdn.pojo.User">
        <constructor-arg name="password" value="123"></constructor-arg>
        <constructor-arg name="username" value="叽莫叽"></constructor-arg>
	</bean>
4.2静态工厂创建对象
package com.csdn.factory;

import com.csdn.pojo.User;

/**
 * 工厂创建user
 * @author jimoji
 * @date : 2022-11-19
 */
public class UserFactory {
    
    
    /**
     * 非静态工厂创建对象
     * @return
     */
    public User getUser(){
    
    
        return new User("非静态工厂创建对象1","11111111111");
    }
    /**
     * 静态方法创建对象
     * @return
     */
    public static User getStaticUser(){
    
    
        return new User("静态工厂创建对象2","11111111111");
    }
}

编写我们的spring-config.xml

    <!--静态工厂创建对象-->
    <bean id="user3" class="com.csdn.factory.UserFactory" factory-method="getStaticUser"></bean>

	<!--非静态工厂创建对象-->
    <bean id="userFactory" class="com.csdn.factory.UserFactory"></bean>
    <!--
         factory-bean:这个表示的是工厂实例 这个实例一定要放到IOC容器
         factory-bean后面的值 一定是我们容器中对象的这个名字或者id
    -->
    <bean id="user4" factory-bean="userFactory" factory-method="getUser"></bean>

5、Spring DI

DI:依赖注入

谁依赖谁?

回顾一下三层结构 Controller —》Service —》DAO —》DB

你暂时可以这样去认为:

​ Controller依赖于Service

​ Serivce依赖于DAO

​ DAO依赖于DB

即一个类中,维护了另外一个类的实例对象 那么我们就可以认为 维护的这个类 依赖于被维护的这个类

注入了什么东西?

注入的是类的实例对象,还可以是具体的值,简单的说 啥都可以注入

注入:说白了就是给成员变量赋值 而这个值必须要在IOC容器中,如我们现在已经在xml文件中配置的user user1…都可以被

创建一个UserService

public class UserService {

    private UserDAO userDAO;

    public void setUserDAO(UserDAO userDAO) {
        this.userDAO = userDAO;
    }

    public void print(){
        userDAO.print();
    }
}
5.1 Set注入
	<bean id="userDAO" class="com.csdn.di.UserDAO"></bean>

    <bean id="userService" class="com.csdn.di.UserService">
        <!--Set注入的前提是这个成员变量一定要有Set方法
              在这种注入数据的方式在开发中用的很多
              ref:这一个表示的是引用 从IOC容器中去找对象  找对象的时候这个ref的值实际上就是我们对象在IOC容器中的这个值
              value:表示给定一个具体的值
        -->
       <!--这里的
			第一个userDAO是UserService类中set方法的名字
			第二个userDAO是xml文件中id=userDAO的bean
		-->
        <property name="userDAO" ref="userDAO"></property>
    </bean>
5.2 p标签注入

注意事项:就是我们的成员变量也必须要写 Set方法
还需要在beans引入 xmlns:p=“http://www.springframework.org/schema/p” 否则没法玩

说明一个问题:p标签注入的底层也是 set注入
<bean id="userDAO" class="com.csdn.di.UserDAO"></bean>
<bean id="userService" class="com.csdn.di.UserService" p:userDAO-ref="userDAO"></bean>
5.3 内部bean注入
<!--第三种注入方式:内部bean注入
        前提是类必须要为成员变量写Set方法
        这种方式的底层也是Set注入
    -->
    <bean id="userService" class="com.csdn.di.UserService">
        <property name="userDAO">
            <bean class="com.csdn.di.UserDAO"></bean>
        </property>
    </bean>
5.4 构造器注入
<!--下面写个构造器注入 说白了 就是在构造器上 为成员变量赋值-->
    <bean id="userDAO" class="com.csdn.di.UserDAO"></bean>
    <bean id="userService" class="com.csdn.di.UserService">
        <constructor-arg name="userDAO" ref="userDAO"></constructor-arg>
    </bean>

6、自动装配

autowire=“byName”:表示的意思是 会去找UserService中拥有Set方法的成员变量 然后通过名字去
IOC容器中找 名字相同的对象然后实施赋值
即UserService若有UserDAO这个属性,就会通过userDAO的set方法去容器中找userDAO的bean

<!--下面玩的是自动装配-->
    <bean id="userDAO" class="com.csdn.di.UserDAO"></bean>
    <!--
       autowire="byType" :这个表示的是通过类型 去IOC容器中找类型和 成员变量相同的然后实施赋值
       注意:成员变量必须有Set方法
    -->
    <bean id="userService" class="com.csdn.di.UserService" autowire="byType"></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:p="http://www.springframework.org/schema/p"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:task="http://www.springframework.org/schema/task"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-4.0.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc.xsd
        http://www.springframework.org/schema/task
        http://www.springframework.org/schema/task/spring-task-3.1.xsd" >

   <!--创建User类的对象-->
    <bean id="user" class="com.csdn.pojo.User" scope="singleton" init-method="init" destroy-method="destory" lazy-init="false"></bean>
    <!--创建一个带有构造器的对象  通过下标来构建我们的这个数据-->
	<bean id="user" class="com.csdn.pojo.User">
        <constructor-arg index="0" value="叽莫叽"></constructor-arg>
        <constructor-arg index="1" value="123"></constructor-arg>
	</bean>

	<!--通过变量名字来初始化我们的对象-->
    <bean id="user2" class="com.csdn.pojo.User">
        <constructor-arg name="password" value="123"></constructor-arg>
        <constructor-arg name="username" value="叽莫叽"></constructor-arg>
	</bean>
    
    <!--静态工厂创建对象-->
    <bean id="user3" class="com.csdn.factory.UserFactory" factory-method="getStaticUser"></bean>

	<!--非静态工厂创建对象-->
    <bean id="userFactory" class="com.csdn.factory.UserFactory"></bean>
    <bean id="user4" factory-bean="userFactory" factory-method="getUser"></bean>
    
	<!--第一种注入方式:Set注入-->
    <bean id="userDAO1" class="com.csdn.di.UserDAO"></bean>
    <bean id="userService1" class="com.csdn.di.UserService">
        <property name="userDAO" ref="userDAO1"></property>
    </bean>
    
    <!--第一种注入方式:p标签注入-->
	<bean id="userDAO2" class="com.csdn.di.UserDAO"></bean>
	<bean id="userService" class="com.csdn.di.UserService" p:userDAO-ref="userDAO2"></bean>
    
    <!--第三种注入方式:内部bean注入-->
    <bean id="userService3" class="com.csdn.di.UserService">
        <property name="userDAO">
            <bean class="com.csdn.di.UserDAO"></bean>
        </property>
    </bean>
    
     <!--第四种注入方式:构造器注入-->
    <bean id="userDAO4" class="com.csdn.di.UserDAO"></bean>
    <bean id="userService4" class="com.csdn.di.UserService">
        <constructor-arg name="userDAO" ref="userDAO4"></constructor-arg>
    </bean>
    
    <!--下面玩的是自动装配-->
    <bean id="userDAO" class="com.csdn.di.UserDAO"></bean>
    <bean id="userService" class="com.csdn.di.UserService" autowire="byType"></bean>
    
</beans>

7、使用注解完成上述功能

7.1 Spring的原始注解主要是替代<Bean>的配置
注解 说明
@Component 使用在类上用于实例化Bean
@Controller 使用在web层类上用于实例化Bean
@Service 使用在Service层类上用于实例化Bean
@Repository 使用在dao层类上用于实例化Bean
@Autowired 使用在字段上用于根据类型依赖注入
@Qualifier 结合@Autowired一起使用用于根据名称进行依赖注入
@Resource 相当于@Autowired+@Qualifier,按照名称进行注入
@Value 注入普通属性
@Scope 标注Bean的作用范围
@PostConstruct 使用在方法上标注该方法Bean的初始化方法
@PreDestroy 使用在方法上标注该方法是Bean的销毁方法

注意:@Controller@Service@Repository实际上只是为了我们更方便阅读,被语义化的注解,其实作用更@Component一样

//<bean name="userDao" class="com.dao.impl.UserDaoImpl"></bean>
//使用注解Repository替代配置文件中的bean

@Repository("userDAO")
public class UserDaoImpl implements UserDAO {
    @Override
    public void save() {
        System.out.println("save running...");
    }
}

注意:

使用注解进行开发时,需要在spring-config.xml中配置组件扫描,作用是指定哪个包及其子包下的Bean需要进行扫描以便使用注解配置的类、字段和方法。

<!--注解的组件扫描-->
<context:component-scan base-package="com"></context:component-scan>
7.2 Spring新注解

使用上面的注解还不能全部替代xml配置文件,还需要使用注解替代的配置如下:

  • 非自定义的Bean的配置:<bean>
  • 加载properties文件的配置:<context:property-placeholder>
  • 组件扫描的配置:<context:component-scan>
  • 引入其他文件<import>
注解 说明
@Configuration 用于指定当前类是一个Spring配置类,当闯将容器时会从该类上加载注解
@ComponentScan 用于指定Spring在初始化容器时要扫描的包
作用和在Spring的xml配置文件中的<context:component-scan base-package=“com”/>一样
@Bean 使用在方法上,标注将该方法的返回值存储到Spring容器中
@PropertySource 用于加载properties文件中的配置
@Import 用于导入其他配置类

8、代理设计模式

代理的设计模式是为了实现什么功能呢?

就是为了动态的的监控功能一个类中方法在什么时候 执行 以及能在方法的执行前后 动态的植入我们的代码

8.1 静态代理

静态代理 和动态代理都有一个代理的前提

这个代理前提就是 这个被代理的类必须实现接口,如果没有实现接口的话 那么这个代理是无法实现的

下面来实现一波

编写接口

public interface IUserService {
    
    
    /**
     * 更新数据
     */
    void update();
    /**
     * 插入数据
     */
    void  insert();
}

实现类

public class UserService implements IUserService{
    
    

    public void update() {
    
    
        System.out.println("-----------update------------");
    }
    public void insert() {
    
    
        System.out.println("-----------insert------------");
    }
}

代理类

1、编写代理类和被代理的类 实现相同的接口

2、在代理类中维护被代理的类的对象

3、在构造器中进行被代理类的初始化

4、在相同的名字方法中 调用被代理类中的相同的名字的方法

5、在代理类中调用被代理的类的方法的时候 就可以进行方法的增强了

public class UserServiceProxy implements IUserService{
    
    

    private IUserService userService;

    public UserServiceProxy(IUserService userService){
    
    
        this.userService=userService;
    }
    public void update() {
    
    
        System.out.println("打开事务");
        userService.update();
        System.out.println("提交事务");
    }
    public void insert() {
    
    
        System.out.println("打开事务");
        userService.insert();
        System.out.println("提交事务");
    }
}

测试一波

public class Test001 {
    
    
    public static void main(String[] args){
    
    
        UserServiceProxy userServiceProxy = new UserServiceProxy(new UserService());
        userServiceProxy.update();
    }
}
8.2 动态代理

动态代理 相当于是静态代理的实现 只不过 在JDK中已经帮你实现了 所以动态代理 还有一个名字 JDK代理

实现一波

编写接口类

public interface IUserService {
    
    
    /**
     * 更新数据
     */
    void update();
    /**
     * 插入数据
     */
    void  insert();
}

编写被代理的类

public class UserService implements IUserService {
    
    
    public void update() {
    
    
        System.out.println("-----------update------------");
    }
    public void insert() {
    
    
        System.out.println("-----------insert------------");
    }
}

编写代理类测试

public class Test001 {
    
    
    @Test
    public void testProxy(){
    
    
        /**
         * 第一个参数类加载器:这个固定的写法  被代理的类.class.getClassLoader()
         *           类加载器是用来干嘛的? 记住这个类加载器 是用来 加载类的 找类的
         * 第二个参数:当前这个代理的类实现的接口
         *           1、被代理的是类  被代理的类.class.getInterfaces()
         *           2、被代理的是接口  new Class[]{被代理的接口.class}
         * 第三个参数:监控这个类中方法在什么时候 进行调用
         *           new Invocationhandler{
         *
         *               ... invoke()....
         *
         *           }

         */
        IUserService userServiceProxy= (IUserService) Proxy.newProxyInstance(
                UserService.class.getClassLoader(),
                UserService.class.getInterfaces(),
                new InvocationHandler() {
    
    
                    /**
                     * 监控方法在什么时候 执行的
                     * @param proxy :代理类对象
                     * @param method :执行的目标方法
                     * @param args :执行方法需要的参数
                     * @return
                     * @throws Throwable
                     */
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    
    
                        String name = method.getName();
                        System.out.println("当前执行的方法是:"+name);
                        //你就可以执行目标方法了
                        //下面是反射执行方法 这个执行的是被代理类中的方法 所以只能使能被代理的类的对象来执行
                        Object invoke = method.invoke(new UserService(), args);
                        return invoke;
                    }
                }
        );
        //调用被代理的方法
        userServiceProxy.update();
    }
}
8.3 CGLIB代理

动静态代理都是对实现了接口的类进行代理,那没实现接口的类就不能被代理了吗,这显然不合规矩,因此我们的CGLIB代理应运而生了 即CGLIB代理说的问题是:一个类 没有实现接口 也可以写代理

接下来玩一下

  1. 导包
    <dependency>
        <groupId>cglib</groupId>
        <artifactId>cglib</artifactId>
        <version>3.3.0</version>
    </dependency>
  1. 被代理类UserService
public class UserService {
    
    
    public void update() {
    
    
        System.out.println("-----------update------------");
    }
    public void insert() {
    
    
        System.out.println("-----------insert------------");
    }
}
  1. 编写代理类
public class UserServiceProxyFactory implements MethodInterceptor{
    
    

    /**
     * 这个位置就是生成代理类的地方
     * @return
     */
    public  UserService getUserServiceProxy(){
    
    
        Enhancer enhancer=new Enhancer();
        //给生成的代理类整个爹
        enhancer.setSuperclass(UserService.class);
        //要监控他爹里面的方法在什么时候 进行调用
        enhancer.setCallback(this);
        return (UserService) enhancer.create();
    }

    /**
     * 专门用来拦截监听我们类中的方法在什么时候调用
     * @param o
     * @param method
     * @param objects
     * @param methodProxy
     * @return
     * @throws Throwable
     */
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
    
    
        String name = method.getName();
        System.out.println("当前执行的方法是:"+name);
        //执行的是 被代理的类中的方法
        Object invoke = method.invoke(new UserService(), objects);
        return invoke;
    }
}

测试类

public class Test001 {
    
    

    @Test
    public void testCGLIBPRoxy(){
    
    
        UserServiceProxyFactory proxyFactory = new UserServiceProxyFactory();
        UserService userServiceProxy = proxyFactory.getUserServiceProxy();
        userServiceProxy.update();
    }
}

9、AOP

AOP:是一种编程思想 类似于面向对象OOP

AOP究竟说的是啥? 简单说 就是我们在写代码的时候 有可能存在代码的重复(冗余) 这个时候 我们可以将这个代码抽取出来 专门放到一个类的方法中,然后当代码正常运行的时候 通过代理的设计模式 动态植入我们的代码 这种编程思想就叫做面向切面编程

在开发中你们有没有想过一个问题:就是我们的事务 如何控制?
在正常的开发中,我们的事务 不是添加到DAO层 ,而是添加到Service层的,因为一个业务的成功才代表了 一次操作的成功,所以在业务逻辑层上,所有的业务都应该有 打开事务 和 提交事务 的这个操作

简单点说 就是 每一个业务逻辑层的方法上 都有 打开事务 提交事务 的操作,如果是每一个方法我们都自己去写的话 那么代码会存在冗余 那么这个时候AOP就可以实现这个功能了

手动实现一个AOP
  1. 编写AOP类
@Component
public class Aop {
    
    
    /**
     * 打开事务
     */
    public void startTransaction(){
    
    
        System.out.println("....打开事务....");
    }
    /**
     * 提交事务
     */
    public void commitTransaction(){
    
    
        System.out.println("....打开事务....");
    }
}
  1. 编写UserService类
@Component
public class UserService {
    
    

    public void update() {
    
    
        System.out.println("-----------update------------");
    }

    public void insert() {
    
    
        System.out.println("-----------insert------------");
    }

}

  1. 编写代理类
package com.csdn.aop.sx;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

/**
 * @author jimoji
 * @date : 2022-11-19
 */
@Component
public class UserServiceProxyFactory implements MethodInterceptor{
    
    

    @Autowired
    private Aop aop;

    @Autowired
    private UserService userService;

    /**
     * 这个位置就是生成代理类的地方
     * @return
     */
    public  UserService getUserServiceProxy(){
    
    
        Enhancer enhancer=new Enhancer();
        //给生成的代理类整个爹
        enhancer.setSuperclass(UserService.class);
        //要监控他爹里面的方法在什么时候 进行调用
        enhancer.setCallback(this);
        return (UserService) enhancer.create();
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
    
    
        String name = method.getName();
        System.out.println("当前执行的方法是:"+name);
        //调用aop的方法
        aop.startTransaction();
        //执行的是 被代理的类中的方法
        Object invoke = method.invoke(userService, objects);
        //调用aop的方法
        aop.commitTransaction();
        return invoke;
    }
}
  1. 配置xml
<!--设置扫描Spring注解的位置-->
<context:component-scan base-package="com.csdn.aop.sx"></context:component-scan>
  1. 编写测试
    @Test
    public void testAop(){
    
    
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:spring-config.xml");
        UserServiceProxyFactory userServiceProxyFactory = context.getBean(UserServiceProxyFactory.class);
        UserService userServiceProxy = userServiceProxyFactory.getUserServiceProxy();
        userServiceProxy.update();
    }
9.2 使用配置模式实现AOP
  1. 编写AOP类
package com.csdn.aop.config;

import org.aspectj.lang.ProceedingJoinPoint;

/**
 * @author xiaobobo
 */
public class Aop {
    
    

    /**
     * 表示的是在执行目标方法之前执行
     */
    public void before(){
    
    

        System.out.println("----------before-----------");
    }
    /**
     * 在执行了目标方法之后执行
     */
    public void after(){
    
    
        System.out.println("----------after-----------");

    }

    public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
    
    
        System.out.println("---------------环绕之前---------------");
        proceedingJoinPoint.proceed();
        System.out.println("---------------环绕之后---------------");
    }

    /**
     * 在执行了目标方法有返回值的时候执行
     */
    public void afterReturn(){
    
    
        System.out.println("----------afterReturn-----------");

    }

    /**
     * 抛出异常的时候执行
     */
    public void afterThrowing(){
    
    
        System.out.println("----------afterThrowing-----------");
    }
}

  1. 编写UserService类
package com.csdn.aop.config;
import org.springframework.stereotype.Component
/**
 * @author jimoji
 * @date : 2022-11-19
 */
@Component
public class UserService {
    
    

    public void update() {
    
    
        System.out.println("-----------update------------");
    }

    public void insert() {
    
    
        System.out.println("-----------insert------------");
    }

}
  1. 编写配置文件spring-aop-config.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:p="http://www.springframework.org/schema/p"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:task="http://www.springframework.org/schema/task"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-4.0.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc.xsd
        http://www.springframework.org/schema/task
        http://www.springframework.org/schema/task/spring-task-3.1.xsd" >

    <!--全部使用配置来完成-->
    <bean id="aop" class="com.csdn.aop.config.Aop"></bean>

    <!--把这个类的对象放到IOC容器中去-->
    <bean id="userService" class="com.csdn.aop.config.UserService"></bean>

    <aop:config>
        <!--下面配置切入点表达式? 所谓的切入点指的是我们的代码植入的位置
            id:取名字 随便取 但是一般见名之意 pt
            expression:配置的是切入点表达式
            execution(* com.csdn.aop.config.UserService.*(..))
            第一个 *:表示的是方法的返回值  因为可能有很多个 那么不知道 不知道就写 *
            UserService.*:这里的这个 * :代表的是 这个类中的所有方法
            (..) :表示的是不知道这些方法的参数是什么  所以写两个 .
        -->
        <aop:pointcut id="pt" expression="execution(* com.csdn.aop.config.UserService.*(..))"></aop:pointcut>

        <!--下面配置咋们的切面-->
        <aop:aspect ref="aop">
            <aop:before method="before" pointcut-ref="pt"></aop:before>
            <aop:after method="after" pointcut-ref="pt"></aop:after>
            <aop:after-returning method="afterReturn" pointcut-ref="pt"></aop:after-returning>
            <aop:after-throwing method="afterThrowing" pointcut-ref="pt"></aop:after-throwing>
            <aop:around method="around" pointcut-ref="pt"></aop:around>
        </aop:aspect>
    </aop:config>
</beans>
  1. 编写测试
package com.csdn.aop.config;

import com.csdn.aop.sx.UserServiceProxyFactory;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @author jimoji
 * @date : 2022-11-19
 */
public class Test001 {
    
    
    @Test
    public void testAop(){
    
    
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:spring-aop-config.xml");
        UserService userService = context.getBean(UserService.class);
        userService.insert();

    }
}
9.3 使用注解模式实现AOP
  1. 编写配置文件
   <!--使能aop的自动代理-->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
    <!--设置Spring要扫描的这个包-->
    <context:component-scan base-package="com.csdn.aop.anno"></context:component-scan>
  1. 编写aop类
@Component
@Aspect    //表明当前的这个类 是一个切面类
public class Aop {
    
    
    /**
     * 定义切入点表达式
     */
    @Pointcut(value = "execution(* com.csdn.aop.anno.UserService.*(..))")
    public void pt(){
    
    }
    /**
     * 表示的是在执行目标方法之前执行
     */
    @Before(value = "pt()")
    public void before(){
    
    
        System.out.println("----------before-----------");
    }
    /**
     * 在执行了目标方法之后执行
     */
    @After(value = "pt()")
    public void after(){
    
    
        System.out.println("----------after-----------");
    }
    @Around(value = "pt()")
    public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
    
    
        System.out.println("---------------环绕之前---------------");
        proceedingJoinPoint.proceed();
        System.out.println("---------------环绕之后---------------");
    }
    /**
     * 在执行了目标方法有返回值的时候执行
     */
    @AfterReturning(value = "pt()")
    public void afterReturn(){
    
    
        System.out.println("----------afterReturn-----------");

    }
    /**
     * 抛出异常的时候执行
     */
    @AfterThrowing(value = "pt()")
    public void afterThrowing(){
    
    
        System.out.println("----------afterThrowing-----------");
    }
}
  1. 编写配置文件
    <!--使能aop的自动代理-->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
    
    <!--设置Spring要扫描的这个包-->
    <context:component-scan base-package="com.csdn.aop.anno"></context:component-scan>
  1. 编写UserService类
@Component
public class UserService {
    
    
    public void update() {
    
    
        System.out.println("-----------update------------");
    }
    public void insert() {
    
    
        System.out.println("-----------insert------------");
        throw new RuntimeException("出现了叽莫叽异常...");
    }
}
  1. 编写测试类
public class Test001 {
    
    
    @Test
    public void testAop(){
    
    
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:spring-aop-anno.xml");
        UserService userService = context.getBean(UserService.class);
        userService.insert();
    }
}

10、Spring中DAO模块的使用(不用记)

1.导包

        <!--Spring中的这个DAO实际导入的包是下面这个-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.1.3.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.40</version>
        </dependency>


        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.10</version>
        </dependency>


        <dependency>
            <groupId>commons-beanutils</groupId>
            <artifactId>commons-beanutils</artifactId>
            <version>1.9.3</version>
        </dependency>

  1. 编写DAO
package com.csdn.dao;

import com.csdn.pojo.User;
import org.apache.commons.beanutils.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Repository;

import java.lang.reflect.InvocationTargetException;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.List;

/**
 * @author jimoji
 * @date : 2022-11-19
 */
@Repository
public class UserDAO {
    
    

    @Autowired
    private JdbcTemplate jdbcTemplate;

    /**
     * 查询所有的数据库的对象
     */
    public List<User> selectList(){
    
    
        return jdbcTemplate.query("select * from t_user", new RowMapper<User>() {
    
    
            @Override
            public User mapRow(ResultSet resultSet, int i) throws SQLException {
    
    
                //将结果集取出来 映射成一个Java对象?
                //首先要获取列的数量
                ResultSetMetaData metaData = resultSet.getMetaData();
                //获取一共有几列数据
                int columnCount = metaData.getColumnCount();
                //遍历每一个行
                while (resultSet.next()){
    
    
                    User user = new User();
                    //每一行又有columnCount多个列
                    for (int j = 0; j <columnCount ; j++) {
    
    
                        //获取列的名字
                        String columnName = metaData.getColumnName(j+1);
                        //再通过列的民资 获取列的值
                        Object val = resultSet.getObject(columnName);
                        //这里需要将键值对映射到User对象中去
                        try {
    
    
                            BeanUtils.copyProperty(user,columnName,val);
                        } catch (IllegalAccessException e) {
    
    
                            e.printStackTrace();
                        } catch (InvocationTargetException e) {
    
    
                            e.printStackTrace();
                        }
                    }
                    return user;
                }
                return null;
            }
        });
    }



}

  1. 编写Service
package com.csdn.dao;

import com.csdn.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * @author jimoji
 * @date : 2022-11-19
 */
@Service
public class UserService {
    
    

    @Autowired
    private UserDAO userDAO;


    /**
     * 查询所有的用户对象
     * @return
     */
    public List<User> findUserAll(){
    
    
        List<User> userList = userDAO.selectList();
        System.out.println("查询到的数据是:"+userList);
        return userList;
    }
}
  1. 编写全局配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:task="http://www.springframework.org/schema/task"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-4.0.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc.xsd
        http://www.springframework.org/schema/task
        http://www.springframework.org/schema/task/spring-task-3.1.xsd" >

    <!--连接池需要配置-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
        <property name="url" value="jdbc:mysql:///cd_2209?useUnicode=true&amp;characterEncoding=UTF-8"></property>
        <property name="username" value="root"></property>
        <property name="password" value="root"></property>
    </bean>


    <!--配置操作数据库的这个对象-->
    <bean  id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!--设置Spring要扫描的这个包-->
    <context:component-scan base-package="com.csdn.dao"></context:component-scan>

</beans>
  1. 编写测试
package com.csdn.dao;
import com.csdn.pojo.User;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.util.List;

/**
 * @author jimoji
 * @date : 2022-11-19
 */
public class Test001 {
    
    
    @Test
    public void testAop(){
    
    

        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:bean-base-aop-dao.xml");

        UserService userService = context.getBean(UserService.class);
        List<User> userAll = userService.findUserAll();
        System.out.println("返回的数据是:"+userAll);
    }
}

11、Spring中的事务问题

以后做开发的时候要注意一个问题 :这个问题就是我们的事务 是应该添加到  业务逻辑层的方法上的
一个业务逻辑的成功与否 才代表了一次操作的成功与否

事务是添加到业务逻辑层的
11.1、通过配置方式实现Spring的事务
  1. 编写配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:task="http://www.springframework.org/schema/task"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-4.0.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc.xsd
        http://www.springframework.org/schema/task
        http://www.springframework.org/schema/task/spring-task-3.1.xsd" >

    <!--连接池需要配置-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
        <property name="url" value="jdbc:mysql:///cd_2209?useUnicode=true&amp;characterEncoding=UTF-8"></property>
        <property name="username" value="root"></property>
        <property name="password" value="root"></property>
    </bean>

    <!--配置操作数据库的这个对象-->
    <bean  id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!--配置一个事务管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>


    <!--配置我们的事务增强-->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <!--
                name="*表示的是所有方法"
                read-only="false":表示的是这些方法的事务类型是不是只读事务 如果是false表示的是读写事务
                只读事务只适合于查询数据
                读写事务 适合于增删改
            -->
            <tx:method name="*" read-only="false"/>
        </tx:attributes>
    </tx:advice>

    <!--接下来配置aop-->
    <aop:config>
        <!--这个表示在哪里使用这个事务-->
       <aop:pointcut id="pt" expression="execution(* com.csdn.tx.config.UserService.*(..))"></aop:pointcut>
        <!--接下来配置应用事务增强-->
        <aop:advisor advice-ref="txAdvice" pointcut-ref="pt"></aop:advisor>
    </aop:config>


    <!--设置Spring要扫描的这个包-->
    <context:component-scan base-package="com.csdn.tx.config"></context:component-scan>

</beans>
  1. 编写DAO
package com.csdn.tx.config;

import com.csdn.pojo.User;
import org.apache.commons.beanutils.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Repository;

import java.lang.reflect.InvocationTargetException;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.List;

/**
 * @author jimoji
 * @date : 2022-11-19
 */
@Repository
public class UserDAO {
    
    
    @Autowired
    private JdbcTemplate jdbcTemplate;
    /**
     * 查询所有的数据库的对象
     */
    public List<User> selectList(){
    
    
        return jdbcTemplate.query("select * from t_user", new RowMapper<User>() {
    
    
            @Override
            public User mapRow(ResultSet resultSet, int i) throws SQLException {
    
    
                //将结果集取出来 映射成一个Java对象?
                //首先要获取列的数量
                ResultSetMetaData metaData = resultSet.getMetaData();
                //获取一共有几列数据
                int columnCount = metaData.getColumnCount();
                //遍历每一个行
                while (resultSet.next()){
    
    
                    User user = new User();
                    //每一行又有columnCount多个列
                    for (int j = 0; j <columnCount ; j++) {
    
    
                        //获取列的名字
                        String columnName = metaData.getColumnName(j+1);
                        //再通过列的民资 获取列的值
                        Object val = resultSet.getObject(columnName);
                        //这里需要将键值对映射到User对象中去
                        try {
    
    
                            BeanUtils.copyProperty(user,columnName,val);
                        } catch (IllegalAccessException e) {
    
    
                            e.printStackTrace();
                        } catch (InvocationTargetException e) {
    
    
                            e.printStackTrace();
                        }
                    }
                    return user;
                }
                return null;
            }
        });
    }
    public void insert(){
    
    
        jdbcTemplate.update("insert into t_user(username,password) values('abc','bcd')");
    }
    public void update(){
    
    
        jdbcTemplate.update("update t_user set username='xxx'");
    }
}
  1. 编写Service
package com.csdn.tx.config;

import com.csdn.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * @author jimoji
 * @date : 2022-11-19
 */
@Service
public class UserService {
    
    
    @Autowired
    private UserDAO userDAO;
    /**
     * 查询所有的用户对象
     * @return
     */
    public List<User> findUserAll(){
    
    
        List<User> userList = userDAO.selectList();
        System.out.println("查询到的数据是:"+userList);
        return userList;
    }
    public void testTranaction(){
    
    
        userDAO.insert();
//        int k=1/0;
        userDAO.update();
    }
}
  1. 编写测试
package com.csdn.tx.config;
import com.csdn.pojo.User;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.util.List;

/**
 * @author jimoji
 * @date : 2022-11-19
 */
public class Test001 {
    
    
    @Test
    public void testAop(){
    
    
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:bean-base-tx-config.xml");
        UserService userService = context.getBean(UserService.class);
        userService.testTranaction();
    }
}
11.2 通过注解模式实现Spring的事务
  1. 编写配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:task="http://www.springframework.org/schema/task"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-4.0.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc.xsd
        http://www.springframework.org/schema/task
        http://www.springframework.org/schema/task/spring-task-3.1.xsd" >

    <!--连接池需要配置-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
        <property name="url" value="jdbc:mysql:///cd_2209?useUnicode=true&amp;characterEncoding=UTF-8"></property>
        <property name="username" value="root"></property>
        <property name="password" value="root"></property>
    </bean>

    <!--配置操作数据库的这个对象-->
    <bean  id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!--配置一个事务管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!--这个是使能这个事务的这个注解-->
    <tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>

    <!--设置Spring要扫描的这个包-->
    <context:component-scan base-package="com.csdn.tx.anno"></context:component-scan>

</beans>
  1. 编写DAO
package com.csdn.tx.anno;

import com.csdn.pojo.User;
import org.apache.commons.beanutils.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Repository;

import java.lang.reflect.InvocationTargetException;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.List;

/**
 * @author jimoji
 * @date : 2022-11-19
 */
@Repository
public class UserDAO {
    
    
    @Autowired
    private JdbcTemplate jdbcTemplate;
    public void insert(){
    
    
        jdbcTemplate.update("insert into t_user(username,password) values('abc','bcd')");
    }
    public void update(){
    
    
        jdbcTemplate.update("update t_user set username='xxx'");
    }
}

  1. 编写Service
package com.csdn.tx.anno;
import com.csdn.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import javax.lang.model.type.ArrayType;
import java.sql.SQLException;
import java.util.List;
/**
 * @author jimoji
 * @date : 2022-11-19
 */
@Service
public class UserService {
    
    
    @Autowired
    private UserDAO userDAO;
    /**
     * rollbackFor:这个表示的是哪一个异常需要回滚 rollbackFor = Exception.class
     * noRollbackFor:那个异常不需要回滚  noRollbackFor = ArithmeticException.class
     * timeout:你可以给这个操作设置一个过期时间  过期了 那么也就不能操作了 -1:永远不过期
     * isolation :设置事务的隔离级别  默认是可重复读  这个做开发不用设置
     * propagation:事务的传输类型
     * 这个是用在哪里的呢? 业务逻辑类调用业务逻辑类的场景 因为两个业务逻辑类 都有事务
     *    问题来了 , 那么这两个事务 以谁为准呢?
     *    如果是事务的传输类型是  Propagation.REQUIRED  那么A---->B 如果都有事务的话 那么会以A的事务为准 简单的说 b出错了 会引起A回滚
     *    如果事务的传输类型是 Propagation.REQUIRES_NEW的话 那么A和B之间的事务是两个事务 相互之间没有影响
     *
     *    readOnly = false:这个表示的是这个事务 是不是只读事务  一般增删改都需要读写事务所以这里需要设置成 false 如果是查询这里可以设置为true
     *
     */
    @Transactional(readOnly = false)
    public void testTranaction(){
    
    
        userDAO.insert();
        int k=1/0;
        userDAO.update();
    }
}
  1. 编写测试
package com.csdn.tx.anno;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @author jimoji
 * @date : 2022-11-19
 */
public class Test001 {
    
    
    @Test
    public void testAop(){
    
    
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:spring-tx-anno.xml");
        UserService userService = context.getBean(UserService.class);
        userService.testTranaction();
    }
}

总结一波:

ringframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import javax.lang.model.type.ArrayType;
import java.sql.SQLException;
import java.util.List;
/**

  • @author jimoji
  • @date : 2022-11-19
    /
    @Service
    public class UserService {
    @Autowired
    private UserDAO userDAO;
    /
    *
    • rollbackFor:这个表示的是哪一个异常需要回滚 rollbackFor = Exception.class
    • noRollbackFor:那个异常不需要回滚 noRollbackFor = ArithmeticException.class
    • timeout:你可以给这个操作设置一个过期时间 过期了 那么也就不能操作了 -1:永远不过期
    • isolation :设置事务的隔离级别 默认是可重复读 这个做开发不用设置
    • propagation:事务的传输类型
    • 这个是用在哪里的呢? 业务逻辑类调用业务逻辑类的场景 因为两个业务逻辑类 都有事务
    • 问题来了 , 那么这两个事务 以谁为准呢?
    • 如果是事务的传输类型是 Propagation.REQUIRED 那么A---->B 如果都有事务的话 那么会以A的事务为准 简单的说 b出错了 会引起A回滚
    • 如果事务的传输类型是 Propagation.REQUIRES_NEW的话 那么A和B之间的事务是两个事务 相互之间没有影响
    • readOnly = false:这个表示的是这个事务 是不是只读事务 一般增删改都需要读写事务所以这里需要设置成 false 如果是查询这里可以设置为true
    */
    @Transactional(readOnly = false)
    public void testTranaction(){
    userDAO.insert();
    int k=1/0;
    userDAO.update();
    }
    }

4. 编写测试

```java
package com.csdn.tx.anno;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @author jimoji
 * @date : 2022-11-19
 */
public class Test001 {
    @Test
    public void testAop(){
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:spring-tx-anno.xml");
        UserService userService = context.getBean(UserService.class);
        userService.testTranaction();
    }
}

总结一波:

此教程很适合刚入门的小伙伴查阅,里边涉及了Spring的五个模块的知识点,写的真的很详细,原创属实不易,希望小伙伴们多多支持。嘿嘿,感兴趣的给个关注

猜你喜欢

转载自blog.csdn.net/qq_48988285/article/details/127940171