Spring学习?这一篇文章就够,史上最全!

文章目录

  • 前言
  • 一、IOC概述及底层原理
    • 1.概述和原理
  • 二、思路分析
  • 三、IOC操作bean管理(基于xml,使用的是IDEA2022.3.3,maven仓库)
    • 1.xml实现bean管理
      • (1)创建对象
      • (2)注入属性
      • (3)p名称空间注入
      • (4)其他注入
        • 1.注入的属性值是null或者有符号,如下:
        • 2.注入外部bean,如下:
        • 3.内部bean注入
        • 4.级联赋值
        • 5.注入集合
      • (5)FactoryBean(工厂bean)
    • 2.bean的作用域
    • 3.bean的生命周期
    • 4.xml自动配置属性值
    • 5.外部属性文件操作bean
  • 四、注解实现bean管理
    • 1.基于注解创建对象
    • 2.组件扫描细节
    • 3.基于注解进行属性注入
  • 五、完全注解开发
  • 六、AOP概述和原理
    • 1.概述和原理
    • 2.JDK动态代理实例
  • 七、基于AspectJ实现的AOP操作
    • 1.什么是AspectJ
    • 2.AOP相关术语
    • 3.切点表达式
    • 3.基于注解方式实现
      • (1)实例:
      • (2)切入点提取
      • (3)设置增强类优先级
      • (4)完全注解开发
    • 4.基于xml配置文件实现(了解)
  • 八、JdbcTemplate
    • 1.相关依赖(AOP、IOC、JdbcTemplate都有)
    • 2.代码实战
      • (1)方法讲解
      • (2)代码实例
  • 九、事务及其参数含义
    • 1.事务的四个特性
    • 2.事务的传播行为(propagation)
    • 3.事务隔离性
    • 4.事务的隔离级别(ioslation)
    • 5.timeout(超时)
    • 6.readOnly(是否只读)
    • 7.rollbackFor(回滚)
    • 8.noRollbackFor(不回滚)
  • 十、事务管理
    • 1.事务管理的两种形式
    • 2.注解实现声明式事务管理
    • 3.xml实现声明式事务管理
    • 4.完全注解开发
  • 总结


前言

Spring框架:IOC、AOP、JdbcTemplate、事务管理,带你一篇速通。


一、IOC概述及底层原理

1.概述和原理

  • IOC是控制反转的意思。使用对象时候由主动new对象转换成由外部提供对象,此过程中对象的创建权由程序转移到外部,这种思想叫做控制反转。即把对象创建和对象的调用过程交给spring进行管理。
  • 目的:降低耦合度。
  • 底层原理:xml配置,反射,工厂模式。
  • Spring提供IOC容器两种实现方式(两个接口)
    (1)BeanFactory:Spring内部使用的接口,不提倡开发人员使用。特点:加载配置文件时不会创建对象,获取对象时才会创建对象。
    (2)ApplicationContext:BeanFactory的子接口,提供了更多更强大的功能,一般由开发人员使用。特点:加载配置文件时会把配置文件里的对象进行创建。
    (3)核心:Spring提供了一个容器,称为IOC容器,用来充当IOC思想中的外部
    IOC容器负责对象的创建、初始化等一系列工作,被创建或被管理的对象在IOC容器中统称为Bean。
  • ApplicationContext两个常用的实现类:
    (1)FileSystemXmlApplicationContext:绝对路径,从盘符开始算起
    (2)ClassPathXmlApplicationContext:相对路径,从项目的src开始算起
    在这里插入图片描述
  • IOC实现:依赖注入,即在容器中建立bean与bean之间的依赖关系的整个过程。

二、思路分析

  • IOC管理什么(bean对象)
  • 如何告知IOC去管理bean对象(通过配置文件)
  • 被管理的对象交给IOC容器,如何获取IOC容器?(接口)
  • IOC容器得到后,如何获取bean?(通过ApplicationContext接口的两个实现类的getBean方法获取bean实例创建对象)

三、IOC操作bean管理(基于xml,使用的是IDEA2022.3.3,maven仓库)

首先告诉大家本篇文章的所有使用的spring依赖版本:

    <dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>6.0.9</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-beans</artifactId><version>6.0.9</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-core</artifactId><version>6.0.9</version></dependency><dependency><groupId>commons-logging</groupId><artifactId>commons-logging</artifactId><version>1.2</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.2.8</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-aop</artifactId><version>6.0.9</version></dependency></dependencies>

1.xml实现bean管理

(1)创建对象

项目的resource资源文件夹创建spring的配置文件,然后添加如下代码:

<bean id="book" class="com.dragon.spring5.Book"></bean>
  • id:创建对象的名称
  • class:Book类的路径
  • 创建对象时默认是执行无参构造函数
    在这里插入图片描述

(2)注入属性

创建对象后,对象内的属性还没有赋值等等,讲诉三种注入属性得到方式:

  • 第一种:set方法注入
    这种方法需要类的属性有对应的set方法,如下:
public class Book {private String bname;private String bauthor;public void setBname(String bname) {this.bname = bname;}public void setBauthor(String bauthor) {this.bauthor = bauthor;}public void testbook(){System.out.println(bname+":"+bauthor);}
}

然后在spring配置文件中通过property标签进行属性注入,如下:

<bean id="book" class="com.dragon.spring5.Book"><property name="bname" value="易筋经"></property><property name="bauthor" value="达摩老祖"></property>
</bean>

然后测试:

	<!--加载spring配置文件创建对象-->ApplicationContext context=new ClassPathXmlApplicationContext("bean.xml");<!--反射-->Book book=context.getBean("book", Book.class);System.out.println(book);book.testbook();

在这里插入图片描述

  • 第二种:有参构造方法注入
    提供有参构造方法:
public class Book {private String bname;private String bauthor;public Book(String bname, String bauthor) {this.bname = bname;this.bauthor = bauthor;}public void testbook(){System.out.println(bname+":"+bauthor);}
}

然后在spring配置文件中,如下:

<bean id="book" class="com.dragon.spring5.Book"><constructor-arg name="bname" value="易筋经"></constructor-arg><constructor-arg name="bauthor" value="达摩老祖"></constructor-arg>
</bean>

(3)p名称空间注入

set方法、测试的代码跟上诉一样,不再赘诉。
在spring配置文件中添加p名称空间,和配置代码:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"<!--添加p名称空间-->xmlns:p="http://www.springframework.org/schema/p"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="book" class="com.dragon.spring5.Book" p:bname="九阴神功" p:bauthor="无名氏"></bean></beans>

在这里插入图片描述

(4)其他注入

1.注入的属性值是null或者有符号,如下:
<bean id="book" class="com.dragon.spring5.Book"><property name="bauthor"><null/></property><property name="bname"><value><![CDATA[<<读者>>]]></value></property></bean>
  • 有符号:用<![CDATA[带符号的属性值(包括符号)]]>
  • 空值:< null />

在这里插入图片描述

2.注入外部bean,如下:

spring配置文件:

  • ref:引用外部bean的id值
    <bean id="userService" class="com.dragon.spring5.service.UserService"><property name="userDao" ref="userDaoImpl"></property></bean><bean id="userDaoImpl" class="com.dragon.spring5.dao.UserDaoImpl"></bean>

UserService、UserDao、UserDaoImpl、测试类代码:

package com.dragon.spring5.dao;public interface UserDao {public void update();
}
=============================================================
package com.dragon.spring5.dao;public class UserDaoImpl implements UserDao{@Overridepublic void update() {System.out.println("dao update.......");}
}
=========================================================
package com.dragon.spring5.service;import com.dragon.spring5.dao.UserDao;public class UserService {private UserDao userDao;public void setUserDao(UserDao userDao) {this.userDao = userDao;}public void add(){System.out.println("service add........");userDao.update();}
}
======================================================
ApplicationContext context=new ClassPathXmlApplicationContext("bean1.xml");
UserService userService=context.getBean("userService", UserService.class);
userService.add();

在这里插入图片描述

3.内部bean注入

不通过ref属性,而是通过嵌套一个bean标签实现
spring配置文件:

        <bean id="emp" class="com.dragon.spring5.bean.Emp"><property name="enanme" value="lucy"></property><property name="gender" value="女"></property><property name="dept"><bean id="dept" class="com.dragon.spring5.bean.Dept"><property name="dname" value="保安部门"></property></bean></property></bean>

Emp、Dept、测试类代码:

package com.dragon.spring5.bean;public class Emp {private String enanme;private String gender;private Dept dept;public Dept getDept() {return dept;}public void setDept(Dept dept) {this.dept = dept;}public void setEnanme(String enanme) {this.enanme = enanme;}public void setGender(String gender) {this.gender = gender;}public void add(){System.out.println(enanme+"::"+gender+"::"+dept);}
}
===================================================================
package com.dragon.spring5.bean;public class Dept {private String dname;public void setDname(String dname) {this.dname = dname;}@Overridepublic String toString() {return "Dept{" +"dname='" + dname + '\'' +'}';}
}
==========================================================================
ApplicationContext context1=new ClassPathXmlApplicationContext("bean2.xml");Emp emp=context1.getBean("emp", Emp.class);emp.add();

在这里插入图片描述

4.级联赋值

写法一:也就是上面所说的外部bean,通过ref属性来获取外部bean
写法二:
emp类中有ename和dept两个属性,其中dept有dname属性,写法二需要emp提供dept属性的get方法。

                <bean id="emp" class="com.dragon.spring5.bean.Emp"><property name="enanme" value="john"></property><property name="gender" value="男"></property><!--写法一--><property name="dept" ref="dept"></property><!--写法二--><property name="dept.dname" value="技术部"></property></bean><bean id="dept" class="com.dragon.spring5.bean.Dept"><property name="dname" value="财务部"></property></bean>
5.注入集合

stu类:

package com.dragon.spring5.collectiontype;import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;public class Stu {private String[] courses;private List<String> list;private Map<String,String> maps;private Set<String> sets;private List<Course> courselist;public void setCourselist(List<Course> courselist) {this.courselist = courselist;}public void setSets(Set<String> sets) {this.sets = sets;}public void setCourses(String[] courses) {this.courses = courses;}public void setList(List<String> list) {this.list = list;}public void setMaps(Map<String, String> maps) {this.maps = maps;}public void test(){System.out.println(Arrays.toString(courses));System.out.println(list);System.out.println(maps);System.out.println(sets);System.out.println(courselist);}
}

Course类:

package com.dragon.spring5.collectiontype;public class Course {private String cname;public void setCname(String cname) {this.cname = cname;}@Overridepublic String toString() {return "Course{" +"cname='" + cname + '\'' +'}';}
}

spring配置文件:

<bean id="stu" class="com.dragon.spring5.collectiontype.Stu"><property name="courses"><array><value>java课程</value><value>数据库课程</value></array></property><property name="list"><list><value>张三</value><value>小三</value></list></property><property name="maps"><map><entry key="JAAVA" value="java"></entry><entry key="PHP" value="php"></entry></map></property><property name="sets"><set><value>MySQL</value><value>Redis</value></set></property><!--外部bean注入--><property name="courselist"><list><ref bean="course1"></ref><ref bean="course2"></ref></list></property>
</bean>
<bean id="course2" class="com.dragon.spring5.collectiontype.Course"><property name="cname" value="MyBatis框架"></property>
</bean>

测试:

		ApplicationContext context=new ClassPathXmlApplicationContext("bean3.xml");Stu stu=context.getBean("stu", Stu.class);stu.test();

在这里插入图片描述
集合提取出来注入:
用util标签(注意util标签怎么引入):
Book类:

package com.dragon.spring5.collectiontype;import java.util.List;public class Book {private List<String> list;public void setList(List<String> list) {this.list = list;}public void test(){System.out.println(list);}
}
<?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:util="http://www.springframework.org/schema/util"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"><util:list id="booklist"><value>易筋经</value><value>九阳神功</value><value>九阴真经</value></util:list><bean id="book" class="com.dragon.spring5.collectiontype.Book" scope="prototype"><property name="list" ref="booklist"></property></bean>
</beans>

(5)FactoryBean(工厂bean)

普通bean在配置文件中定义的bean类型就是返回类型。而工厂bean在配置文件定义的bean类型可以和返回类型不一样。
下面的MyBean类中实现FactoryBean接口,重写getObject,getObjectType方法。
这里把getObject重写成返回Course对象的方法。

package com.dragon.spring5.factorybean;import com.dragon.spring5.collectiontype.Course;
import org.springframework.beans.factory.FactoryBean;public class MyBean implements FactoryBean<Course> {@Overridepublic Course getObject() throws Exception {Course course=new Course();course.setCname("abc");return course;}@Overridepublic Class<?> getObjectType() {return null;}@Overridepublic boolean isSingleton() {return FactoryBean.super.isSingleton();}
}

spring配置文件:

<bean id="mybean" class="com.dragon.spring5.factorybean.MyBean"></bean>

测试:
注意这里实例化对象不是MyBean类型,是上面getObject方法返回的对象类型。

		ApplicationContext context=new ClassPathXmlApplicationContext("bean5.xml");Course course=context.getBean("mybean", Course.class);System.out.println(course);

在这里插入图片描述

2.bean的作用域

  • 在Spring中,默认情况下bean创建的是单实例对象:
 		ApplicationContext context1=new ClassPathXmlApplicationContext("bean4.xml");Book book1=context1.getBean("book", Book.class);Book book2=context1.getBean("book", Book.class);

在这里插入图片描述
可以看出地址一样

  • bean有个属性是scope,可以通过设置成singleton或prototype来决定其是单实例还是多实例(1)singleton:默认值,表示单实例对象。加载配置文件时就会创建单实例对象。
    (2)prototype:表示多实例对象。不是在加载配置文件时创建对象,在调用getBean方法时创建多实例对象。
<bean id="book" class="com.dragon.spring5.collectiontype.Book" scope="prototype"><property name="list" ref="booklist"></property>
</bean>

在这里插入图片描述

  • scope的值还可以是request、session(大家应该知道这两个值的作用域吧)

3.bean的生命周期

(1)通过构造器创建 bean 实例(无参数构造)

(2)为 bean 的属性设置值和对其他 bean 引用(调用 set 方法)

(3)把 bean 实例传递 bean 后置处理器的方法 postProcessBeforeInitialization

(4)调用 bean 的初始化的方法(需要进行配置初始化的方法)

(5)把 bean 实例传递 bean 后置处理器的方法 postProcessAfterInitialization

(6)bean 可以使用了(对象获取到了)

(7)当容器关闭时候,调用 bean 的销毁的方法(需要进行配置销毁的方法)
下面提供大家测试需要用的类,方便大家理解:
Orders类:

package com.dragon.spring5.bean;public class Orders {private String oname;public Orders() {System.out.println("第一步 执行无参数构造创建bean实例");}public void setOname(String oname) {this.oname = oname;System.out.println("第二步 调用set方法设置属性值");}public void initMethod(){System.out.println("第三步 执行初始化方法");}public void destoryMethod(){System.out.println("第五步 bean销毁的方法");}
}

后置处理器:

package com.dragon.spring5.bean;import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;public class MyBeanPost implements BeanPostProcessor {@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {System.out.println("在初始化之前执行的方法");return bean;}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {System.out.println("在初始化之后执行的方法");return bean;}
}

测试:

package com.dragon.spring5.testDemo;import com.dragon.spring5.bean.Orders;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class test3 {public static void main(String[] args) {ClassPathXmlApplicationContext context=new ClassPathXmlApplicationContext("bean6.xml");Orders orders=context.getBean("orders", Orders.class);System.out.println("第四步 获取创建beam实例对象");System.out.println(orders);context.close();}
}

spring配置文件:

        </bean>
<!--        后置处理器--><bean id="myBeanPost" class="com.dragon.spring5.bean.MyBeanPost"></bean>

在这里插入图片描述

4.xml自动配置属性值

bean标签属性autowire两个常用值:
(1)byName:根据属性名称注入,注入值bean的id值和类属性名称一样
(2)byType:根据属性类型注入
spring配置文件:
(Emp类中有dept属性)

<bean id="emp" class="com.dragon.spring5.autowrite.Emp"><property name="dept" ref="dept"></property>
</bean>
<bean id="dept" class="com.dragon.spring5.autowrite.Dept"></bean>

正常情况下属性值需要用property标签注入。
而用autowire,可以自动注入

        <bean id="emp" class="com.dragon.spring5.autowrite.Emp" autowire="byName"></bean><bean id="dept" class="com.dragon.spring5.autowrite.Dept"></bean>

5.外部属性文件操作bean

这里用连接数据库举例:
在resource文件夹内jdbc属性文件(jdbc.properties)

pro.driverClass=com.mysql.jdbc.Driver
pro.url=jdbc:mysql://localhost:3306/?(这个根据自己数据库配置)
pro.username=root
pro.password=root

spring配置文件(注意context配置,这里使用的< context:property-placeholder/ >标签引入属性文件,其中classpath就是配置属性文件的全称):

<?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.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"><context:property-placeholder location="classpath:jdbc.properties"/><bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"><property name="driverClassName" value="${pro.driverClass}"></property><property name="url" value="${pro.url}"></property><property name="username" value="${pro.username}"></property><property name="password" value="${pro.password}"></property></bean>
</beans>

四、注解实现bean管理

1.基于注解创建对象

spring提供四种创建对象的注解(下面四个注解说的一般使用在哪层是约定俗成的,其实效果都一样,都可以混用):

  • @Component
  • @Service:一般用于业务逻辑或Service层
  • @Controller:一般用于web层
  • @ Repository:一般用于Dao层
    步骤:
    (1)引入依赖(开头已告知所有maven依赖库)
    (2)开启组件扫描:扫描base-package包下所有有注解的类并为其创建对象
<context:component-scan base-package="com.dragon.spring5_1"></context:component-scan>

代表扫描com.dragon.spring5_1下的所有文件,找寻有注解的文件,然后创建实例。
(2)创建类并在类上创建对象注解

@Service(value = "userService")
public class UserService {public void add(){System.out.println("service add.......");}
}

测试:

        ApplicationContext context=new ClassPathXmlApplicationContext("bean9.xml");UserService userService=context.getBean("userService",UserService.class);System.out.println(userService);userService.add();

在这里插入图片描述

2.组件扫描细节

还有两种用法:

        设置不扫描的注解<context:component-scan base-package="com.dragon.spring5_1"><context:exclude-filter type="annotation" expression="org.springframework.stereotype.Component"/></context:component-scan>设置扫描的注解<context:component-scan base-package="com.dragon.spring5_1" use-default-filters="false"><context:include-filter type="annotation" expression="org.springframework.stereotype.Component"/></context:component-scan>

3.基于注解进行属性注入

  • @Autowired:根据属性类型自动装配
  • @Qualifier:根据属性名称自动装配,需要和@Autowired一起使用
    当遇到一个接口有很多实现类时,只通过@Autowire是无法完成自动装配的,所以需要再使用@Qualifier通过名称来锁定某个类
  • @Resource:可以根据类型注入,也可以根据名称注入(不常用)
  • @Value:注入属性值
    实例:
    UserDao、UserDaoImpl、UserService类:
package com.dragon.spring5_1.dao;import org.springframework.stereotype.Repository;public interface UserDao {public void add();
}
==================================================
package com.dragon.spring5_1.dao;import org.springframework.stereotype.Repository;@Repository(value = "userDaoImpl1")
public class UserDaoImpl implements UserDao{@Overridepublic void add() {System.out.println("dao add......");}
}
=========================================================
package com.dragon.spring5_1.service;import com.dragon.spring5_1.dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;import javax.annotation.Resource;@Service(value = "userService")
public class UserService {@Value(value = "abc")private String name;@Autowired@Qualifier(value ="userDaoImpl1")private UserDao userDao;public void add(){System.out.println("service add......."+name);userDao.add();}
}

spring配置文件:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context  http://www.springframework.org/schema/context/spring-context.xsd"><context:component-scan base-package="com.dragon.spring5_1"></context:component-scan>
</beans>

测试:

	ApplicationContext context=new ClassPathXmlApplicationContext("bean9.xml");UserService userService=context.getBean("userService",UserService.class);System.out.println(userService);userService.add();

在这里插入图片描述

五、完全注解开发

上面讲诉后,完全注解开发应该是最简洁的。来个实例看一看。
这时要引入配置类来代替spring配置文件,来实现组件扫描不用xml配置,进而实现完全注解开发。
配置类:

package com.dragon.spring5_1.config;import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;@Configuration//配置类
@ComponentScan(basePackages = {"com.dragon.spring5_1"})//配置扫描的文件
public class SpringConfig {}

测试(UserDao、UserDaoImpl、UserService还是上面基于注解属性注入例子的):

package com.dragon.spring5_1.testDemo;import com.dragon.spring5_1.config.SpringConfig;
import com.dragon.spring5_1.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;public class test2 {public static void main(String[] args) {//注意new的对象变了,变成了AnnotationConfigApplicationContextApplicationContext context=new AnnotationConfigApplicationContext(SpringConfig.class);UserService userService=context.getBean("userService", UserService.class);System.out.println(userService);	userService.add();}
}

六、AOP概述和原理

用的依赖(包括上篇文章讲诉的IOC依赖):

       <dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>6.0.9</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-beans</artifactId><version>6.0.9</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-core</artifactId><version>6.0.9</version></dependency><dependency><groupId>commons-logging</groupId><artifactId>commons-logging</artifactId><version>1.2</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.2.8</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-aop</artifactId><version>6.0.9</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-aspects</artifactId><version>6.0.9</version></dependency><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.9.19</version><scope>runtime</scope></dependency><dependency><groupId>aopalliance</groupId><artifactId>aopalliance</artifactId><version>1.0</version></dependency><dependency><groupId>net.sourceforge.cglib</groupId><artifactId>com.springsource.net.sf.cglib</artifactId><version>2.1.3</version></dependency>

1.概述和原理

  • AOP:面向切面编程。利用 AOP 可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。通俗来说就是在不修改代码的情况下添加新的功能。
  • 底层通过动态代理实现:
    (1)有接口情况:使用JDK动态代理,即创建接口实现类的代理对象。
    (2)无接口情况:使用CGLIB动态代理,即创建当前类子类的代理对象。

2.JDK动态代理实例

核心:

  • 通过 java.lang.reflect.Proxy类 的 newProxyInstance方法 创建代理类。
  • newProxyInstance方法
    在这里插入图片描述
    参数一:类加载器
    参数二:所增强方法所在的类,这个类实现的接口,支持多个接口
    参数三:实现InvocationHandle接口,重写invoke方法来添加新的功能
    模拟代理:
    UserDao、UserDaoImpl类:
package com.dragon.springaop;public interface UserDao {public int add(int a,int b);public String update(String id);
}
================================================
package com.dragon.springaop;public class UserDaoImpl implements UserDao{@Overridepublic int add(int a,int b) {System.out.println("add方法执行了...");return a+b;}@Overridepublic String update(String id) {System.out.println("update方法执行了...");return id;}
}

JDKProxy类(通过 java.lang.reflect.Proxy类 的 newProxyInstance方法创建代理类):

package com.dragon.springaop;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;public class JDKProxy {public static void main(String[] args) {Class[] interfaces={UserDao.class};//创建接口实现类代理对象UserDaoImpl userDao=new UserDaoImpl();UserDao dao=(UserDao)Proxy.newProxyInstance(JDKProxy.class.getClassLoader(),interfaces,new UserDaoProxy(userDao)) ;int result=dao.add(1,2);System.out.println("result:"+result);}
}
class UserDaoProxy implements InvocationHandler{//创建的是谁的代理对象,把谁传递过来//有参构造传递private Object obj;public UserDaoProxy (Object obj){this.obj=obj;}//参数含义:代理对象、方法、参数@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("方法之前执行...."+ method.getName()+":传递参数...."+ Arrays.toString(args));Object res=method.invoke(obj,args);System.out.println("方法之后执行...."+obj);return res;}
}

在这里插入图片描述
其实JDK动态代理本质就是在原来要增强的方法前面或后面增加一些逻辑处理等,而不修改源代码。从上面运行结果看以看出,add方法执行结果是3,但是在执行add方法执行多一些语句输出,这些就是我们增加的逻辑处理部分。其中method.invoke()就是模拟的原add方法执行,而前后的输出语句是模拟的增强的代码

七、基于AspectJ实现的AOP操作

1.什么是AspectJ

AspectJ不是Spring组成部分,独立AOP框架,一般把AspectJ和Spring框架一起使用进行AOP操作。

2.AOP相关术语

  • 连接点:类中可以被增强的方法,称为连接点。
  • 切入点:实际被增强的方法,称为切入点。
  • 通知:增强的那一部分逻辑代码。通知有多种类型:
    (1)前置通知:增强部分代码在原代码前面。
    (2)后置通知:增强部分代码在原代码后面。
    (3)环绕通知:增强部分代码既有在原代码前面,也有在原代码后面。
    (4)异常通知:原代码发生异常后才会执行。
    (5)最终通知:类似与finally那一部分
  • 切面:指把通知应用到切入点这一个动作。

3.切点表达式

  • 语法:execution([权限修饰符] [返回类型] [类全路径] [方法名称] [参数列表])
  • 例1:对 com.atguigu.dao.BookDao 类里面的 add 进行增强
execution(* com.auguigu.dao.BookDao.add(..))
  • 例2:对 com.atguigu.dao.BookDao 类里面的所有的方法进行增强
execution(* com.atguigu.dao.BookDao.*(..))
  • 例3:对 com.atguigu.dao 包里面所有类,类里面所有方法进行增强
execution(* com.atguigu.dao.*.* (..))

3.基于注解方式实现

(1)实例:

User:
注解方式创建User对象user

package com.dragon.springaop.anno;import org.springframework.stereotype.Component;@Component
public class User {public void add(){System.out.println("add....");}
}

UserProxy类(先忽略@Order注解):
注解方式创建UserProxy对象userProxy
@Aspect定义UserProxy为切面类(即指把通知应用到切入点的类)

package com.dragon.springaop.anno;import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.junit.jupiter.api.Order;
import org.springframework.stereotype.Component;@Component
@Aspect//定义切面类
@Order(3)
public class UserProxy {@Before(value = "execution(* com.dragon.springaop.anno.User.add(..))")public void before(){System.out.println("before.....");}@AfterReturning(value = "execution(* com.dragon.springaop.anno.User.add(..))")public void afterReturning(){System.out.println("afterReturning....");}@After(value = "execution(* com.dragon.springaop.anno.User.add(..))")public void after(){System.out.println("after....");}@AfterThrowing(value = "execution(* com.dragon.springaop.anno.User.add(..))")public void afterThrowing(){System.out.println("afterThrowing....");}@Around(value = "execution(* com.dragon.springaop.anno.User.add(..))")public void around(ProceedingJoinPoint proceedingJoinPoint)throws Throwable{System.out.println("环绕之前....");proceedingJoinPoint.proceed();System.out.println("环绕之后....");}
}

spring配置文件:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context  http://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/aop  http://www.springframework.org/schema/aop/spring-aop.xsd"><!--开启组件扫描--><context:component-scan base-package="com.dragon.springaop.anno"/><!--开启AspectJ生成代理对象--><aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>

测试:

 	ApplicationContext context=new ClassPathXmlApplicationContext("beanaop1.xml");User user=context.getBean("user", User.class);user.add();

在这里插入图片描述
可以看出Befoe(前置通知,在add前运行)、AfterRetruning(后置通知或返回通知,在add返回值后运行)、AfterThrowing(异常通知,在add出现异常后,这个没有运行,因为没异常,大家在add内添加 int i=1/0 测试一下,不在演示)、After(最终通知,在add执行完后)、Around(环绕通知,在add前和后)的运行时期。

(2)切入点提取

上面的UserProxy 类中有很多重复的切入点表达式,可以进行公共提取

@Pointcut(value = "execution(* com.dragon.springaop.anno.User.add(..))")
public void pointDemo(){    
}//前置通知
@Before(value="pointDemo()")
public void before(){System.out.println("before....");
}

(3)设置增强类优先级

上面的实例只有UserProxy一个增强类,当有多个增强类时,可以使用@Order(数值)设置优先级执行。(数字越小优先级越高)
在上诉例子中多创建一个PeopleProxy类,设置@Order:

package com.dragon.springaop.anno;import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.junit.jupiter.api.Order;
import org.springframework.stereotype.Component;@Component
@Aspect
@Order(1)
public class PersionProxy {@Before(value = "execution(* com.dragon.springaop.anno.User.add(..))")public void persionBefore(){System.out.println("persionBefore.....");}
}

上面的UserProxy类中我设置的是Order(3),所以PeopleProxylei类先运行。
在这里插入图片描述

(4)完全注解开发

AOPConfig类:

package com.dragon.springaop.config;import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;@Configuration
@ComponentScan(basePackages = {"com.dragon.springaop"})
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class AopConfig {
}

Book、BookProxy:

package com.dragon.springaop.aopxml;import org.springframework.stereotype.Component;@Component
public class Book {public void buy(){System.out.println("buy......");}
}========================================
package com.dragon.springaop.aopxml;public class BookProxy {public void before(){System.out.println("before....");}
}

测试:

		ApplicationContext context=new AnnotationConfigApplicationContext(AopConfig.class);Book book=context.getBean("book", Book.class);book.buy();

4.基于xml配置文件实现(了解)

Book、BookProxy:

package com.dragon.springaop.aopxml;import org.springframework.stereotype.Component;public class Book {public void buy(){System.out.println("buy......");}
}========================================
package com.dragon.springaop.aopxml;public class BookProxy {public void before(){System.out.println("before....");}
}

spring配置文件:

 <bean id="book" class="com.dragon.springaop.aopxml.Book"></bean><bean id="bookProxy" class="com.dragon.springaop.aopxml.BookProxy"></bean><!--    配置aop增强--><aop:config>
<!--        切入点--><aop:pointcut id="p" expression="execution(* com.dragon.springaop.aopxml.Book.buy(..))"/>
<!--        配置切面--><aop:aspect ref="bookProxy">
<!--            增强作用在具体的方法上--><aop:before method="before" pointcut-ref="p"></aop:before></aop:aspect></aop:config>

测试:

		ApplicationContext context=new ClassPathXmlApplicationContext("beanaop2.xml");Book book=context.getBean("book", Book.class);book.buy();

八、JdbcTemplate

1.相关依赖(AOP、IOC、JdbcTemplate都有)

        <?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</artifactId><version>1.0-SNAPSHOT</version><properties><maven.compiler.source>19</maven.compiler.source><maven.compiler.target>19</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><dependencies><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.13.2</version><scope>compile</scope></dependency><dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter</artifactId><version>5.9.2</version><scope>compile</scope></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.13.2</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>6.0.9</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-beans</artifactId><version>6.0.9</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-core</artifactId><version>6.0.9</version></dependency><dependency><groupId>commons-logging</groupId><artifactId>commons-logging</artifactId><version>1.2</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.2.16</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-aop</artifactId><version>6.0.9</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-aspects</artifactId><version>6.0.9</version></dependency><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.9.19</version><scope>runtime</scope></dependency><dependency><groupId>aopalliance</groupId><artifactId>aopalliance</artifactId><version>1.0</version></dependency><dependency><groupId>net.sourceforge.cglib</groupId><artifactId>com.springsource.net.sf.cglib</artifactId><version>2.1.3</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.33</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>6.0.9</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-tx</artifactId><version>6.0.9</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-orm</artifactId><version>6.0.9</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.13.2</version><scope>compile</scope></dependency><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.9.19</version></dependency></dependencies>
</project>

2.代码实战

(1)方法讲解

  • 增删改:
int update(String sql, Object... args);
  • 查询(返回某个值):
T queryForObject(String sql,Class<T> requiredType);
  • 查询(返回某个对象):
T queryForObject(String sql,Class<T> requiredType);
  • 查询(返回集合):
List<T> query(String sql,RowMapper<T> rowMapper,Object... args);
  • 批量增删改:
int[] batchUpdate(String sql,List<Object[]> batchArgs);

(2)代码实例

实体层——Book实体类:

package com.dragon.jdbc.entity;public class Book {private String bookId;private String bookname;private String bstatus;public String getBookId() {return bookId;}public String getBookname() {return bookname;}public String getBstatus() {return bstatus;}public void setBookId(String bookId) {this.bookId = bookId;}public void setBookname(String bookname) {this.bookname = bookname;}public void setBstatus(String bstatus) {this.bstatus = bstatus;}@Overridepublic String toString() {return "Book{" +"bookId='" + bookId + '\'' +", bookname='" + bookname + '\'' +", bstatus='" + bstatus + '\'' +'}';}
}

Dao层——BookDao类:

package com.dragon.jdbc.dao;import com.dragon.jdbc.entity.Book;import java.util.List;public interface BookDao {public void add(Book book);//添加public void update(Book book);//修改更新public void delete(String id);//删除public int selectCount();//查找数量,返回int类型public Book findBookInfo(String id);//根据id查找某本书,返回对象public List<Book> findAllBook();//查找数据库内所有对象,返回集合public void bathAddBook(List<Object[]> bathArgs);//批量添加public void bathUpdateBook(List<Object[]> bathArgs);//批量修改public void bathDeleteBook(List<Object[]> bathArgs);//批量删除
}

BookDao实现类BookDaoImpl:

package com.dragon.jdbc.dao;import com.dragon.jdbc.entity.Book;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;import java.util.Arrays;
import java.util.List;@Repository
public class BookDaoImpl implements BookDao{@Autowiredprivate JdbcTemplate jdbcTemplate;@Overridepublic void add(Book book) {String sql="insert into t_book values(?,?,?)";Object[] args={book.getBookId(),book.getBookname(),book.getBstatus()};int update=jdbcTemplate.update(sql,args);System.out.println(update);}@Overridepublic void update(Book book) {String sql="update t_book set bookname=?,bstatus=? where book_id=?";Object[] args={book.getBookname(),book.getBstatus(),book.getBookId()};int update=jdbcTemplate.update(sql,args);System.out.println(update);}@Overridepublic void delete(String id) {String sql="delete from t_book where book_id=?";int update=jdbcTemplate.update(sql,id);System.out.println(update);}@Overridepublic int selectCount() {String sql="select count(*) from t_book";Integer count=jdbcTemplate.queryForObject(sql,Integer.class);return count;}@Overridepublic Book findBookInfo(String id) {String sql="select * from t_book where book_id=?";Book book= jdbcTemplate.queryForObject(sql,new BeanPropertyRowMapper<Book>(Book.class),id);return book;}@Overridepublic List<Book> findAllBook() {String sql="select * from t_book";List<Book> bookList=jdbcTemplate.query(sql,new BeanPropertyRowMapper<Book>(Book.class));return bookList;}@Overridepublic void bathAddBook(List<Object[]> bathArgs) {String sql="insert into t_book values(?,?,?)";int[] ints=jdbcTemplate.batchUpdate(sql,bathArgs);System.out.println(Arrays.toString(ints));}@Overridepublic void bathUpdateBook(List<Object[]> bathArgs) {String sql="update t_book set bookname=?,bstatus=? where book_id=?";int[] ints=jdbcTemplate.batchUpdate(sql,bathArgs);System.out.println(Arrays.toString(ints));}@Overridepublic void bathDeleteBook(List<Object[]> bathArgs) {String sql="delete from t_book where book_id=?";int[] ints=jdbcTemplate.batchUpdate(sql,bathArgs);System.out.println(Arrays.toString(ints));}}

service层——BookService:

package com.dragon.jdbc.service;import com.dragon.jdbc.dao.BookDao;
import com.dragon.jdbc.entity.Book;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.util.List;@Service
public class BookService {@Autowiredprivate BookDao bookDao;public void addBook(Book book){bookDao.add(book);}public void updateBook(Book book){bookDao.update(book);}public void deleteBook(String id){bookDao.delete(id);}public int findCount(){return bookDao.selectCount();}public Book finOne(String id){return bookDao.findBookInfo(id);}public List<Book> findAll(){return bookDao.findAllBook();}public void bathAdd(List<Object[]> bathArgs){bookDao.bathAddBook(bathArgs);}public void bathUpdate(List<Object[]> bathArgs){bookDao.bathUpdateBook(bathArgs);}public void bathDelete(List<Object[]> bathArgs){bookDao.bathDeleteBook(bathArgs);}
}

数据库连接配置——Spring配置文件:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"><context:property-placeholder location="classpath:jdbc.properties"/><bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"><property name="driverClassName" value="${pro.driverClass}"></property><property name="url" value="${pro.url}"></property><property name="username" value="${pro.username}"></property><property name="password" value="${pro.password}"></property></bean><bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"><property name="dataSource" ref="dataSource"></property></bean><context:component-scan base-package="com.dragon.jdbc"></context:component-scan>
</beans>

properties配置文件——jdbc.properties:
需要自行修改数据库名称(我的是user_db)

pro.driverClass=com.mysql.cj.jdbc.Driver
pro.url=jdbc:mysql://localhost:3306/user_db?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8&autoReconnect=true&useSSL=false
pro.username=root
pro.password=root

测试类:

package com.dragon.jdbc.test;import com.dragon.jdbc.entity.Book;
import com.dragon.jdbc.service.BookService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;import java.util.ArrayList;
import java.util.List;public class test1 {public static void main(String[] args) {ApplicationContext context=new ClassPathXmlApplicationContext("bean8.xml");BookService bookService=context.getBean("bookService",BookService.class);
//        Book book=new Book();
//        book.setBookId("1");
//        book.setBookname("java");
//        book.setBstatus("a");
//        bookService.addBook(book);//        Book book=new Book();
//        book.setBookId("1");
//        book.setBookname("javaup");
//        book.setBstatus("a");
//        bookService.updateBook(book);//        bookService.deleteBook("1");//        System.out.println( bookService.findCount());//        Book book=bookService.finOne("1");
//        System.out.println(book);//        System.out.println(bookService.findAll());//        List<Object[]> bathArgs=new ArrayList<>();
//        Object[] o1={"3","java","j"};
//        Object[] o2={"4","c++","c"};
//        Object[] o3={"5","MySql","m"};
//        bathArgs.add(o1);
//        bathArgs.add(o2);
//        bathArgs.add(o3);
//        bookService.bathAdd(bathArgs);//        List<Object[]> bathArgs=new ArrayList<>();
//        Object[] o1={"java001","j","3"};
//        Object[] o2={"c++002","c","4"};
//        Object[] o3={"MySql003","m","5"};
//        bathArgs.add(o1);
//        bathArgs.add(o2);
//        bathArgs.add(o3);
//        bookService.bathUpdate(bathArgs);List<Object[]> bathArgs=new ArrayList<>();Object[] o1={"3"};Object[] o2={"4"};bathArgs.add(o1);bathArgs.add(o2);bookService.bathDelete(bathArgs);}}

九、事务及其参数含义

1.事务的四个特性

  • 原子性
  • 一致性
  • 隔离性
  • 持久性。

2.事务的传播行为(propagation)

Spring定义了7种传播行为:

传播属性描述
REQUIRED如果有事务在运行,当前的方法就在这个事务内运行,否则,就启动一个新的事务,并在自己的事务内运行
REQUIRED_NEW当前的方法必须启动新事务,并在它自己的事务内运行,如果有事务正在运行,应该将它挂起
SUPPORTS如果有事务在运行,当前的方法就在这个事务内运行,否则它可以不运行在事务中
NOT_SUPPORTED当前方法不应该运行在事务中,如果有运行的事务,将它挂起
MANDATORY当前的方法不应该运行在事务中,如果有运行的事务,就抛出异常
NESTED如果有事务在运行,当前的方法就应该在这个事务的嵌套事务内运行,否则,就启动一个新的事务,并在它自己的事务内运行

在这里插入图片描述
这里只图解介绍一个,其他类推

3.事务隔离性

  • 脏读:一个未提交事务读取到另一个未提交事务的数据
    例:事务A读取到事务B修改后的数据,但是读取后事务B回滚了,此时A读取的是修改后的数据,但是修改撤销了。
  • 不可重复读:一个未提交的事务读取到另一个提交事务修改数据
    例:事务A和事务B读取同一个数据,但是事务B在读取后进行修改,然后提交,提交后事务A又读取这个数据,此时读取的是修改后的,跟上次读取的不一样。
  • 幻读(虚读):一个未提交的事务读取到另一个提交事务添加数据

4.事务的隔离级别(ioslation)

在这里插入图片描述

5.timeout(超时)

事务在一定时间内进行提交,如果不提交会进行回滚,默认值是-1,设置时间以秒为单位进行计算。

6.readOnly(是否只读)

读:查询,写:增删改
默认值是false,表示可以增删改查,设置true后只能查询。

7.rollbackFor(回滚)

设置出现哪些异常进行事务回滚。

8.noRollbackFor(不回滚)

设置出现哪些异常不进行事务回滚。

十、事务管理

Spring事务管理提供了一个接口,叫做事务管理器,这个接口针对不同的框架提供不同的实现类。
在这里插入图片描述

1.事务管理的两种形式

  • 编程式事务管理
    例:
        try{//开启事务//进行业务操作userDao.reduceMoney();//模拟异常int i=10/0;userDao.addMoney();//没出现异常,事务提交}catch (Exception e){//异常,事务回滚}
  • 声明式事务管理(AOP原理)
    例:
@Service
@Transactional(timeout = -1,propagation = Propagation.REQUIRED,isolation = Isolation.READ_COMMITTED)
public class UserService{@Autowiredprivate UserDao userDao;public void accountMoney(){userDao.reduceMoney();int i= 1 / 0;userDao.addMoney();}
}

2.注解实现声明式事务管理

就是上述声明式管理的例子,这里补充一下全部代码:

================userDao====================
package com.dragon.shiwu.dao;public interface UserDao {public void addMoney();public void reduceMoney();
}
==============userDaoImpl===================
package com.dragon.shiwu.dao;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;@Repository
public class UserDaoImpl implements UserDao{@Autowiredprivate JdbcTemplate jdbcTemplate;@Overridepublic void addMoney() {String sql="update t_account set money=money + ? where username = ?";jdbcTemplate.update(sql,100,"mary");}@Overridepublic void reduceMoney() {String sql="update t_account set money=money-? where username=?";jdbcTemplate.update(sql,100,"lucy");}
}
==============userService============================
package com.dragon.shiwu.service;import com.dragon.shiwu.dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;@Service
@Transactional(timeout = -1,propagation = Propagation.REQUIRED,isolation = Isolation.READ_COMMITTED)
public class UserService{@Autowiredprivate UserDao userDao;public void accountMoney(){userDao.reduceMoney();int i= 1 / 0;userDao.addMoney();}
}
============Spring配置文件===========================(注意这里引入了tx命名空间和)
<?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"xmlns:tx="http://www.springframework.org/schema/tx"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"><context:property-placeholder location="classpath:jdbc.properties"/><bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"><property name="driverClassName" value="${pro.driverClass}"></property><property name="url" value="${pro.url}"></property><property name="username" value="${pro.username}"></property><property name="password" value="${pro.password}"></property></bean>
<!--创建JdbcTemplate对象--><bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"><!--注入数据库连接池--><property name="dataSource" ref="dataSource"></property></bean><context:component-scan base-package="com.dragon.shiwu"></context:component-scan>
<!--创建事务管理器--><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>
</beans>

运行前:
在这里插入图片描述
运行后:
在这里插入图片描述
在这里插入图片描述

3.xml实现声明式事务管理

Spring配置文件:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xmlns:tx="http://www.springframework.org/schema/tx"xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsdhttp://www.springframework.org/schema/aop  http://www.springframework.org/schema/aop/spring-aop.xsd"><context:property-placeholder location="classpath:jdbc.properties"/><bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"><property name="driverClassName" value="${pro.driverClass}"></property><property name="url" value="${pro.url}"></property><property name="username" value="${pro.username}"></property><property name="password" value="${pro.password}"></property></bean><bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"><property name="dataSource" ref="dataSource"></property></bean>
<!--    开启组件扫描--><context:component-scan base-package="com.dragon.shiwu"></context:component-scan><!--配置事务通知--><tx:advice id="txadvice"><tx:attributes><!--配置事务参数--><tx:method name="accountMoney" propagation="REQUIRED"/></tx:attributes></tx:advice><!--    配置切入点和切面--><aop:config>
<!--        配置切入点--><aop:pointcut id="pt" expression="execution(* com.dragon.shiwu.service.UserService.*(..))"/>
<!--        配置切面--><aop:advisor advice-ref="txadvice" pointcut-ref="pt"></aop:advisor></aop:config>
</beans>

4.完全注解开发

TxConfig类:

package com.dragon.shiwu.config;import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;import javax.sql.DataSource;@Configuration//配置类
@ComponentScan(basePackages = "com.dragon.shiwu")//组件扫描
@EnableTransactionManagement//开启事务
public class TxConfig {//创建数据库连接池@Beanpublic DruidDataSource getDruidDataSource(){DruidDataSource druidDataSource = new DruidDataSource();druidDataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");druidDataSource.setUrl("jdbc:mysql://localhost:3306/user_db");druidDataSource.setUsername("root");druidDataSource.setPassword("root");return druidDataSource;}//创建JdbcTemplate对象@Beanpublic JdbcTemplate getJdbcTemplate(DataSource dataSource){JdbcTemplate jdbcTemplate = new JdbcTemplate();jdbcTemplate.setDataSource(dataSource);return jdbcTemplate;}//创建事务管理器@Beanpublic DataSourceTransactionManager getDataSourceTransactionManager(DataSource dataSource){DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();transactionManager.setDataSource(dataSource);return transactionManager;}}

测试类:

package com.dragon.shiwu.test;import com.dragon.shiwu.config.TxConfig;
import com.dragon.shiwu.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;public class test2 {public static void main(String[] args) {ApplicationContext context=new AnnotationConfigApplicationContext(TxConfig.class);UserService userService = context.getBean("userService",UserService.class);userService.accountMoney();}
}

总结

以上就是Spring的全部详细讲解。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/286399.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何在公网环境使用固定域名远程访问内网BUG管理系统协同办公

文章目录 前言1. 本地安装配置BUG管理系统2. 内网穿透2.1 安装cpolar内网穿透2.2 创建隧道映射本地服务3. 测试公网远程访问4. 配置固定二级子域名4.1 保留一个二级子域名5.1 配置二级子域名6. 使用固定二级子域名远程 前言 BUG管理软件,作为软件测试工程师的必备工具之一。在…

沉浸式数字文旅黑科技!用AI数字人升级景区体验

这年头文旅界也太卷了&#xff01; 在国家文化数字化战略的深入实施下&#xff0c;各地方文旅纷纷打造新型消费场景&#xff0c;以数字文旅提升消费产品的互动性和社交性&#xff0c;增强用户沉浸式体验。 其中&#xff0c;数字人乘着AI大语言模型的东风&#xff0c;被文旅品牌…

数据可视化---离群值展示

内容导航 类别内容导航机器学习机器学习算法应用场景与评价指标机器学习算法—分类机器学习算法—回归机器学习算法—聚类机器学习算法—异常检测机器学习算法—时间序列数据可视化数据可视化—折线图数据可视化—箱线图数据可视化—柱状图数据可视化—饼图、环形图、雷达图统…

Flowable解读-序

提示&#xff1a;这个专栏是关于flowable的&#xff0c;但不是按照顺序来的&#xff08;不会是怎么运行、怎么引入依赖等等&#xff09;&#xff0c;因为我也在技术预研中&#xff0c;目前没有找到很完善的教程&#xff0c;只能按照自己的理解开始一点一点的接触。后续会整理成…

blender2.83物体对齐到地面怎么做?

在blender中打开一个模型场景&#xff0c;场景中的模型分散在场景中的不同高度位置&#xff0c;现在我们需要他们都对齐到地面上&#xff0c;这种情况我们通常都是直接使用对齐工具进行对齐的&#xff0c;西面我们一起看看应该怎么做。 首先我们打开blender在里面创建一个平面作…

成功在windows系统上安装OpenPCDet-踩坑无数版

先上图 在网上看了无数帖子,终于集百家之长后,安装成功了。事实证明是可以安装成功的,希望还在挣扎的兄弟们不要放弃。 关键配置(版本问题很致命) #有的差一个小版本号都会出问题 操作系统 : win10 cuda版本 : 11.7([cuda安装参考](https://blog.csdn.net/weixin_438…

图片速览 OOD用于零样本 OOD 检测的 CLIPN:教 CLIP 说不

PAPERCODEhttps://arxiv.org/pdf/2308.12213v2.pdfhttps://github.com/xmed-lab/clipn 文章创新 以往由CLIP驱动的零样本OOD检测方法&#xff0c;只需要ID的类名&#xff0c;受到的关注较少。 本文提出了一种新的方法&#xff0c;即CLIP说“不”&#xff08;CLIPN&#xff09;…

nacos使用注册中心—springcloud使用

nacos——springcloud使用 nacos注册中心 文章目录 nacos——springcloud使用nacos注册中心1.Windows安装1.1.下载安装包1.2.解压1.3.端口配置1.4.启动1.5.访问 服务注册到NacosNacos分级存储Nacos的负载均衡服务实例的权重配置环境隔离nacos和Eureka对比 1.Windows安装 开发…

【ros2 control 机器人驱动开发】简单双关节机器人学习-example 1

【ros2 control 机器人驱动开发】简单双关节机器人学习-example 1 文章目录 前言一、RR机器人创建description pkg创建demos pkg 二、创建controller相关创建example pkg 三、测试运行总结 前言 本系列文件主要有以下目标和内容&#xff1a; 为系统、传感器和执行器创建 Har…

【Java不看后悔系列】|面向对象编程|[继承、封装、多态全覆盖]

&#x1f308;个人主页: Aileen_0v0&#x1f525;系列专栏:Java学习系列专栏&#x1f4ab;个人格言:"没有罗马,那就自己创造罗马~" 1.Judging right from wrong (inheritance) 1.A child class inherits everything from its parent class. 2.A child class canno…

web之CSS悬停效果页面设计

参考小米商城的“手机”页面&#xff0c;做出一个“手机”的标签&#xff0c;实现当鼠标悬停在“手机”上时&#xff0c;出现手机系列菜单&#xff1b;当鼠标移走时&#xff0c;菜单页面消失的效果&#xff01; 参考图&#xff1a; 实现代码&#xff1a; <!DOCTYPE html&g…

失业无忧!掌握这四个网站,年收入10-20万!

大家好&#xff01;在职场中&#xff0c;失业可能是每个人都会面临的一种情况。当然&#xff0c;失业并不是终点&#xff0c;而是重新出发的起点。在这个充满机遇的数字时代&#xff0c;利用网络资源来提升自己是再合适不过了。今天&#xff0c;我将介绍四个非常有用的网站&…